/* Copyright (C) 1999-2006 Id Software, Inc. and contributors. For a list of contributors, see the accompanying CONTRIBUTORS file. This file is part of GtkRadiant. GtkRadiant is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. GtkRadiant is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GtkRadiant; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "qrad.h" vec3_t texture_reflectivity[MAX_MAP_TEXINFO]; /* =================================================================== TEXTURE LIGHT VALUES =================================================================== */ /* ====================== CalcTextureReflectivity_Quake2 ====================== */ void CalcTextureReflectivity_Quake2 (void) { int i; int j, k, texels; int color[3]; int texel; byte *palette; char path[1024]; float r, scale; miptex_t *mt; sprintf (path, "%spics/colormap.pcx", gamedir); // get the game palette Load256Image (path, NULL, &palette, NULL, NULL); // allways set index 0 even if no textures texture_reflectivity[0][0] = 0.5; texture_reflectivity[0][1] = 0.5; texture_reflectivity[0][2] = 0.5; for (i=0 ; iwidth)*LittleLong(mt->height); color[0] = color[1] = color[2] = 0; for (j=0 ; joffsets[0]) + j]; for (k=0 ; k<3 ; k++) color[k] += palette[texel*3+k]; } for (j=0 ; j<3 ; j++) { r = color[j]/texels/255.0; texture_reflectivity[i][j] = r; } // scale the reflectivity up, because the textures are // so dim scale = ColorNormalize (texture_reflectivity[i], texture_reflectivity[i]); if (scale < 0.5) { scale *= 2; VectorScale (texture_reflectivity[i], scale, texture_reflectivity[i]); } #if 0 texture_reflectivity[i][0] = 0.5; texture_reflectivity[i][1] = 0.5; texture_reflectivity[i][2] = 0.5; #endif } } /* ====================== CalcTextureReflectivity_Heretic2 ====================== */ void CalcTextureReflectivity_Heretic2 (void) { int i; int j, texels; int color[3]; int texel; char path[1024]; float r; miptex_m8_t *mt; miptex_m32_t *mt32; byte *pos; // allways set index 0 even if no textures texture_reflectivity[0][0] = 0.5; texture_reflectivity[0][1] = 0.5; texture_reflectivity[0][2] = 0.5; for (i=0 ; iwidth[0])*LittleLong(mt->height[0]); color[0] = color[1] = color[2] = 0; for (j=0 ; joffsets[0]) + j]; color[0] += mt->palette[texel].r; color[1] += mt->palette[texel].g; color[2] += mt->palette[texel].b; } free(mt); } else { texels = LittleLong(mt32->width[0])*LittleLong(mt32->height[0]); color[0] = color[1] = color[2] = 0; for (j=0 ; joffsets[0] + (j<<2); color[0] += *pos++; // r color[1] += *pos++; // g color[2] += *pos++; // b } free(mt32); } for (j=0 ; j<3 ; j++) { r = color[j]/((float) texels*255.0); texture_reflectivity[i][j] = r; } } } /* ======================================================================= MAKE FACES ======================================================================= */ /* ============= WindingFromFace ============= */ winding_t *WindingFromFace (dface_t *f) { int i; int se; dvertex_t *dv; int v; winding_t *w; w = AllocWinding (f->numedges); w->numpoints = f->numedges; for (i=0 ; inumedges ; i++) { se = dsurfedges[f->firstedge + i]; if (se < 0) v = dedges[-se].v[1]; else v = dedges[se].v[0]; dv = &dvertexes[v]; VectorCopy (dv->point, w->p[i]); } RemoveColinearPoints (w); return w; } /* ============= BaseLightForFace ============= */ void BaseLightForFace (dface_t *f, vec3_t color) { texinfo_t *tx; // // check for light emited by texture // tx = &texinfo[f->texinfo]; if (!(tx->flags & SURF_LIGHT) || tx->value == 0) { VectorClear (color); return; } VectorScale (texture_reflectivity[f->texinfo], tx->value, color); } qboolean IsSky (dface_t *f) { texinfo_t *tx; tx = &texinfo[f->texinfo]; if (tx->flags & SURF_SKY) return true; return false; } /* ============= MakePatchForFace ============= */ float totalarea; void MakePatchForFace (int fn, winding_t *w) { dface_t *f; float area; patch_t *patch; dplane_t *pl; int i; vec3_t color; dleaf_t *leaf; f = &dfaces[fn]; area = WindingArea (w); totalarea += area; patch = &patches[num_patches]; if (num_patches == MAX_PATCHES) Error ("num_patches == MAX_PATCHES"); patch->next = face_patches[fn]; face_patches[fn] = patch; patch->winding = w; if (f->side) patch->plane = &backplanes[f->planenum]; else patch->plane = &dplanes[f->planenum]; if (face_offset[fn][0] || face_offset[fn][1] || face_offset[fn][2] ) { // origin offset faces must create new planes if (numplanes + fakeplanes >= MAX_MAP_PLANES) Error ("numplanes + fakeplanes >= MAX_MAP_PLANES"); pl = &dplanes[numplanes + fakeplanes]; fakeplanes++; *pl = *(patch->plane); pl->dist += DotProduct (face_offset[fn], pl->normal); patch->plane = pl; } WindingCenter (w, patch->origin); VectorAdd (patch->origin, patch->plane->normal, patch->origin); leaf = Rad_PointInLeaf(patch->origin); patch->cluster = leaf->cluster; if (patch->cluster == -1) Sys_FPrintf( SYS_VRB, "patch->cluster == -1\n"); patch->area = area; if (patch->area <= 1) patch->area = 1; patch->sky = IsSky (f); VectorCopy (texture_reflectivity[f->texinfo], patch->reflectivity); // non-bmodel patches can emit light if (fn < dmodels[0].numfaces) { BaseLightForFace (f, patch->baselight); ColorNormalize (patch->reflectivity, color); for (i=0 ; i<3 ; i++) patch->baselight[i] *= color[i]; VectorCopy (patch->baselight, patch->totallight); } num_patches++; } entity_t *EntityForModel (int modnum) { int i; char *s; char name[16]; sprintf (name, "*%i", modnum); // search the entities for one using modnum for (i=0 ; inumfaces ; j++) { fn = mod->firstface + j; face_entity[fn] = ent; VectorCopy (origin, face_offset[fn]); f = &dfaces[fn]; w = WindingFromFace (f); for (k=0 ; knumpoints ; k++) { VectorAdd (w->p[k], origin, w->p[k]); } MakePatchForFace (fn, w); } } Sys_FPrintf( SYS_VRB, "%i sqaure feet\n", (int)(totalarea/64)); } /* ======================================================================= SUBDIVIDE ======================================================================= */ void FinishSplit (patch_t *patch, patch_t *newp) { dleaf_t *leaf; VectorCopy (patch->baselight, newp->baselight); VectorCopy (patch->totallight, newp->totallight); VectorCopy (patch->reflectivity, newp->reflectivity); newp->plane = patch->plane; newp->sky = patch->sky; patch->area = WindingArea (patch->winding); newp->area = WindingArea (newp->winding); if (patch->area <= 1) patch->area = 1; if (newp->area <= 1) newp->area = 1; WindingCenter (patch->winding, patch->origin); VectorAdd (patch->origin, patch->plane->normal, patch->origin); leaf = Rad_PointInLeaf(patch->origin); patch->cluster = leaf->cluster; if (patch->cluster == -1) Sys_FPrintf( SYS_VRB, "patch->cluster == -1\n"); WindingCenter (newp->winding, newp->origin); VectorAdd (newp->origin, newp->plane->normal, newp->origin); leaf = Rad_PointInLeaf(newp->origin); newp->cluster = leaf->cluster; if (newp->cluster == -1) Sys_FPrintf( SYS_VRB, "patch->cluster == -1\n"); } /* ============= SubdividePatch Chops the patch only if its local bounds exceed the max size ============= */ void SubdividePatch (patch_t *patch) { winding_t *w, *o1, *o2; vec3_t mins, maxs, total; vec3_t split; vec_t dist; int i, j; vec_t v; patch_t *newp; w = patch->winding; mins[0] = mins[1] = mins[2] = 99999; maxs[0] = maxs[1] = maxs[2] = -99999; for (i=0 ; inumpoints ; i++) { for (j=0 ; j<3 ; j++) { v = w->p[i][j]; if (v < mins[j]) mins[j] = v; if (v > maxs[j]) maxs[j] = v; } } VectorSubtract (maxs, mins, total); for (i=0 ; i<3 ; i++) if (total[i] > (subdiv+1) ) break; if (i == 3) { // no splitting needed return; } // // split the winding // VectorCopy (vec3_origin, split); split[i] = 1; dist = (mins[i] + maxs[i])*0.5; ClipWindingEpsilon (w, split, dist, ON_EPSILON, &o1, &o2); // // create a new patch // if (num_patches == MAX_PATCHES) Error ("MAX_PATCHES"); newp = &patches[num_patches]; num_patches++; newp->next = patch->next; patch->next = newp; patch->winding = o1; newp->winding = o2; FinishSplit (patch, newp); SubdividePatch (patch); SubdividePatch (newp); } /* ============= DicePatch Chops the patch by a global grid ============= */ void DicePatch (patch_t *patch) { winding_t *w, *o1, *o2; vec3_t mins, maxs; vec3_t split; vec_t dist; int i; patch_t *newp; w = patch->winding; WindingBounds (w, mins, maxs); for (i=0 ; i<3 ; i++) if (floor((mins[i]+1)/subdiv) < floor((maxs[i]-1)/subdiv)) break; if (i == 3) { // no splitting needed return; } // // split the winding // VectorCopy (vec3_origin, split); split[i] = 1; dist = subdiv*(1+floor((mins[i]+1)/subdiv)); ClipWindingEpsilon (w, split, dist, ON_EPSILON, &o1, &o2); // // create a new patch // if (num_patches == MAX_PATCHES) Error ("MAX_PATCHES"); newp = &patches[num_patches]; num_patches++; newp->next = patch->next; patch->next = newp; patch->winding = o1; newp->winding = o2; FinishSplit (patch, newp); DicePatch (patch); DicePatch (newp); } /* ============= SubdividePatches ============= */ void SubdividePatches (void) { int i, num; if (subdiv < 1) return; num = num_patches; // because the list will grow for (i=0 ; i