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