diff options
| author | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:31:46 -0800 |
|---|---|---|
| committer | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:46:31 -0800 |
| commit | f56bb35301836e56582a575a75864392a0177875 (patch) | |
| tree | de61ddd39de3e7df52759711950b4c288592f0dc /mp/src/utils/vrad/radial.cpp | |
| parent | Mark some more files as text. (diff) | |
| download | source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip | |
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/utils/vrad/radial.cpp')
| -rw-r--r-- | mp/src/utils/vrad/radial.cpp | 1764 |
1 files changed, 882 insertions, 882 deletions
diff --git a/mp/src/utils/vrad/radial.cpp b/mp/src/utils/vrad/radial.cpp index 46e3b925..5dc99b50 100644 --- a/mp/src/utils/vrad/radial.cpp +++ b/mp/src/utils/vrad/radial.cpp @@ -1,882 +1,882 @@ -//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//
-//=============================================================================//
-
-#include "vrad.h"
-#include "lightmap.h"
-#include "radial.h"
-#include "mathlib/bumpvects.h"
-#include "utlrbtree.h"
-#include "mathlib/VMatrix.h"
-#include "macro_texture.h"
-
-
-void WorldToLuxelSpace( lightinfo_t const *l, Vector const &world, Vector2D &coord )
-{
- Vector pos;
-
- VectorSubtract( world, l->luxelOrigin, pos );
- coord[0] = DotProduct( pos, l->worldToLuxelSpace[0] ) - l->face->m_LightmapTextureMinsInLuxels[0];
- coord[1] = DotProduct( pos, l->worldToLuxelSpace[1] ) - l->face->m_LightmapTextureMinsInLuxels[1];
-}
-
-void LuxelSpaceToWorld( lightinfo_t const *l, float s, float t, Vector &world )
-{
- Vector pos;
-
- s += l->face->m_LightmapTextureMinsInLuxels[0];
- t += l->face->m_LightmapTextureMinsInLuxels[1];
- VectorMA( l->luxelOrigin, s, l->luxelToWorldSpace[0], pos );
- VectorMA( pos, t, l->luxelToWorldSpace[1], world );
-}
-
-void WorldToLuxelSpace( lightinfo_t const *l, FourVectors const &world, FourVectors &coord )
-{
- FourVectors luxelOrigin;
- luxelOrigin.DuplicateVector ( l->luxelOrigin );
-
- FourVectors pos = world;
- pos -= luxelOrigin;
-
- coord.x = pos * l->worldToLuxelSpace[0];
- coord.x = SubSIMD ( coord.x, ReplicateX4 ( l->face->m_LightmapTextureMinsInLuxels[0] ) );
- coord.y = pos * l->worldToLuxelSpace[1];
- coord.y = SubSIMD ( coord.y, ReplicateX4 ( l->face->m_LightmapTextureMinsInLuxels[1] ) );
- coord.z = Four_Zeros;
-}
-
-void LuxelSpaceToWorld( lightinfo_t const *l, fltx4 s, fltx4 t, FourVectors &world )
-{
- world.DuplicateVector ( l->luxelOrigin );
- FourVectors st;
-
- s = AddSIMD ( s, ReplicateX4 ( l->face->m_LightmapTextureMinsInLuxels[0] ) );
- st.DuplicateVector ( l->luxelToWorldSpace[0] );
- st *= s;
- world += st;
-
- t = AddSIMD ( t, ReplicateX4 ( l->face->m_LightmapTextureMinsInLuxels[1] ) );
- st.DuplicateVector ( l->luxelToWorldSpace[1] );
- st *= t;
- world += st;
-}
-
-
-
-void AddDirectToRadial( radial_t *rad,
- Vector const &pnt,
- Vector2D const &coordmins, Vector2D const &coordmaxs,
- LightingValue_t const light[NUM_BUMP_VECTS+1],
- bool hasBumpmap, bool neighborHasBumpmap )
-{
- int s_min, s_max, t_min, t_max;
- Vector2D coord;
- int s, t;
- float ds, dt;
- float r;
- float area;
- int bumpSample;
-
- // convert world pos into local lightmap texture coord
- WorldToLuxelSpace( &rad->l, pnt, coord );
-
- s_min = ( int )( coordmins[0] );
- t_min = ( int )( coordmins[1] );
- s_max = ( int )( coordmaxs[0] + 0.9999f ) + 1; // ????
- t_max = ( int )( coordmaxs[1] + 0.9999f ) + 1;
-
- s_min = max( s_min, 0 );
- t_min = max( t_min, 0 );
- s_max = min( s_max, rad->w );
- t_max = min( t_max, rad->h );
-
- for( s = s_min; s < s_max; s++ )
- {
- for( t = t_min; t < t_max; t++ )
- {
- float s0 = max( coordmins[0] - s, -1.0 );
- float t0 = max( coordmins[1] - t, -1.0 );
- float s1 = min( coordmaxs[0] - s, 1.0 );
- float t1 = min( coordmaxs[1] - t, 1.0 );
-
- area = (s1 - s0) * (t1 - t0);
-
- if (area > EQUAL_EPSILON)
- {
- ds = fabs( coord[0] - s );
- dt = fabs( coord[1] - t );
-
- r = max( ds, dt );
-
- if (r < 0.1)
- {
- r = area / 0.1;
- }
- else
- {
- r = area / r;
- }
-
- int i = s+t*rad->w;
-
- if( hasBumpmap )
- {
- if( neighborHasBumpmap )
- {
- for( bumpSample = 0; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ )
- {
- rad->light[bumpSample][i].AddWeighted( light[bumpSample], r );
- }
- }
- else
- {
- rad->light[0][i].AddWeighted(light[0],r );
- for( bumpSample = 1; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ )
- {
- rad->light[bumpSample][i].AddWeighted( light[0], r * OO_SQRT_3 );
- }
- }
- }
- else
- {
- rad->light[0][i].AddWeighted( light[0], r );
- }
-
- rad->weight[i] += r;
- }
- }
- }
-}
-
-
-
-void AddBouncedToRadial( radial_t *rad,
- Vector const &pnt,
- Vector2D const &coordmins, Vector2D const &coordmaxs,
- Vector const light[NUM_BUMP_VECTS+1],
- bool hasBumpmap, bool neighborHasBumpmap )
-{
- int s_min, s_max, t_min, t_max;
- Vector2D coord;
- int s, t;
- float ds, dt;
- float r;
- int bumpSample;
-
- // convert world pos into local lightmap texture coord
- WorldToLuxelSpace( &rad->l, pnt, coord );
-
- float dists, distt;
-
- dists = (coordmaxs[0] - coordmins[0]);
- distt = (coordmaxs[1] - coordmins[1]);
-
- // patches less than a luxel in size could be mistakeningly filtered, so clamp.
- dists = max( 1.0, dists );
- distt = max( 1.0, distt );
-
- // find possible domain of patch influence
- s_min = ( int )( coord[0] - dists * RADIALDIST );
- t_min = ( int )( coord[1] - distt * RADIALDIST );
- s_max = ( int )( coord[0] + dists * RADIALDIST + 1.0f );
- t_max = ( int )( coord[1] + distt * RADIALDIST + 1.0f );
-
- // clamp to valid luxel
- s_min = max( s_min, 0 );
- t_min = max( t_min, 0 );
- s_max = min( s_max, rad->w );
- t_max = min( t_max, rad->h );
-
- for( s = s_min; s < s_max; s++ )
- {
- for( t = t_min; t < t_max; t++ )
- {
- // patch influence is based on patch size
- ds = ( coord[0] - s ) / dists;
- dt = ( coord[1] - t ) / distt;
-
- r = RADIALDIST2 - (ds * ds + dt * dt);
-
- int i = s+t*rad->w;
-
- if (r > 0)
- {
- if( hasBumpmap )
- {
- if( neighborHasBumpmap )
- {
- for( bumpSample = 0; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ )
- {
- rad->light[bumpSample][i].AddWeighted( light[bumpSample], r );
- }
- }
- else
- {
- rad->light[0][i].AddWeighted( light[0], r );
- for( bumpSample = 1; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ )
- {
- rad->light[bumpSample][i].AddWeighted( light[0], r * OO_SQRT_3 );
- }
- }
- }
- else
- {
- rad->light[0][i].AddWeighted( light[0], r );
- }
-
- rad->weight[i] += r;
- }
- }
- }
-}
-
-void PatchLightmapCoordRange( radial_t *rad, int ndxPatch, Vector2D &mins, Vector2D &maxs )
-{
- winding_t *w;
- int i;
- Vector2D coord;
-
- mins.Init( 1E30, 1E30 );
- maxs.Init( -1E30, -1E30 );
-
- CPatch *patch = &g_Patches.Element( ndxPatch );
- w = patch->winding;
-
- for (i = 0; i < w->numpoints; i++)
- {
- WorldToLuxelSpace( &rad->l, w->p[i], coord );
- mins[0] = min( mins[0], coord[0] );
- maxs[0] = max( maxs[0], coord[0] );
- mins[1] = min( mins[1], coord[1] );
- maxs[1] = max( maxs[1], coord[1] );
- }
-}
-
-radial_t *AllocateRadial( int facenum )
-{
- radial_t *rad;
-
- rad = ( radial_t* )calloc( 1, sizeof( *rad ) );
-
- rad->facenum = facenum;
- InitLightinfo( &rad->l, facenum );
-
- rad->w = rad->l.face->m_LightmapTextureSizeInLuxels[0]+1;
- rad->h = rad->l.face->m_LightmapTextureSizeInLuxels[1]+1;
-
- return rad;
-}
-
-void FreeRadial( radial_t *rad )
-{
- if (rad)
- free( rad );
-}
-
-
-radial_t *BuildPatchRadial( int facenum )
-{
- int j;
- radial_t *rad;
- CPatch *patch;
- faceneighbor_t *fn;
- Vector2D mins, maxs;
- bool needsBumpmap, neighborNeedsBumpmap;
-
- needsBumpmap = texinfo[g_pFaces[facenum].texinfo].flags & SURF_BUMPLIGHT ? true : false;
-
- rad = AllocateRadial( facenum );
-
- fn = &faceneighbor[ rad->facenum ];
-
- CPatch *pNextPatch;
-
- if( g_FacePatches.Element( rad->facenum ) != g_FacePatches.InvalidIndex() )
- {
- for( patch = &g_Patches.Element( g_FacePatches.Element( rad->facenum ) ); patch; patch = pNextPatch )
- {
- // next patch
- pNextPatch = NULL;
- if( patch->ndxNext != g_Patches.InvalidIndex() )
- {
- pNextPatch = &g_Patches.Element( patch->ndxNext );
- }
-
- // skip patches with children
- if (patch->child1 != g_Patches.InvalidIndex() )
- continue;
-
- // get the range of patch lightmap texture coords
- int ndxPatch = patch - g_Patches.Base();
- PatchLightmapCoordRange( rad, ndxPatch, mins, maxs );
-
- if (patch->numtransfers == 0)
- {
- // Error, using patch that was never evaluated or has no samples
- // patch->totallight[1] = 255;
- }
-
- //
- // displacement surface patch origin position and normal vectors have been changed to
- // represent the displacement surface position and normal -- for radial "blending"
- // we need to get the base surface patch origin!
- //
- if( ValidDispFace( &g_pFaces[facenum] ) )
- {
- Vector patchOrigin;
- WindingCenter (patch->winding, patchOrigin );
- AddBouncedToRadial( rad, patchOrigin, mins, maxs, patch->totallight.light,
- needsBumpmap, needsBumpmap );
- }
- else
- {
- AddBouncedToRadial( rad, patch->origin, mins, maxs, patch->totallight.light,
- needsBumpmap, needsBumpmap );
- }
- }
- }
-
- for (j=0 ; j<fn->numneighbors; j++)
- {
- if( g_FacePatches.Element( fn->neighbor[j] ) != g_FacePatches.InvalidIndex() )
- {
- for( patch = &g_Patches.Element( g_FacePatches.Element( fn->neighbor[j] ) ); patch; patch = pNextPatch )
- {
- // next patch
- pNextPatch = NULL;
- if( patch->ndxNext != g_Patches.InvalidIndex() )
- {
- pNextPatch = &g_Patches.Element( patch->ndxNext );
- }
-
- // skip patches with children
- if (patch->child1 != g_Patches.InvalidIndex() )
- continue;
-
- // get the range of patch lightmap texture coords
- int ndxPatch = patch - g_Patches.Base();
- PatchLightmapCoordRange( rad, ndxPatch, mins, maxs );
-
- neighborNeedsBumpmap = texinfo[g_pFaces[facenum].texinfo].flags & SURF_BUMPLIGHT ? true : false;
-
- //
- // displacement surface patch origin position and normal vectors have been changed to
- // represent the displacement surface position and normal -- for radial "blending"
- // we need to get the base surface patch origin!
- //
- if( ValidDispFace( &g_pFaces[fn->neighbor[j]] ) )
- {
- Vector patchOrigin;
- WindingCenter (patch->winding, patchOrigin );
- AddBouncedToRadial( rad, patchOrigin, mins, maxs, patch->totallight.light,
- needsBumpmap, needsBumpmap );
- }
- else
- {
- AddBouncedToRadial( rad, patch->origin, mins, maxs, patch->totallight.light,
- needsBumpmap, needsBumpmap );
- }
- }
- }
- }
-
- return rad;
-}
-
-
-radial_t *BuildLuxelRadial( int facenum, int style )
-{
- LightingValue_t light[NUM_BUMP_VECTS + 1];
-
- facelight_t *fl = &facelight[facenum];
- faceneighbor_t *fn = &faceneighbor[facenum];
-
- radial_t *rad = AllocateRadial( facenum );
-
- bool needsBumpmap = texinfo[g_pFaces[facenum].texinfo].flags & SURF_BUMPLIGHT ? true : false;
-
- for (int k=0 ; k<fl->numsamples ; k++)
- {
- if( needsBumpmap )
- {
- for( int bumpSample = 0; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ )
- {
- light[bumpSample] = fl->light[style][bumpSample][k];
- }
- }
- else
- {
- light[0] = fl->light[style][0][k];
- }
-
- AddDirectToRadial( rad, fl->sample[k].pos, fl->sample[k].mins, fl->sample[k].maxs, light, needsBumpmap, needsBumpmap );
- }
-
- for (int j = 0; j < fn->numneighbors; j++)
- {
- fl = &facelight[fn->neighbor[j]];
-
- bool neighborHasBumpmap = false;
-
- if( texinfo[g_pFaces[fn->neighbor[j]].texinfo].flags & SURF_BUMPLIGHT )
- {
- neighborHasBumpmap = true;
- }
-
- int nstyle = 0;
-
- // look for style that matches
- if (g_pFaces[fn->neighbor[j]].styles[nstyle] != g_pFaces[facenum].styles[style])
- {
- for (nstyle = 1; nstyle < MAXLIGHTMAPS; nstyle++ )
- if ( g_pFaces[fn->neighbor[j]].styles[nstyle] == g_pFaces[facenum].styles[style] )
- break;
-
- // if not found, skip this neighbor
- if (nstyle >= MAXLIGHTMAPS)
- continue;
- }
-
- lightinfo_t l;
-
- InitLightinfo( &l, fn->neighbor[j] );
-
- for (int k=0 ; k<fl->numsamples ; k++)
- {
- if( neighborHasBumpmap )
- {
- for( int bumpSample = 0; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ )
- {
- light[bumpSample] = fl->light[nstyle][bumpSample][k];
- }
- }
- else
- {
- light[0]=fl->light[nstyle][0][k];
- }
-
- Vector tmp;
- Vector2D mins, maxs;
-
- LuxelSpaceToWorld( &l, fl->sample[k].mins[0], fl->sample[k].mins[1], tmp );
- WorldToLuxelSpace( &rad->l, tmp, mins );
- LuxelSpaceToWorld( &l, fl->sample[k].maxs[0], fl->sample[k].maxs[1], tmp );
- WorldToLuxelSpace( &rad->l, tmp, maxs );
-
- AddDirectToRadial( rad, fl->sample[k].pos, mins, maxs, light,
- needsBumpmap, neighborHasBumpmap );
- }
- }
-
- return rad;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: returns the closest light value for a given point on the surface
-// this is normally a 1:1 mapping
-//-----------------------------------------------------------------------------
-bool SampleRadial( radial_t *rad, Vector& pnt, LightingValue_t light[NUM_BUMP_VECTS + 1], int bumpSampleCount )
-{
- int bumpSample;
- Vector2D coord;
-
- WorldToLuxelSpace( &rad->l, pnt, coord );
- int u = ( int )( coord[0] + 0.5f );
- int v = ( int )( coord[1] + 0.5f );
- int i = u + v * rad->w;
-
- if (u < 0 || u > rad->w || v < 0 || v > rad->h)
- {
- static bool warning = false;
- if ( !warning )
- {
- // punting over to KenB
- // 2d coord indexes off of lightmap, generation of pnt seems suspect
- Warning( "SampleRadial: Punting, Waiting for fix\n" );
- warning = true;
- }
- for( bumpSample = 0; bumpSample < bumpSampleCount; bumpSample++ )
- {
- light[bumpSample].m_vecLighting.Init( 2550, 0, 0 );
- }
- return false;
- }
-
- bool baseSampleOk = true;
- for( bumpSample = 0; bumpSample < bumpSampleCount; bumpSample++ )
- {
- light[bumpSample].Zero();
-
- if (rad->weight[i] > WEIGHT_EPS)
- {
- light[bumpSample]= rad->light[bumpSample][i];
- light[bumpSample].Scale( 1.0 / rad->weight[i] );
- }
- else
- {
- if ( bRed2Black )
- {
- // Error, luxel has no samples
- light[bumpSample].m_vecLighting.Init( 0, 0, 0 );
- }
- else
- {
- // Error, luxel has no samples
- // Yes, it actually should be 2550
- light[bumpSample].m_vecLighting.Init( 2550, 0, 0 );
- }
-
- if (bumpSample == 0)
- baseSampleOk = false;
- }
- }
-
- return baseSampleOk;
-}
-
-bool FloatLess( float const& src1, float const& src2 )
-{
- return src1 < src2;
-}
-
-
-//-----------------------------------------------------------------------------
-// Debugging!
-//-----------------------------------------------------------------------------
-void GetRandomColor( unsigned char *color )
-{
- static bool firstTime = true;
-
- if( firstTime )
- {
- firstTime = false;
- srand( 0 );
- }
-
- color[0] = ( unsigned char )( rand() * ( 255.0f / VALVE_RAND_MAX ) );
- color[1] = ( unsigned char )( rand() * ( 255.0f / VALVE_RAND_MAX ) );
- color[2] = ( unsigned char )( rand() * ( 255.0f / VALVE_RAND_MAX ) );
-}
-
-
-#if 0
-// debugging! -- not accurate!
-void DumpLuxels( facelight_t *pFaceLight, Vector *luxelColors, int ndxFace )
-{
- static FileHandle_t pFpLuxels = NULL;
-
- ThreadLock();
-
- if( !pFpLuxels )
- {
- pFpLuxels = g_pFileSystem->Open( "luxels.txt", "w" );
- }
-
- dface_t *pFace = &g_pFaces[ndxFace];
- bool bDisp = ( pFace->dispinfo != -1 );
-
- for( int ndx = 0; ndx < pFaceLight->numluxels; ndx++ )
- {
- WriteWinding( pFpLuxels, pFaceLight->sample[ndx].w, luxelColors[ndx] );
- if( bDumpNormals && bDisp )
- {
- WriteNormal( pFpLuxels, pFaceLight->luxel[ndx], pFaceLight->luxelNormals[ndx], 15.0f, Vector( 255, 255, 0 ) );
- }
- }
-
- ThreadUnlock();
-}
-#endif
-
-
-static FileHandle_t pFileLuxels[4] = { NULL, NULL, NULL, NULL };
-
-void DumpDispLuxels( int iFace, Vector &color, int iLuxel, int nBump )
-{
- // Lock the thread and dump the luxel data.
- ThreadLock();
-
- // Get the face and facelight data.
- facelight_t *pFaceLight = &facelight[iFace];
-
- // Open the luxel files.
- char szFileName[512];
- for ( int iBump = 0; iBump < ( NUM_BUMP_VECTS+1 ); ++iBump )
- {
- if ( pFileLuxels[iBump] == NULL )
- {
- sprintf( szFileName, "luxels_bump%d.txt", iBump );
- pFileLuxels[iBump] = g_pFileSystem->Open( szFileName, "w" );
- }
- }
-
- WriteWinding( pFileLuxels[nBump], pFaceLight->sample[iLuxel].w, color );
-
- ThreadUnlock();
-}
-
-void CloseDispLuxels()
-{
- for ( int iBump = 0; iBump < ( NUM_BUMP_VECTS+1 ); ++iBump )
- {
- if ( pFileLuxels[iBump] )
- {
- g_pFileSystem->Close( pFileLuxels[iBump] );
- }
- }
-}
-
-/*
-=============
-FinalLightFace
-
-Add the indirect lighting on top of the direct
-lighting and save into final map format
-=============
-*/
-void FinalLightFace( int iThread, int facenum )
-{
- dface_t *f;
- int i, j, k;
- facelight_t *fl;
- float minlight;
- int lightstyles;
- LightingValue_t lb[NUM_BUMP_VECTS + 1], v[NUM_BUMP_VECTS + 1];
- unsigned char *pdata[NUM_BUMP_VECTS + 1];
- int bumpSample;
- radial_t *rad = NULL;
- radial_t *prad = NULL;
-
- f = &g_pFaces[facenum];
-
- // test for non-lit texture
- if ( texinfo[f->texinfo].flags & TEX_SPECIAL)
- return;
-
- fl = &facelight[facenum];
-
-
- for (lightstyles=0; lightstyles < MAXLIGHTMAPS; lightstyles++ )
- {
- if ( f->styles[lightstyles] == 255 )
- break;
- }
- if ( !lightstyles )
- return;
-
-
- //
- // sample the triangulation
- //
- minlight = FloatForKey (face_entity[facenum], "_minlight") * 128;
-
- bool needsBumpmap = ( texinfo[f->texinfo].flags & SURF_BUMPLIGHT ) ? true : false;
- int bumpSampleCount = needsBumpmap ? NUM_BUMP_VECTS + 1 : 1;
-
- bool bDisp = ( f->dispinfo != -1 );
-
-//#define RANDOM_COLOR
-
-#ifdef RANDOM_COLOR
- unsigned char randomColor[3];
- GetRandomColor( randomColor );
-#endif
-
-
- // NOTE: I'm using these RB trees to sort all the illumination values
- // to compute median colors. Turns out that this is a somewhat better
- // method that using the average; usually if there are surfaces
- // with a large light intensity variation, the extremely bright regions
- // have a very small area and tend to influence the average too much.
- CUtlRBTree< float, int > m_Red( 0, 256, FloatLess );
- CUtlRBTree< float, int > m_Green( 0, 256, FloatLess );
- CUtlRBTree< float, int > m_Blue( 0, 256, FloatLess );
-
- for (k=0 ; k < lightstyles; k++ )
- {
- m_Red.RemoveAll();
- m_Green.RemoveAll();
- m_Blue.RemoveAll();
-
- if (!do_fast)
- {
- if( !bDisp )
- {
- rad = BuildLuxelRadial( facenum, k );
- }
- else
- {
- rad = StaticDispMgr()->BuildLuxelRadial( facenum, k, needsBumpmap );
- }
- }
-
- if (numbounce > 0 && k == 0)
- {
- // currently only radiosity light non-displacement surfaces!
- if( !bDisp )
- {
- prad = BuildPatchRadial( facenum );
- }
- else
- {
- prad = StaticDispMgr()->BuildPatchRadial( facenum, needsBumpmap );
- }
- }
-
- // pack the nonbump texture and the three bump texture for the given
- // lightstyle right next to each other.
- // NOTE: Even though it's building positions for all bump-mapped data,
- // it isn't going to use those positions (see loop over bumpSample below)
- // The file offset is correctly computed to only store space for 1 set
- // of light data if we don't have bumped lighting.
- for( bumpSample = 0; bumpSample < bumpSampleCount; ++bumpSample )
- {
- pdata[bumpSample] = &(*pdlightdata)[f->lightofs + (k * bumpSampleCount + bumpSample) * fl->numluxels*4];
- }
-
- // Compute the average luxel color, but not for the bump samples
- Vector avg( 0.0f, 0.0f, 0.0f );
- int avgCount = 0;
-
- for (j=0 ; j<fl->numluxels; j++)
- {
- // garymct - direct lighting
- bool baseSampleOk = true;
-
- if (!do_fast)
- {
- if( !bDisp )
- {
- baseSampleOk = SampleRadial( rad, fl->luxel[j], lb, bumpSampleCount );
- }
- else
- {
- baseSampleOk = StaticDispMgr()->SampleRadial( facenum, rad, fl->luxel[j], j, lb, bumpSampleCount, false );
- }
- }
- else
- {
- for ( int iBump = 0 ; iBump < bumpSampleCount; iBump++ )
- {
- lb[iBump] = fl->light[0][iBump][j];
- }
- }
-
- if (prad)
- {
- // garymct - bounced light
- // v is indirect light that is received on the luxel.
- if( !bDisp )
- {
- SampleRadial( prad, fl->luxel[j], v, bumpSampleCount );
- }
- else
- {
- StaticDispMgr()->SampleRadial( facenum, prad, fl->luxel[j], j, v, bumpSampleCount, true );
- }
-
- for( bumpSample = 0; bumpSample < bumpSampleCount; ++bumpSample )
- {
- lb[bumpSample].AddLight( v[bumpSample] );
- }
- }
-
- if ( bDisp && g_bDumpPatches )
- {
- for( bumpSample = 0; bumpSample < bumpSampleCount; ++bumpSample )
- {
- DumpDispLuxels( facenum, lb[bumpSample].m_vecLighting, j, bumpSample );
- }
- }
-
- if (fl->numsamples == 0)
- {
- for( i = 0; i < bumpSampleCount; i++ )
- {
- lb[i].Init( 255, 0, 0 );
- }
- baseSampleOk = false;
- }
-
- int bumpSample;
- for( bumpSample = 0; bumpSample < bumpSampleCount; bumpSample++ )
- {
- // clip from the bottom first
- // garymct: minlight is a per entity minimum light value?
- for( i=0; i<3; i++ )
- {
- lb[bumpSample].m_vecLighting[i] = max( lb[bumpSample].m_vecLighting[i], minlight );
- }
-
- // Do the average light computation, I'm assuming (perhaps incorrectly?)
- // that all luxels in a particular lightmap have the same area here.
- // Also, don't bother doing averages for the bump samples. Doing it here
- // because of the minlight clamp above + the random color testy thingy.
- // Also have to do it before Vec3toColorRGBExp32 because it
- // destructively modifies lb[bumpSample] (Feh!)
- if ((bumpSample == 0) && baseSampleOk)
- {
- ++avgCount;
-
- ApplyMacroTextures( facenum, fl->luxel[j], lb[0].m_vecLighting );
-
- // For median computation
- m_Red.Insert( lb[bumpSample].m_vecLighting[0] );
- m_Green.Insert( lb[bumpSample].m_vecLighting[1] );
- m_Blue.Insert( lb[bumpSample].m_vecLighting[2] );
- }
-
-#ifdef RANDOM_COLOR
- pdata[bumpSample][0] = randomColor[0] / ( bumpSample + 1 );
- pdata[bumpSample][1] = randomColor[1] / ( bumpSample + 1 );
- pdata[bumpSample][2] = randomColor[2] / ( bumpSample + 1 );
- pdata[bumpSample][3] = 0;
-#else
- // convert to a 4 byte r,g,b,signed exponent format
- VectorToColorRGBExp32( Vector( lb[bumpSample].m_vecLighting.x, lb[bumpSample].m_vecLighting.y,
- lb[bumpSample].m_vecLighting.z ), *( ColorRGBExp32 *)pdata[bumpSample] );
-#endif
-
- pdata[bumpSample] += 4;
- }
- }
- FreeRadial( rad );
- if (prad)
- {
- FreeRadial( prad );
- prad = NULL;
- }
-
- // Compute the median color for this lightstyle
- // Remember, the data goes *before* the specified light_ofs, in *reverse order*
- ColorRGBExp32 *pAvgColor = dface_AvgLightColor( f, k );
- if (avgCount == 0)
- {
- Vector median( 0, 0, 0 );
- VectorToColorRGBExp32( median, *pAvgColor );
- }
- else
- {
- unsigned int r, g, b;
- r = m_Red.FirstInorder();
- g = m_Green.FirstInorder();
- b = m_Blue.FirstInorder();
- avgCount >>= 1;
- while (avgCount > 0)
- {
- r = m_Red.NextInorder(r);
- g = m_Green.NextInorder(g);
- b = m_Blue.NextInorder(b);
- --avgCount;
- }
-
- Vector median( m_Red[r], m_Green[g], m_Blue[b] );
- VectorToColorRGBExp32( median, *pAvgColor );
- }
- }
-}
+//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include "vrad.h" +#include "lightmap.h" +#include "radial.h" +#include "mathlib/bumpvects.h" +#include "utlrbtree.h" +#include "mathlib/VMatrix.h" +#include "macro_texture.h" + + +void WorldToLuxelSpace( lightinfo_t const *l, Vector const &world, Vector2D &coord ) +{ + Vector pos; + + VectorSubtract( world, l->luxelOrigin, pos ); + coord[0] = DotProduct( pos, l->worldToLuxelSpace[0] ) - l->face->m_LightmapTextureMinsInLuxels[0]; + coord[1] = DotProduct( pos, l->worldToLuxelSpace[1] ) - l->face->m_LightmapTextureMinsInLuxels[1]; +} + +void LuxelSpaceToWorld( lightinfo_t const *l, float s, float t, Vector &world ) +{ + Vector pos; + + s += l->face->m_LightmapTextureMinsInLuxels[0]; + t += l->face->m_LightmapTextureMinsInLuxels[1]; + VectorMA( l->luxelOrigin, s, l->luxelToWorldSpace[0], pos ); + VectorMA( pos, t, l->luxelToWorldSpace[1], world ); +} + +void WorldToLuxelSpace( lightinfo_t const *l, FourVectors const &world, FourVectors &coord ) +{ + FourVectors luxelOrigin; + luxelOrigin.DuplicateVector ( l->luxelOrigin ); + + FourVectors pos = world; + pos -= luxelOrigin; + + coord.x = pos * l->worldToLuxelSpace[0]; + coord.x = SubSIMD ( coord.x, ReplicateX4 ( l->face->m_LightmapTextureMinsInLuxels[0] ) ); + coord.y = pos * l->worldToLuxelSpace[1]; + coord.y = SubSIMD ( coord.y, ReplicateX4 ( l->face->m_LightmapTextureMinsInLuxels[1] ) ); + coord.z = Four_Zeros; +} + +void LuxelSpaceToWorld( lightinfo_t const *l, fltx4 s, fltx4 t, FourVectors &world ) +{ + world.DuplicateVector ( l->luxelOrigin ); + FourVectors st; + + s = AddSIMD ( s, ReplicateX4 ( l->face->m_LightmapTextureMinsInLuxels[0] ) ); + st.DuplicateVector ( l->luxelToWorldSpace[0] ); + st *= s; + world += st; + + t = AddSIMD ( t, ReplicateX4 ( l->face->m_LightmapTextureMinsInLuxels[1] ) ); + st.DuplicateVector ( l->luxelToWorldSpace[1] ); + st *= t; + world += st; +} + + + +void AddDirectToRadial( radial_t *rad, + Vector const &pnt, + Vector2D const &coordmins, Vector2D const &coordmaxs, + LightingValue_t const light[NUM_BUMP_VECTS+1], + bool hasBumpmap, bool neighborHasBumpmap ) +{ + int s_min, s_max, t_min, t_max; + Vector2D coord; + int s, t; + float ds, dt; + float r; + float area; + int bumpSample; + + // convert world pos into local lightmap texture coord + WorldToLuxelSpace( &rad->l, pnt, coord ); + + s_min = ( int )( coordmins[0] ); + t_min = ( int )( coordmins[1] ); + s_max = ( int )( coordmaxs[0] + 0.9999f ) + 1; // ???? + t_max = ( int )( coordmaxs[1] + 0.9999f ) + 1; + + s_min = max( s_min, 0 ); + t_min = max( t_min, 0 ); + s_max = min( s_max, rad->w ); + t_max = min( t_max, rad->h ); + + for( s = s_min; s < s_max; s++ ) + { + for( t = t_min; t < t_max; t++ ) + { + float s0 = max( coordmins[0] - s, -1.0 ); + float t0 = max( coordmins[1] - t, -1.0 ); + float s1 = min( coordmaxs[0] - s, 1.0 ); + float t1 = min( coordmaxs[1] - t, 1.0 ); + + area = (s1 - s0) * (t1 - t0); + + if (area > EQUAL_EPSILON) + { + ds = fabs( coord[0] - s ); + dt = fabs( coord[1] - t ); + + r = max( ds, dt ); + + if (r < 0.1) + { + r = area / 0.1; + } + else + { + r = area / r; + } + + int i = s+t*rad->w; + + if( hasBumpmap ) + { + if( neighborHasBumpmap ) + { + for( bumpSample = 0; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ ) + { + rad->light[bumpSample][i].AddWeighted( light[bumpSample], r ); + } + } + else + { + rad->light[0][i].AddWeighted(light[0],r ); + for( bumpSample = 1; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ ) + { + rad->light[bumpSample][i].AddWeighted( light[0], r * OO_SQRT_3 ); + } + } + } + else + { + rad->light[0][i].AddWeighted( light[0], r ); + } + + rad->weight[i] += r; + } + } + } +} + + + +void AddBouncedToRadial( radial_t *rad, + Vector const &pnt, + Vector2D const &coordmins, Vector2D const &coordmaxs, + Vector const light[NUM_BUMP_VECTS+1], + bool hasBumpmap, bool neighborHasBumpmap ) +{ + int s_min, s_max, t_min, t_max; + Vector2D coord; + int s, t; + float ds, dt; + float r; + int bumpSample; + + // convert world pos into local lightmap texture coord + WorldToLuxelSpace( &rad->l, pnt, coord ); + + float dists, distt; + + dists = (coordmaxs[0] - coordmins[0]); + distt = (coordmaxs[1] - coordmins[1]); + + // patches less than a luxel in size could be mistakeningly filtered, so clamp. + dists = max( 1.0, dists ); + distt = max( 1.0, distt ); + + // find possible domain of patch influence + s_min = ( int )( coord[0] - dists * RADIALDIST ); + t_min = ( int )( coord[1] - distt * RADIALDIST ); + s_max = ( int )( coord[0] + dists * RADIALDIST + 1.0f ); + t_max = ( int )( coord[1] + distt * RADIALDIST + 1.0f ); + + // clamp to valid luxel + s_min = max( s_min, 0 ); + t_min = max( t_min, 0 ); + s_max = min( s_max, rad->w ); + t_max = min( t_max, rad->h ); + + for( s = s_min; s < s_max; s++ ) + { + for( t = t_min; t < t_max; t++ ) + { + // patch influence is based on patch size + ds = ( coord[0] - s ) / dists; + dt = ( coord[1] - t ) / distt; + + r = RADIALDIST2 - (ds * ds + dt * dt); + + int i = s+t*rad->w; + + if (r > 0) + { + if( hasBumpmap ) + { + if( neighborHasBumpmap ) + { + for( bumpSample = 0; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ ) + { + rad->light[bumpSample][i].AddWeighted( light[bumpSample], r ); + } + } + else + { + rad->light[0][i].AddWeighted( light[0], r ); + for( bumpSample = 1; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ ) + { + rad->light[bumpSample][i].AddWeighted( light[0], r * OO_SQRT_3 ); + } + } + } + else + { + rad->light[0][i].AddWeighted( light[0], r ); + } + + rad->weight[i] += r; + } + } + } +} + +void PatchLightmapCoordRange( radial_t *rad, int ndxPatch, Vector2D &mins, Vector2D &maxs ) +{ + winding_t *w; + int i; + Vector2D coord; + + mins.Init( 1E30, 1E30 ); + maxs.Init( -1E30, -1E30 ); + + CPatch *patch = &g_Patches.Element( ndxPatch ); + w = patch->winding; + + for (i = 0; i < w->numpoints; i++) + { + WorldToLuxelSpace( &rad->l, w->p[i], coord ); + mins[0] = min( mins[0], coord[0] ); + maxs[0] = max( maxs[0], coord[0] ); + mins[1] = min( mins[1], coord[1] ); + maxs[1] = max( maxs[1], coord[1] ); + } +} + +radial_t *AllocateRadial( int facenum ) +{ + radial_t *rad; + + rad = ( radial_t* )calloc( 1, sizeof( *rad ) ); + + rad->facenum = facenum; + InitLightinfo( &rad->l, facenum ); + + rad->w = rad->l.face->m_LightmapTextureSizeInLuxels[0]+1; + rad->h = rad->l.face->m_LightmapTextureSizeInLuxels[1]+1; + + return rad; +} + +void FreeRadial( radial_t *rad ) +{ + if (rad) + free( rad ); +} + + +radial_t *BuildPatchRadial( int facenum ) +{ + int j; + radial_t *rad; + CPatch *patch; + faceneighbor_t *fn; + Vector2D mins, maxs; + bool needsBumpmap, neighborNeedsBumpmap; + + needsBumpmap = texinfo[g_pFaces[facenum].texinfo].flags & SURF_BUMPLIGHT ? true : false; + + rad = AllocateRadial( facenum ); + + fn = &faceneighbor[ rad->facenum ]; + + CPatch *pNextPatch; + + if( g_FacePatches.Element( rad->facenum ) != g_FacePatches.InvalidIndex() ) + { + for( patch = &g_Patches.Element( g_FacePatches.Element( rad->facenum ) ); patch; patch = pNextPatch ) + { + // next patch + pNextPatch = NULL; + if( patch->ndxNext != g_Patches.InvalidIndex() ) + { + pNextPatch = &g_Patches.Element( patch->ndxNext ); + } + + // skip patches with children + if (patch->child1 != g_Patches.InvalidIndex() ) + continue; + + // get the range of patch lightmap texture coords + int ndxPatch = patch - g_Patches.Base(); + PatchLightmapCoordRange( rad, ndxPatch, mins, maxs ); + + if (patch->numtransfers == 0) + { + // Error, using patch that was never evaluated or has no samples + // patch->totallight[1] = 255; + } + + // + // displacement surface patch origin position and normal vectors have been changed to + // represent the displacement surface position and normal -- for radial "blending" + // we need to get the base surface patch origin! + // + if( ValidDispFace( &g_pFaces[facenum] ) ) + { + Vector patchOrigin; + WindingCenter (patch->winding, patchOrigin ); + AddBouncedToRadial( rad, patchOrigin, mins, maxs, patch->totallight.light, + needsBumpmap, needsBumpmap ); + } + else + { + AddBouncedToRadial( rad, patch->origin, mins, maxs, patch->totallight.light, + needsBumpmap, needsBumpmap ); + } + } + } + + for (j=0 ; j<fn->numneighbors; j++) + { + if( g_FacePatches.Element( fn->neighbor[j] ) != g_FacePatches.InvalidIndex() ) + { + for( patch = &g_Patches.Element( g_FacePatches.Element( fn->neighbor[j] ) ); patch; patch = pNextPatch ) + { + // next patch + pNextPatch = NULL; + if( patch->ndxNext != g_Patches.InvalidIndex() ) + { + pNextPatch = &g_Patches.Element( patch->ndxNext ); + } + + // skip patches with children + if (patch->child1 != g_Patches.InvalidIndex() ) + continue; + + // get the range of patch lightmap texture coords + int ndxPatch = patch - g_Patches.Base(); + PatchLightmapCoordRange( rad, ndxPatch, mins, maxs ); + + neighborNeedsBumpmap = texinfo[g_pFaces[facenum].texinfo].flags & SURF_BUMPLIGHT ? true : false; + + // + // displacement surface patch origin position and normal vectors have been changed to + // represent the displacement surface position and normal -- for radial "blending" + // we need to get the base surface patch origin! + // + if( ValidDispFace( &g_pFaces[fn->neighbor[j]] ) ) + { + Vector patchOrigin; + WindingCenter (patch->winding, patchOrigin ); + AddBouncedToRadial( rad, patchOrigin, mins, maxs, patch->totallight.light, + needsBumpmap, needsBumpmap ); + } + else + { + AddBouncedToRadial( rad, patch->origin, mins, maxs, patch->totallight.light, + needsBumpmap, needsBumpmap ); + } + } + } + } + + return rad; +} + + +radial_t *BuildLuxelRadial( int facenum, int style ) +{ + LightingValue_t light[NUM_BUMP_VECTS + 1]; + + facelight_t *fl = &facelight[facenum]; + faceneighbor_t *fn = &faceneighbor[facenum]; + + radial_t *rad = AllocateRadial( facenum ); + + bool needsBumpmap = texinfo[g_pFaces[facenum].texinfo].flags & SURF_BUMPLIGHT ? true : false; + + for (int k=0 ; k<fl->numsamples ; k++) + { + if( needsBumpmap ) + { + for( int bumpSample = 0; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ ) + { + light[bumpSample] = fl->light[style][bumpSample][k]; + } + } + else + { + light[0] = fl->light[style][0][k]; + } + + AddDirectToRadial( rad, fl->sample[k].pos, fl->sample[k].mins, fl->sample[k].maxs, light, needsBumpmap, needsBumpmap ); + } + + for (int j = 0; j < fn->numneighbors; j++) + { + fl = &facelight[fn->neighbor[j]]; + + bool neighborHasBumpmap = false; + + if( texinfo[g_pFaces[fn->neighbor[j]].texinfo].flags & SURF_BUMPLIGHT ) + { + neighborHasBumpmap = true; + } + + int nstyle = 0; + + // look for style that matches + if (g_pFaces[fn->neighbor[j]].styles[nstyle] != g_pFaces[facenum].styles[style]) + { + for (nstyle = 1; nstyle < MAXLIGHTMAPS; nstyle++ ) + if ( g_pFaces[fn->neighbor[j]].styles[nstyle] == g_pFaces[facenum].styles[style] ) + break; + + // if not found, skip this neighbor + if (nstyle >= MAXLIGHTMAPS) + continue; + } + + lightinfo_t l; + + InitLightinfo( &l, fn->neighbor[j] ); + + for (int k=0 ; k<fl->numsamples ; k++) + { + if( neighborHasBumpmap ) + { + for( int bumpSample = 0; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ ) + { + light[bumpSample] = fl->light[nstyle][bumpSample][k]; + } + } + else + { + light[0]=fl->light[nstyle][0][k]; + } + + Vector tmp; + Vector2D mins, maxs; + + LuxelSpaceToWorld( &l, fl->sample[k].mins[0], fl->sample[k].mins[1], tmp ); + WorldToLuxelSpace( &rad->l, tmp, mins ); + LuxelSpaceToWorld( &l, fl->sample[k].maxs[0], fl->sample[k].maxs[1], tmp ); + WorldToLuxelSpace( &rad->l, tmp, maxs ); + + AddDirectToRadial( rad, fl->sample[k].pos, mins, maxs, light, + needsBumpmap, neighborHasBumpmap ); + } + } + + return rad; +} + + +//----------------------------------------------------------------------------- +// Purpose: returns the closest light value for a given point on the surface +// this is normally a 1:1 mapping +//----------------------------------------------------------------------------- +bool SampleRadial( radial_t *rad, Vector& pnt, LightingValue_t light[NUM_BUMP_VECTS + 1], int bumpSampleCount ) +{ + int bumpSample; + Vector2D coord; + + WorldToLuxelSpace( &rad->l, pnt, coord ); + int u = ( int )( coord[0] + 0.5f ); + int v = ( int )( coord[1] + 0.5f ); + int i = u + v * rad->w; + + if (u < 0 || u > rad->w || v < 0 || v > rad->h) + { + static bool warning = false; + if ( !warning ) + { + // punting over to KenB + // 2d coord indexes off of lightmap, generation of pnt seems suspect + Warning( "SampleRadial: Punting, Waiting for fix\n" ); + warning = true; + } + for( bumpSample = 0; bumpSample < bumpSampleCount; bumpSample++ ) + { + light[bumpSample].m_vecLighting.Init( 2550, 0, 0 ); + } + return false; + } + + bool baseSampleOk = true; + for( bumpSample = 0; bumpSample < bumpSampleCount; bumpSample++ ) + { + light[bumpSample].Zero(); + + if (rad->weight[i] > WEIGHT_EPS) + { + light[bumpSample]= rad->light[bumpSample][i]; + light[bumpSample].Scale( 1.0 / rad->weight[i] ); + } + else + { + if ( bRed2Black ) + { + // Error, luxel has no samples + light[bumpSample].m_vecLighting.Init( 0, 0, 0 ); + } + else + { + // Error, luxel has no samples + // Yes, it actually should be 2550 + light[bumpSample].m_vecLighting.Init( 2550, 0, 0 ); + } + + if (bumpSample == 0) + baseSampleOk = false; + } + } + + return baseSampleOk; +} + +bool FloatLess( float const& src1, float const& src2 ) +{ + return src1 < src2; +} + + +//----------------------------------------------------------------------------- +// Debugging! +//----------------------------------------------------------------------------- +void GetRandomColor( unsigned char *color ) +{ + static bool firstTime = true; + + if( firstTime ) + { + firstTime = false; + srand( 0 ); + } + + color[0] = ( unsigned char )( rand() * ( 255.0f / VALVE_RAND_MAX ) ); + color[1] = ( unsigned char )( rand() * ( 255.0f / VALVE_RAND_MAX ) ); + color[2] = ( unsigned char )( rand() * ( 255.0f / VALVE_RAND_MAX ) ); +} + + +#if 0 +// debugging! -- not accurate! +void DumpLuxels( facelight_t *pFaceLight, Vector *luxelColors, int ndxFace ) +{ + static FileHandle_t pFpLuxels = NULL; + + ThreadLock(); + + if( !pFpLuxels ) + { + pFpLuxels = g_pFileSystem->Open( "luxels.txt", "w" ); + } + + dface_t *pFace = &g_pFaces[ndxFace]; + bool bDisp = ( pFace->dispinfo != -1 ); + + for( int ndx = 0; ndx < pFaceLight->numluxels; ndx++ ) + { + WriteWinding( pFpLuxels, pFaceLight->sample[ndx].w, luxelColors[ndx] ); + if( bDumpNormals && bDisp ) + { + WriteNormal( pFpLuxels, pFaceLight->luxel[ndx], pFaceLight->luxelNormals[ndx], 15.0f, Vector( 255, 255, 0 ) ); + } + } + + ThreadUnlock(); +} +#endif + + +static FileHandle_t pFileLuxels[4] = { NULL, NULL, NULL, NULL }; + +void DumpDispLuxels( int iFace, Vector &color, int iLuxel, int nBump ) +{ + // Lock the thread and dump the luxel data. + ThreadLock(); + + // Get the face and facelight data. + facelight_t *pFaceLight = &facelight[iFace]; + + // Open the luxel files. + char szFileName[512]; + for ( int iBump = 0; iBump < ( NUM_BUMP_VECTS+1 ); ++iBump ) + { + if ( pFileLuxels[iBump] == NULL ) + { + sprintf( szFileName, "luxels_bump%d.txt", iBump ); + pFileLuxels[iBump] = g_pFileSystem->Open( szFileName, "w" ); + } + } + + WriteWinding( pFileLuxels[nBump], pFaceLight->sample[iLuxel].w, color ); + + ThreadUnlock(); +} + +void CloseDispLuxels() +{ + for ( int iBump = 0; iBump < ( NUM_BUMP_VECTS+1 ); ++iBump ) + { + if ( pFileLuxels[iBump] ) + { + g_pFileSystem->Close( pFileLuxels[iBump] ); + } + } +} + +/* +============= +FinalLightFace + +Add the indirect lighting on top of the direct +lighting and save into final map format +============= +*/ +void FinalLightFace( int iThread, int facenum ) +{ + dface_t *f; + int i, j, k; + facelight_t *fl; + float minlight; + int lightstyles; + LightingValue_t lb[NUM_BUMP_VECTS + 1], v[NUM_BUMP_VECTS + 1]; + unsigned char *pdata[NUM_BUMP_VECTS + 1]; + int bumpSample; + radial_t *rad = NULL; + radial_t *prad = NULL; + + f = &g_pFaces[facenum]; + + // test for non-lit texture + if ( texinfo[f->texinfo].flags & TEX_SPECIAL) + return; + + fl = &facelight[facenum]; + + + for (lightstyles=0; lightstyles < MAXLIGHTMAPS; lightstyles++ ) + { + if ( f->styles[lightstyles] == 255 ) + break; + } + if ( !lightstyles ) + return; + + + // + // sample the triangulation + // + minlight = FloatForKey (face_entity[facenum], "_minlight") * 128; + + bool needsBumpmap = ( texinfo[f->texinfo].flags & SURF_BUMPLIGHT ) ? true : false; + int bumpSampleCount = needsBumpmap ? NUM_BUMP_VECTS + 1 : 1; + + bool bDisp = ( f->dispinfo != -1 ); + +//#define RANDOM_COLOR + +#ifdef RANDOM_COLOR + unsigned char randomColor[3]; + GetRandomColor( randomColor ); +#endif + + + // NOTE: I'm using these RB trees to sort all the illumination values + // to compute median colors. Turns out that this is a somewhat better + // method that using the average; usually if there are surfaces + // with a large light intensity variation, the extremely bright regions + // have a very small area and tend to influence the average too much. + CUtlRBTree< float, int > m_Red( 0, 256, FloatLess ); + CUtlRBTree< float, int > m_Green( 0, 256, FloatLess ); + CUtlRBTree< float, int > m_Blue( 0, 256, FloatLess ); + + for (k=0 ; k < lightstyles; k++ ) + { + m_Red.RemoveAll(); + m_Green.RemoveAll(); + m_Blue.RemoveAll(); + + if (!do_fast) + { + if( !bDisp ) + { + rad = BuildLuxelRadial( facenum, k ); + } + else + { + rad = StaticDispMgr()->BuildLuxelRadial( facenum, k, needsBumpmap ); + } + } + + if (numbounce > 0 && k == 0) + { + // currently only radiosity light non-displacement surfaces! + if( !bDisp ) + { + prad = BuildPatchRadial( facenum ); + } + else + { + prad = StaticDispMgr()->BuildPatchRadial( facenum, needsBumpmap ); + } + } + + // pack the nonbump texture and the three bump texture for the given + // lightstyle right next to each other. + // NOTE: Even though it's building positions for all bump-mapped data, + // it isn't going to use those positions (see loop over bumpSample below) + // The file offset is correctly computed to only store space for 1 set + // of light data if we don't have bumped lighting. + for( bumpSample = 0; bumpSample < bumpSampleCount; ++bumpSample ) + { + pdata[bumpSample] = &(*pdlightdata)[f->lightofs + (k * bumpSampleCount + bumpSample) * fl->numluxels*4]; + } + + // Compute the average luxel color, but not for the bump samples + Vector avg( 0.0f, 0.0f, 0.0f ); + int avgCount = 0; + + for (j=0 ; j<fl->numluxels; j++) + { + // garymct - direct lighting + bool baseSampleOk = true; + + if (!do_fast) + { + if( !bDisp ) + { + baseSampleOk = SampleRadial( rad, fl->luxel[j], lb, bumpSampleCount ); + } + else + { + baseSampleOk = StaticDispMgr()->SampleRadial( facenum, rad, fl->luxel[j], j, lb, bumpSampleCount, false ); + } + } + else + { + for ( int iBump = 0 ; iBump < bumpSampleCount; iBump++ ) + { + lb[iBump] = fl->light[0][iBump][j]; + } + } + + if (prad) + { + // garymct - bounced light + // v is indirect light that is received on the luxel. + if( !bDisp ) + { + SampleRadial( prad, fl->luxel[j], v, bumpSampleCount ); + } + else + { + StaticDispMgr()->SampleRadial( facenum, prad, fl->luxel[j], j, v, bumpSampleCount, true ); + } + + for( bumpSample = 0; bumpSample < bumpSampleCount; ++bumpSample ) + { + lb[bumpSample].AddLight( v[bumpSample] ); + } + } + + if ( bDisp && g_bDumpPatches ) + { + for( bumpSample = 0; bumpSample < bumpSampleCount; ++bumpSample ) + { + DumpDispLuxels( facenum, lb[bumpSample].m_vecLighting, j, bumpSample ); + } + } + + if (fl->numsamples == 0) + { + for( i = 0; i < bumpSampleCount; i++ ) + { + lb[i].Init( 255, 0, 0 ); + } + baseSampleOk = false; + } + + int bumpSample; + for( bumpSample = 0; bumpSample < bumpSampleCount; bumpSample++ ) + { + // clip from the bottom first + // garymct: minlight is a per entity minimum light value? + for( i=0; i<3; i++ ) + { + lb[bumpSample].m_vecLighting[i] = max( lb[bumpSample].m_vecLighting[i], minlight ); + } + + // Do the average light computation, I'm assuming (perhaps incorrectly?) + // that all luxels in a particular lightmap have the same area here. + // Also, don't bother doing averages for the bump samples. Doing it here + // because of the minlight clamp above + the random color testy thingy. + // Also have to do it before Vec3toColorRGBExp32 because it + // destructively modifies lb[bumpSample] (Feh!) + if ((bumpSample == 0) && baseSampleOk) + { + ++avgCount; + + ApplyMacroTextures( facenum, fl->luxel[j], lb[0].m_vecLighting ); + + // For median computation + m_Red.Insert( lb[bumpSample].m_vecLighting[0] ); + m_Green.Insert( lb[bumpSample].m_vecLighting[1] ); + m_Blue.Insert( lb[bumpSample].m_vecLighting[2] ); + } + +#ifdef RANDOM_COLOR + pdata[bumpSample][0] = randomColor[0] / ( bumpSample + 1 ); + pdata[bumpSample][1] = randomColor[1] / ( bumpSample + 1 ); + pdata[bumpSample][2] = randomColor[2] / ( bumpSample + 1 ); + pdata[bumpSample][3] = 0; +#else + // convert to a 4 byte r,g,b,signed exponent format + VectorToColorRGBExp32( Vector( lb[bumpSample].m_vecLighting.x, lb[bumpSample].m_vecLighting.y, + lb[bumpSample].m_vecLighting.z ), *( ColorRGBExp32 *)pdata[bumpSample] ); +#endif + + pdata[bumpSample] += 4; + } + } + FreeRadial( rad ); + if (prad) + { + FreeRadial( prad ); + prad = NULL; + } + + // Compute the median color for this lightstyle + // Remember, the data goes *before* the specified light_ofs, in *reverse order* + ColorRGBExp32 *pAvgColor = dface_AvgLightColor( f, k ); + if (avgCount == 0) + { + Vector median( 0, 0, 0 ); + VectorToColorRGBExp32( median, *pAvgColor ); + } + else + { + unsigned int r, g, b; + r = m_Red.FirstInorder(); + g = m_Green.FirstInorder(); + b = m_Blue.FirstInorder(); + avgCount >>= 1; + while (avgCount > 0) + { + r = m_Red.NextInorder(r); + g = m_Green.NextInorder(g); + b = m_Blue.NextInorder(b); + --avgCount; + } + + Vector median( m_Red[r], m_Green[g], m_Blue[b] ); + VectorToColorRGBExp32( median, *pAvgColor ); + } + } +} |