patches.c

Go to the documentation of this file.
00001 
00005 /*
00006 Copyright (C) 1997-2001 Id Software, Inc.
00007 
00008 This program is free software; you can redistribute it and/or
00009 modify it under the terms of the GNU General Public License
00010 as published by the Free Software Foundation; either version 2
00011 of the License, or (at your option) any later version.
00012 
00013 This program is distributed in the hope that it will be useful,
00014 but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00016 
00017 See the GNU General Public License for more details.
00018 
00019 You should have received a copy of the GNU General Public License
00020 along with this program; if not, write to the Free Software
00021 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00022 
00023 */
00024 
00025 #include "lighting.h"
00026 #include "bsp.h"
00027 #include "../../shared/images.h"
00028 
00029 static vec3_t texture_reflectivity[MAX_MAP_TEXINFO];
00030 patch_t *face_patches[MAX_MAP_FACES];
00031 
00032 /*
00033 ===================================================================
00034 TEXTURE LIGHT VALUES
00035 ===================================================================
00036 */
00037 
00038 void CalcTextureReflectivity (void)
00039 {
00040     int i, j, texels = 0;
00041     char path[MAX_QPATH];
00042     int color[3];
00043     SDL_Surface *surf;
00044 
00045     /* always set index 0 even if no textures */
00046     VectorSet(texture_reflectivity[0], 0.5, 0.5, 0.5);
00047 
00048     VectorSet(color, 0, 0, 0);
00049 
00050     for (i = 0; i < curTile->numtexinfo; i++) {
00051         /* see if an earlier texinfo already got the value */
00052         for (j = 0; j < i; j++) {
00053             if (!strcmp(curTile->texinfo[i].texture, curTile->texinfo[j].texture)) {
00054                 VectorCopy(texture_reflectivity[j], texture_reflectivity[i]);
00055                 break;
00056             }
00057         }
00058         if (j != i) /* earlier texinfo found, continue */
00059             continue;
00060 
00061         /* load the image file */
00062         Com_sprintf(path, sizeof(path), "textures/%s", curTile->texinfo[i].texture);
00063         if (!Img_LoadImage(path, &surf)) {
00064             Verb_Printf(VERB_NORMAL, "Couldn't load %s\n", path);
00065             VectorSet(texture_reflectivity[i], 0.5, 0.5, 0.5);
00066             continue;
00067         }
00068 
00069         /* calculate average color */
00070         texels = surf->w * surf->h;
00071         color[0] = color[1] = color[2] = 0;
00072 
00073         for(j = 0; j < texels; j++){
00074             const byte *pos = (byte *)surf->pixels + j * 4;
00075             color[0] += *pos++; /* r */
00076             color[1] += *pos++; /* g */
00077             color[2] += *pos++; /* b */
00078         }
00079 
00080         Verb_Printf(VERB_EXTRA, "Loaded %s (%dx%d)\n", curTile->texinfo[i].texture, surf->w, surf->h);
00081 
00082         SDL_FreeSurface(surf);
00083 
00084         for(j = 0; j < 3; j++){
00085             const float r = color[j] / texels / 255.0;
00086             texture_reflectivity[i][j] = r;
00087         }
00088     }
00089 }
00090 
00091 
00092 static winding_t *WindingFromFace (const dBspSurface_t *f)
00093 {
00094     int i, v;
00095     dBspVertex_t *dv;
00096     winding_t *w;
00097 
00098     w = AllocWinding(f->numedges);
00099     w->numpoints = f->numedges;
00100 
00101     for (i = 0; i < f->numedges; i++) {
00102         const int se = curTile->surfedges[f->firstedge + i];
00103         if (se < 0)
00104             v = curTile->edges[-se].v[1];
00105         else
00106             v = curTile->edges[se].v[0];
00107 
00108         dv = &curTile->vertexes[v];
00109         VectorCopy(dv->point, w->p[i]);
00110     }
00111 
00112     RemoveColinearPoints(w);
00113 
00114     return w;
00115 }
00116 
00117 static inline qboolean HasLight (const dBspSurface_t *f)
00118 {
00119     const dBspTexinfo_t *tex;
00120 
00121     tex = &curTile->texinfo[f->texinfo];
00122     return (tex->surfaceFlags & SURF_LIGHT) && tex->value;
00123 }
00124 
00130 static inline void EmissiveLight (patch_t *patch)
00131 {
00132     if (HasLight(patch->face)) {
00133         const dBspTexinfo_t *tex = &curTile->texinfo[patch->face->texinfo];
00134         const vec_t *ref = texture_reflectivity[patch->face->texinfo];
00135 
00136         VectorScale(ref, tex->value, patch->light);
00137     }
00138 }
00139 
00140 static void BuildPatch (int fn, winding_t *w)
00141 {
00142     patch_t *patch;
00143     dBspPlane_t *plane;
00144 
00145     patch = (patch_t *)Mem_Alloc(sizeof(*patch));
00146 
00147     face_patches[fn] = patch;
00148 
00149     patch->face = &curTile->faces[fn];
00150     patch->winding = w;
00151 
00152     /* resolve the normal */
00153     plane = &curTile->planes[patch->face->planenum];
00154 
00155     if (patch->face->side)
00156         VectorNegate(plane->normal, patch->normal);
00157     else
00158         VectorCopy(plane->normal, patch->normal);
00159 
00160     WindingCenter(w, patch->origin);
00161 
00162     /* nudge the origin out along the normal */
00163     VectorMA(patch->origin, 2.0, patch->normal, patch->origin);
00164 
00165     patch->area = WindingArea(w);
00166 
00167     if (patch->area < 1.0)  /* clamp area */
00168         patch->area = 1.0;
00169 
00170     EmissiveLight(patch);  /* surface light */
00171 }
00172 
00173 static entity_t *EntityForModel (int modnum)
00174 {
00175     int i;
00176     char name[16];
00177 
00178     Com_sprintf(name, sizeof(name), "*%i", modnum);
00179     /* search the entities for one using modnum */
00180     for (i = 0; i < num_entities; i++) {
00181         const char *s = ValueForKey(&entities[i], "model");
00182         if (!strcmp(s, name))
00183             return &entities[i];
00184     }
00185 
00186     /* return the world */
00187     return &entities[0];
00188 }
00189 
00194 void BuildPatches (void)
00195 {
00196     int i, j, k;
00197     winding_t *w;
00198     vec3_t origin;
00199 
00200     memset(face_patches, 0, sizeof(face_patches));
00201 
00202     for (i = 0; i < curTile->nummodels; i++) {
00203         const dBspModel_t *mod = &curTile->models[i];
00204         const entity_t *ent = EntityForModel(i);
00205         /* bmodels with origin brushes (like func_door) need to be offset into their
00206          * in-use position */
00207         GetVectorForKey(ent, "origin", origin);
00208 
00209         for (j = 0; j < mod->numfaces; j++) {
00210             const int facenum = mod->firstface + j;
00211             dBspSurface_t *f = &curTile->faces[facenum];
00212 
00213             /* store the origin in case of moving bmodels (e.g. func_door) */
00214             VectorCopy(origin, face_offset[facenum]);
00215 
00216             if (!HasLight(f))  /* no light */
00217                 continue;
00218 
00219             w = WindingFromFace(f);
00220 
00221             for (k = 0; k < w->numpoints; k++)
00222                 VectorAdd(w->p[k], origin, w->p[k]);
00223 
00224             BuildPatch(facenum, w);
00225         }
00226     }
00227 }
00228 
00229 /*
00230 =======================================================================
00231 SUBDIVIDE
00232 =======================================================================
00233 */
00234 
00235 #define PATCH_SUBDIVIDE 64
00236 
00237 static void FinishSubdividePatch (patch_t *patch, patch_t *newp)
00238 {
00239     VectorCopy(patch->normal, newp->normal);
00240 
00241     VectorCopy(patch->light, newp->light);
00242 
00243     patch->area = WindingArea(patch->winding);
00244 
00245     if (patch->area < 1.0)
00246         patch->area = 1.0;
00247 
00248     newp->area = WindingArea(newp->winding);
00249 
00250     if (newp->area < 1.0)
00251         newp->area = 1.0;
00252 
00253     WindingCenter(patch->winding, patch->origin);
00254     /* nudge the patch origin out along the normal */
00255     VectorMA(patch->origin, 2.0, patch->normal, patch->origin);
00256 
00257     WindingCenter(newp->winding, newp->origin);
00258     /* nudge the patch origin out along the normal */
00259     VectorMA(newp->origin, 2.0, newp->normal, newp->origin);
00260 }
00261 
00265 static void SubdividePatch(patch_t *patch)
00266 {
00267     winding_t *w, *o1, *o2;
00268     vec3_t mins, maxs;
00269     vec3_t split;
00270     vec_t dist;
00271     int i;
00272     patch_t *newp;
00273 
00274     w = patch->winding;
00275     WindingBounds(w, mins, maxs);
00276 
00277     VectorClear(split);
00278 
00279     for (i = 0; i < 3; i++) {
00280         if (floor((mins[i] + 1) / PATCH_SUBDIVIDE) < floor((maxs[i] - 1) / PATCH_SUBDIVIDE)) {
00281             split[i] = 1.0;
00282             break;
00283         }
00284     }
00285     /* no splitting needed */
00286     if (i == 3)
00287         return;
00288 
00289     /* split the winding */
00290     dist = PATCH_SUBDIVIDE * (1 + floor((mins[i] + 1) / PATCH_SUBDIVIDE));
00291     ClipWindingEpsilon(w, split, dist, ON_EPSILON, &o1, &o2);
00292 
00293     /* create a new patch */
00294     newp = (patch_t *)Mem_Alloc(sizeof(*newp));
00295 
00296     newp->next = patch->next;
00297     patch->next = newp;
00298 
00299     patch->winding = o1;
00300     newp->winding = o2;
00301 
00302     FinishSubdividePatch(patch, newp);
00303 
00304     SubdividePatch(patch);
00305     SubdividePatch(newp);
00306 }
00307 
00311 void SubdividePatches (void)
00312 {
00313     int i;
00314 
00315     for (i = 0; i < MAX_MAP_FACES; i++) {
00316         patch_t *p = face_patches[i];
00317 
00318         if (p)  /* break it up */
00319             SubdividePatch(p);
00320     }
00321 }
00322 
00326 void FreePatches (void)
00327 {
00328     int i;
00329 
00330     for (i = 0; i < MAX_MAP_FACES; i++) {
00331         patch_t *p = face_patches[i];
00332         while (p) {
00333             patch_t *pnext = p->next;
00334             Mem_Free(p);
00335             p = pnext;
00336         }
00337     }
00338 }

Generated by  doxygen 1.6.2