diff options
| author | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
|---|---|---|
| committer | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
| commit | 39ed87570bdb2f86969d4be821c94b722dc71179 (patch) | |
| tree | abc53757f75f40c80278e87650ea92808274aa59 /mp/src/utils/vrad/radial.cpp | |
| download | source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip | |
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/utils/vrad/radial.cpp')
| -rw-r--r-- | mp/src/utils/vrad/radial.cpp | 882 |
1 files changed, 882 insertions, 0 deletions
diff --git a/mp/src/utils/vrad/radial.cpp b/mp/src/utils/vrad/radial.cpp new file mode 100644 index 00000000..46e3b925 --- /dev/null +++ b/mp/src/utils/vrad/radial.cpp @@ -0,0 +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 );
+ }
+ }
+}
|