r_lightmap.c

Go to the documentation of this file.
00001 
00007 /*
00008 Copyright (C) 1997-2001 Id Software, Inc.
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00018 
00019 See the GNU General Public License for more details.
00020 
00021 You should have received a copy of the GNU General Public License
00022 along with this program; if not, write to the Free Software
00023 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00024 
00025 */
00026 
00027 #include "r_local.h"
00028 #include "r_error.h"
00029 #include "r_entity.h"
00030 #include "r_lightmap.h"
00031 
00032 lightmaps_t r_lightmaps;
00033 
00034 static void R_UploadLightmapBlock (void)
00035 {
00036     const int samples = r_config.gl_compressed_solid_format ? r_config.gl_compressed_solid_format : r_config.gl_solid_format;
00037     if (r_lightmaps.lightmap_texnum == MAX_GL_LIGHTMAPS) {
00038         Com_Printf("R_UploadLightmapBlock: MAX_GL_LIGHTMAPS reached.\n");
00039         return;
00040     }
00041 
00042     R_BindTexture(r_lightmaps.lightmap_texnum);
00043 
00044     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00045     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00046 
00047     glTexImage2D(GL_TEXTURE_2D, 0, samples, r_lightmaps.size, r_lightmaps.size,
00048         0, GL_RGB, GL_UNSIGNED_BYTE, r_lightmaps.sample_buffer);
00049 
00050     R_CheckError();
00051 
00052     r_lightmaps.lightmap_texnum++;
00053 
00054     if (r_lightmaps.deluxemap_texnum == MAX_GL_DELUXEMAPS) {
00055         Com_Printf("R_UploadLightmapBlock: MAX_GL_DELUXEMAPS reached.\n");
00056         return;
00057     }
00058 
00059     R_BindTexture(r_lightmaps.deluxemap_texnum);
00060 
00061     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00062     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00063 
00064     glTexImage2D(GL_TEXTURE_2D, 0, samples, r_lightmaps.size, r_lightmaps.size,
00065         0, GL_RGB, GL_UNSIGNED_BYTE, r_lightmaps.direction_buffer);
00066 
00067     r_lightmaps.deluxemap_texnum++;
00068 
00069     /* clear the allocation block and buffers */
00070     memset(r_lightmaps.allocated, 0, r_lightmaps.size * sizeof(unsigned));
00071     memset(r_lightmaps.sample_buffer, 0, r_lightmaps.size * r_lightmaps.size * sizeof(unsigned));
00072     memset(r_lightmaps.direction_buffer, 0, r_lightmaps.size * r_lightmaps.size * sizeof(unsigned));
00073 }
00074 
00078 static qboolean R_AllocLightmapBlock (int w, int h, int *x, int *y)
00079 {
00080     int i, j;
00081     int best;
00082 
00083     best = r_lightmaps.size;
00084 
00085     for (i = 0; i < r_lightmaps.size - w; i++) {
00086         int best2 = 0;
00087 
00088         for (j = 0; j < w; j++) {
00089             if (r_lightmaps.allocated[i + j] >= best)
00090                 break;
00091             if (r_lightmaps.allocated[i + j] > best2)
00092                 best2 = r_lightmaps.allocated[i + j];
00093         }
00094         /* this is a valid spot */
00095         if (j == w) {
00096             *x = i;
00097             *y = best = best2;
00098         }
00099     }
00100 
00101     if (best + h > r_lightmaps.size)
00102         return qfalse;
00103 
00104     for (i = 0; i < w; i++)
00105         r_lightmaps.allocated[*x + i] = best + h;
00106 
00107     return qtrue;
00108 }
00109 
00114 static void R_BuildDefaultLightmap (mBspSurface_t *surf, byte *sout, byte *dout, int stride)
00115 {
00116     int i, j;
00117 
00118     const int smax = (surf->stextents[0] / surf->lightmap_scale) + 1;
00119     const int tmax = (surf->stextents[1] / surf->lightmap_scale) + 1;
00120 
00121     /* this works because the block bytes for the deluxemap are the same as for the lightmap */
00122     stride -= (smax * LIGHTMAP_BLOCK_BYTES);
00123 
00124     for (i = 0; i < tmax; i++, sout += stride, dout += stride) {
00125         for (j = 0; j < smax; j++) {
00126             sout[0] = 255;
00127             sout[1] = 255;
00128             sout[2] = 255;
00129 
00130             sout += LIGHTMAP_BLOCK_BYTES;
00131 
00132             dout[0] = 127;
00133             dout[1] = 127;
00134             dout[2] = 255;
00135 
00136             dout += DELUXEMAP_BLOCK_BYTES;
00137         }
00138     }
00139 
00140     Vector4Set(surf->color, 1.0, 1.0, 1.0, 1.0);
00141 }
00142 
00148 static void R_BuildLightmap (mBspSurface_t *surf, byte *sout, byte *dout, int stride)
00149 {
00150     unsigned int i, j;
00151     byte *lightmap, *lm, *l, *deluxemap, *dm;
00152 
00153     const int smax = (surf->stextents[0] / surf->lightmap_scale) + 1;
00154     const int tmax = (surf->stextents[1] / surf->lightmap_scale) + 1;
00155     const int size = smax * tmax;
00156     stride -= (smax * LIGHTMAP_BLOCK_BYTES);
00157 
00158     lightmap = (byte *)Mem_PoolAlloc(size * LIGHTMAP_BLOCK_BYTES, vid_lightPool, 0);
00159     lm = lightmap;
00160 
00161     deluxemap = (byte *)Mem_PoolAlloc(size * DELUXEMAP_BLOCK_BYTES, vid_lightPool, 0);
00162     dm = deluxemap;
00163 
00164     /* convert the raw lightmap samples to floating point and scale them */
00165     for (i = j = 0; i < size; i++, lm += LIGHTMAP_BLOCK_BYTES, dm += DELUXEMAP_BLOCK_BYTES) {
00166         lm[0] = surf->samples[j++];
00167         lm[1] = surf->samples[j++];
00168         lm[2] = surf->samples[j++];
00169 
00170         /* read in directional samples for deluxe mapping as well */
00171         dm[0] = surf->samples[j++];
00172         dm[1] = surf->samples[j++];
00173         dm[2] = surf->samples[j++];
00174     }
00175 
00176     /* apply modulate, contrast, resolve average surface color, etc.. */
00177     R_FilterTexture(lightmap, smax, tmax, it_lightmap, LIGHTMAP_BLOCK_BYTES);
00178 
00179     if (surf->texinfo->flags & (SURF_BLEND33 | SURF_ALPHATEST))
00180         surf->color[3] = 0.25;
00181     else if (surf->texinfo->flags & SURF_BLEND66)
00182         surf->color[3] = 0.50;
00183     else
00184         surf->color[3] = 1.0;
00185 
00186     /* soften it if it's sufficiently large */
00187     if (r_soften->integer && size > 128)
00188         for (i = 0; i < 4; i++) {
00189             R_SoftenTexture(lightmap, smax, tmax, LIGHTMAP_BLOCK_BYTES);
00190             R_SoftenTexture(deluxemap, smax, tmax, DELUXEMAP_BLOCK_BYTES);
00191         }
00192 
00193     /* the final lightmap is uploaded to the card via the strided lightmap
00194      * block, and also cached on the surface for fast point lighting lookups */
00195 
00196     surf->lightmap = (byte *)Mem_PoolAlloc(size * LIGHTMAP_BYTES, vid_lightPool, 0);
00197     l = surf->lightmap;
00198     lm = lightmap;
00199     dm = deluxemap;
00200 
00201     for (i = 0; i < tmax; i++, sout += stride, dout += stride) {
00202         for (j = 0; j < smax; j++) {
00203             /* copy the lightmap to the strided block */
00204             sout[0] = lm[0];
00205             sout[1] = lm[1];
00206             sout[2] = lm[2];
00207             sout += LIGHTMAP_BLOCK_BYTES;
00208 
00209             /* and to the surface, discarding alpha */
00210             l[0] = lm[0];
00211             l[1] = lm[1];
00212             l[2] = lm[2];
00213             l += LIGHTMAP_BYTES;
00214 
00215             lm += LIGHTMAP_BLOCK_BYTES;
00216 
00217             /* lastly copy the deluxemap to the strided block */
00218             dout[0] = dm[0];
00219             dout[1] = dm[1];
00220             dout[2] = dm[2];
00221             dout += DELUXEMAP_BLOCK_BYTES;
00222 
00223             dm += DELUXEMAP_BLOCK_BYTES;
00224         }
00225     }
00226 
00227     Mem_Free(lightmap);
00228     Mem_Free(deluxemap);
00229 }
00230 
00234 void R_CreateSurfaceLightmap (mBspSurface_t * surf)
00235 {
00236     int smax, tmax;
00237     byte *samples, *directions;
00238 
00239     if (!(surf->flags & MSURF_LIGHTMAP))
00240         return;
00241 
00242     smax = (surf->stextents[0] / surf->lightmap_scale) + 1;
00243     tmax = (surf->stextents[1] / surf->lightmap_scale) + 1;
00244 
00245     if (!R_AllocLightmapBlock(smax, tmax, &surf->light_s, &surf->light_t)) {
00246         /* upload the last block */
00247         R_UploadLightmapBlock();
00248         if (!R_AllocLightmapBlock(smax, tmax, &surf->light_s, &surf->light_t))
00249             Com_Error(ERR_DROP, "R_CreateSurfaceLightmap: Consecutive calls to R_AllocLightmapBlock(%d,%d) failed (lightmap_scale: %i, stextends: %f %f)\n",
00250                     smax, tmax, surf->lightmap_scale, surf->stextents[0], surf->stextents[1]);
00251     }
00252 
00253     surf->lightmap_texnum = r_lightmaps.lightmap_texnum;
00254     surf->deluxemap_texnum = r_lightmaps.deluxemap_texnum;
00255 
00256     samples = r_lightmaps.sample_buffer;
00257     samples += (surf->light_t * r_lightmaps.size + surf->light_s) * LIGHTMAP_BLOCK_BYTES;
00258 
00259     directions = r_lightmaps.direction_buffer;
00260     directions += (surf->light_t * r_lightmaps.size + surf->light_s) * DELUXEMAP_BLOCK_BYTES;
00261 
00262     if (!surf->samples)  /* make it fullbright */
00263         R_BuildDefaultLightmap(surf, samples, directions, r_lightmaps.size * LIGHTMAP_BLOCK_BYTES);
00264     else  /* or light it properly */
00265         R_BuildLightmap(surf, samples, directions, r_lightmaps.size * LIGHTMAP_BLOCK_BYTES);
00266 }
00267 
00272 void R_BeginBuildingLightmaps (void)
00273 {
00274     /* users can tune lightmap size for their card */
00275     r_lightmaps.size = r_maxlightmap->integer;
00276 
00277     r_lightmaps.allocated = (unsigned *)Mem_PoolAlloc(r_lightmaps.size *
00278         sizeof(unsigned), vid_lightPool, 0);
00279 
00280     r_lightmaps.sample_buffer = (byte *)Mem_PoolAlloc(
00281         r_lightmaps.size * r_lightmaps.size * sizeof(unsigned), vid_lightPool, 0);
00282 
00283     r_lightmaps.direction_buffer = (byte *)Mem_PoolAlloc(
00284         r_lightmaps.size * r_lightmaps.size * sizeof(unsigned), vid_lightPool, 0);
00285 
00286     r_lightmaps.lightmap_texnum = TEXNUM_LIGHTMAPS;
00287     r_lightmaps.deluxemap_texnum = TEXNUM_DELUXEMAPS;
00288 }
00289 
00294 void R_EndBuildingLightmaps (void)
00295 {
00296     /* upload the pending lightmap block */
00297     R_UploadLightmapBlock();
00298 }
00299 
00300 
00308 void R_Trace (vec3_t start, vec3_t end, float size, int contentmask)
00309 {
00310     vec3_t mins, maxs;
00311     float frac;
00312     trace_t tr;
00313     int i;
00314 
00315     r_locals.tracenum++;
00316 
00317     if (r_locals.tracenum > 0xffff)  /* avoid overflows */
00318         r_locals.tracenum = 0;
00319 
00320     VectorSet(mins, -size, -size, -size);
00321     VectorSet(maxs, size, size, size);
00322 
00323     refdef.trace = CM_CompleteBoxTrace(refdef.mapTiles, start, end, mins, maxs, TRACING_ALL_VISIBLE_LEVELS, contentmask, 0);
00324     refdef.traceEntity = NULL;
00325 
00326     frac = refdef.trace.fraction;
00327 
00328     /* check bsp models */
00329     for (i = 0; i < refdef.numEntities; i++) {
00330         entity_t *ent = R_GetEntity(i);
00331         const model_t *m = ent->model;
00332 
00333         if (!m || m->type != mod_bsp_submodel)
00334             continue;
00335 
00336         tr = CM_TransformedBoxTrace(&(refdef.mapTiles->mapTiles[m->bsp.maptile]), start, end, mins, maxs, m->bsp.firstnode,
00337                 contentmask, 0, ent->origin, ent->angles);
00338 
00339         if (tr.fraction < frac) {
00340             refdef.trace = tr;
00341             refdef.traceEntity = ent;
00342 
00343             frac = tr.fraction;
00344         }
00345     }
00346 
00347     assert(refdef.trace.mapTile >= 0);
00348     assert(refdef.trace.mapTile < r_numMapTiles);
00349 }

Generated by  doxygen 1.6.2