Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3976 lines
117 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "vrad.h"
  9. #include "lightmap.h"
  10. #include "radial.h"
  11. #include "mathlib/bumpvects.h"
  12. #include "tier1/utlvector.h"
  13. #include "vmpi.h"
  14. #include "mathlib/anorms.h"
  15. #include "map_utils.h"
  16. #include "mathlib/halton.h"
  17. #include "imagepacker.h"
  18. #include "tier1/utlrbtree.h"
  19. #include "tier1/utlbuffer.h"
  20. #include "bitmap/tgawriter.h"
  21. #include "mathlib/quantize.h"
  22. #include "bitmap/imageformat.h"
  23. #include "coordsize.h"
  24. enum
  25. {
  26. AMBIENT_ONLY = 0x1,
  27. NON_AMBIENT_ONLY = 0x2,
  28. };
  29. #define SMOOTHING_GROUP_HARD_EDGE 0xff000000
  30. //==========================================================================//
  31. // Ambient occlusion
  32. //==========================================================================//
  33. bool g_bNoSoften = false;
  34. bool g_bNoAO = false;
  35. float CalculateAmbientOcclusion( Vector *pPosition, Vector *pNormal )
  36. {
  37. // Just call through to the simd version of this function
  38. FourVectors position4;
  39. position4.DuplicateVector( *pPosition );
  40. FourVectors normal4;
  41. position4.DuplicateVector( *pNormal );
  42. fltx4 ao = CalculateAmbientOcclusion4( position4, normal4, -1 );
  43. return SubFloat( ao, 0 );
  44. }
  45. fltx4 CalculateAmbientOcclusion4( const FourVectors &position4, const FourVectors &normal4, int static_prop_index_to_ignore )
  46. {
  47. if ( g_bNoAO )
  48. {
  49. return Four_Ones;
  50. }
  51. DirectionalSampler_t sampler;
  52. int nSamples = 32;
  53. if ( do_fast )
  54. {
  55. nSamples /= 2;
  56. }
  57. fltx4 totalVisible = Four_Zeros;
  58. fltx4 totalPossibleVisible = Four_Zeros;
  59. for ( int i = 0; i < nSamples; i++ )
  60. {
  61. FourVectors rayStart = position4;
  62. rayStart += normal4;
  63. // Ray direction on the sphere
  64. FourVectors rayDirection;
  65. rayDirection.DuplicateVector( sampler.NextValue() );
  66. // Mirror ray along normal so all rays are on the hemisphere defined by the normal
  67. fltx4 rayDotN = rayDirection * normal4; // dot product
  68. fltx4 absRayDotN = AbsSIMD( rayDotN );
  69. rayDirection = rayDirection - Mul( normal4, rayDotN ) + Mul( normal4, absRayDotN );
  70. // Set length of ray
  71. FourVectors rayEnd = rayDirection;
  72. rayEnd *= 36.0f;
  73. rayEnd += rayStart;
  74. // Raytrace for visibility function
  75. fltx4 fractionVisible = Four_Ones;
  76. TestLine_IgnoreSky( rayStart, rayEnd, &fractionVisible, static_prop_index_to_ignore );
  77. totalVisible = AddSIMD( totalVisible, MulSIMD( fractionVisible, absRayDotN ) );
  78. totalPossibleVisible = AddSIMD( totalPossibleVisible, absRayDotN );
  79. }
  80. fltx4 ao = DivSIMD( totalVisible, totalPossibleVisible );
  81. ao = MulSIMD( ao, ao ); // Square ao term - This is an artistic choice by the CS:GO team
  82. return ao;
  83. }
  84. //==========================================================================//
  85. // Give surfaces a softer look instead of the harsher linear N.L look
  86. //==========================================================================//
  87. float SoftenCosineTerm( float flDot )
  88. {
  89. if ( g_bNoSoften )
  90. return flDot;
  91. flDot = MAX( flDot, 0.0f );
  92. return ( flDot + ( flDot * flDot ) ) * 0.5f; // This is cheaper than an exponent in shader code
  93. }
  94. fltx4 SoftenCosineTerm( fltx4 dots )
  95. {
  96. if ( g_bNoSoften )
  97. return dots;
  98. dots = MaxSIMD( dots, Four_Zeros );
  99. fltx4 dotsSquared = MulSIMD( dots, dots );
  100. return MulSIMD( AddSIMD( dots, dotsSquared ), Four_PointFives );
  101. }
  102. //==========================================================================//
  103. // CNormalList.
  104. //==========================================================================//
  105. // This class keeps a list of unique normals and provides a fast
  106. class CNormalList
  107. {
  108. public:
  109. CNormalList();
  110. // Adds the normal if unique. Otherwise, returns the normal's index into m_Normals.
  111. int FindOrAddNormal( Vector const &vNormal );
  112. public:
  113. CUtlVector<Vector> m_Normals;
  114. private:
  115. // This represents a grid from (-1,-1,-1) to (1,1,1).
  116. enum {NUM_SUBDIVS = 8};
  117. CUtlVector<int> m_NormalGrid[NUM_SUBDIVS][NUM_SUBDIVS][NUM_SUBDIVS];
  118. };
  119. int g_iCurFace;
  120. edgeshare_t edgeshare[MAX_MAP_EDGES];
  121. Vector face_centroids[MAX_MAP_EDGES];
  122. int vertexref[MAX_MAP_VERTS];
  123. int *vertexface[MAX_MAP_VERTS];
  124. faceneighbor_t faceneighbor[MAX_MAP_FACES];
  125. static directlight_t *gSkyLight = NULL;
  126. static directlight_t *gAmbient = NULL;
  127. //==========================================================================//
  128. // CNormalList implementation.
  129. //==========================================================================//
  130. CNormalList::CNormalList() : m_Normals( 128 )
  131. {
  132. for( int i=0; i < sizeof(m_NormalGrid)/sizeof(m_NormalGrid[0][0][0]); i++ )
  133. {
  134. (&m_NormalGrid[0][0][0] + i)->SetGrowSize( 16 );
  135. }
  136. }
  137. int CNormalList::FindOrAddNormal( Vector const &vNormal )
  138. {
  139. int gi[3];
  140. // See which grid element it's in.
  141. for( int iDim=0; iDim < 3; iDim++ )
  142. {
  143. gi[iDim] = (int)( ((vNormal[iDim] + 1.0f) * 0.5f) * NUM_SUBDIVS - 0.000001f );
  144. gi[iDim] = min( gi[iDim], NUM_SUBDIVS );
  145. gi[iDim] = max( gi[iDim], 0 );
  146. }
  147. // Look for a matching vector in there.
  148. CUtlVector<int> *pGridElement = &m_NormalGrid[gi[0]][gi[1]][gi[2]];
  149. for( int i=0; i < pGridElement->Count(); i++ )
  150. {
  151. int iNormal = pGridElement->Element(i);
  152. Vector *pVec = &m_Normals[iNormal];
  153. //if( pVec->DistToSqr(vNormal) < 0.00001f )
  154. if( *pVec == vNormal )
  155. return iNormal;
  156. }
  157. // Ok, add a new one.
  158. pGridElement->AddToTail( m_Normals.Count() );
  159. return m_Normals.AddToTail( vNormal );
  160. }
  161. // FIXME: HACK until the plane normals are made more happy
  162. void GetBumpNormals( const float* sVect, const float* tVect, const Vector& flatNormal,
  163. const Vector& phongNormal, Vector bumpNormals[NUM_BUMP_VECTS] )
  164. {
  165. Vector stmp( sVect[0], sVect[1], sVect[2] );
  166. Vector ttmp( tVect[0], tVect[1], tVect[2] );
  167. GetBumpNormals( stmp, ttmp, flatNormal, phongNormal, bumpNormals );
  168. }
  169. int EdgeVertex( dface_t *f, int edge )
  170. {
  171. int k;
  172. if (edge < 0)
  173. edge += f->numedges;
  174. else if (edge >= f->numedges)
  175. edge = edge % f->numedges;
  176. k = dsurfedges[f->firstedge + edge];
  177. if (k < 0)
  178. {
  179. // Msg("(%d %d) ", dedges[-k].v[1], dedges[-k].v[0] );
  180. return dedges[-k].v[1];
  181. }
  182. else
  183. {
  184. // Msg("(%d %d) ", dedges[k].v[0], dedges[k].v[1] );
  185. return dedges[k].v[0];
  186. }
  187. }
  188. /*
  189. ============
  190. PairEdges
  191. ============
  192. */
  193. void PairEdges (void)
  194. {
  195. int i, j, k, n, m;
  196. dface_t *f;
  197. int numneighbors;
  198. int tmpneighbor[64];
  199. faceneighbor_t *fn;
  200. // count number of faces that reference each vertex
  201. for (i=0, f = g_pFaces; i<numfaces ; i++, f++)
  202. {
  203. for (j=0 ; j<f->numedges ; j++)
  204. {
  205. // Store the count in vertexref
  206. vertexref[EdgeVertex(f,j)]++;
  207. }
  208. }
  209. // allocate room
  210. for (i = 0; i < numvertexes; i++)
  211. {
  212. // use the count from above to allocate a big enough array
  213. vertexface[i] = ( int* )calloc( vertexref[i], sizeof( vertexface[0] ) );
  214. // clear the temporary data
  215. vertexref[i] = 0;
  216. }
  217. // store a list of every face that uses a particular vertex
  218. for (i=0, f = g_pFaces ; i<numfaces ; i++, f++)
  219. {
  220. for (j=0 ; j<f->numedges ; j++)
  221. {
  222. n = EdgeVertex(f,j);
  223. for (k = 0; k < vertexref[n]; k++)
  224. {
  225. if (vertexface[n][k] == i)
  226. break;
  227. }
  228. if (k >= vertexref[n])
  229. {
  230. // add the face to the list
  231. vertexface[n][k] = i;
  232. vertexref[n]++;
  233. }
  234. }
  235. }
  236. // calc normals and set displacement surface flag
  237. for (i=0, f = g_pFaces; i<numfaces ; i++, f++)
  238. {
  239. fn = &faceneighbor[i];
  240. // get face normal
  241. VectorCopy( dplanes[f->planenum].normal, fn->facenormal );
  242. // set displacement surface flag
  243. fn->bHasDisp = false;
  244. if( ValidDispFace( f ) )
  245. {
  246. fn->bHasDisp = true;
  247. }
  248. }
  249. // find neighbors
  250. for (i=0, f = g_pFaces ; i<numfaces ; i++, f++)
  251. {
  252. numneighbors = 0;
  253. fn = &faceneighbor[i];
  254. // allocate room for vertex normals
  255. fn->normal = ( Vector* )calloc( f->numedges, sizeof( fn->normal[0] ) );
  256. // look up all faces sharing vertices and add them to the list
  257. for (j=0 ; j<f->numedges ; j++)
  258. {
  259. n = EdgeVertex(f,j);
  260. for (k = 0; k < vertexref[n]; k++)
  261. {
  262. double cos_normals_angle;
  263. Vector *pNeighbornormal;
  264. // skip self
  265. if (vertexface[n][k] == i)
  266. continue;
  267. // if this face doens't have a displacement -- don't consider displacement neighbors
  268. if( ( !fn->bHasDisp ) && ( faceneighbor[vertexface[n][k]].bHasDisp ) )
  269. continue;
  270. pNeighbornormal = &faceneighbor[vertexface[n][k]].facenormal;
  271. cos_normals_angle = DotProduct( *pNeighbornormal, fn->facenormal );
  272. // add normal if >= threshold or its a displacement surface (this is only if the original
  273. // face is a displacement)
  274. if ( fn->bHasDisp )
  275. {
  276. // Always smooth with and against a displacement surface.
  277. VectorAdd( fn->normal[j], *pNeighbornormal, fn->normal[j] );
  278. }
  279. else
  280. {
  281. // No smoothing - use of method (backwards compatibility).
  282. if ( ( f->smoothingGroups == 0 ) && ( g_pFaces[vertexface[n][k]].smoothingGroups == 0 ) )
  283. {
  284. if ( cos_normals_angle >= smoothing_threshold )
  285. {
  286. VectorAdd( fn->normal[j], *pNeighbornormal, fn->normal[j] );
  287. }
  288. else
  289. {
  290. // not considered a neighbor
  291. continue;
  292. }
  293. }
  294. else
  295. {
  296. unsigned int smoothingGroup = ( f->smoothingGroups & g_pFaces[vertexface[n][k]].smoothingGroups );
  297. // Hard edge.
  298. if ( ( smoothingGroup & SMOOTHING_GROUP_HARD_EDGE ) != 0 )
  299. continue;
  300. if ( smoothingGroup != 0 )
  301. {
  302. VectorAdd( fn->normal[j], *pNeighbornormal, fn->normal[j] );
  303. }
  304. else
  305. {
  306. // not considered a neighbor
  307. continue;
  308. }
  309. }
  310. }
  311. // look to see if we've already added this one
  312. for (m = 0; m < numneighbors; m++)
  313. {
  314. if (tmpneighbor[m] == vertexface[n][k])
  315. break;
  316. }
  317. if (m >= numneighbors)
  318. {
  319. // add to neighbor list
  320. tmpneighbor[m] = vertexface[n][k];
  321. numneighbors++;
  322. if ( numneighbors > ARRAYSIZE(tmpneighbor) )
  323. {
  324. Error("Stack overflow in neighbors\n");
  325. }
  326. }
  327. }
  328. }
  329. if (numneighbors)
  330. {
  331. // copy over neighbor list
  332. fn->numneighbors = numneighbors;
  333. fn->neighbor = ( int* )calloc( numneighbors, sizeof( fn->neighbor[0] ) );
  334. for (m = 0; m < numneighbors; m++)
  335. {
  336. fn->neighbor[m] = tmpneighbor[m];
  337. }
  338. }
  339. // fixup normals
  340. for (j = 0; j < f->numedges; j++)
  341. {
  342. VectorAdd( fn->normal[j], fn->facenormal, fn->normal[j] );
  343. VectorNormalize( fn->normal[j] );
  344. }
  345. }
  346. }
  347. void SaveVertexNormals( void )
  348. {
  349. faceneighbor_t *fn;
  350. int i, j;
  351. dface_t *f;
  352. CNormalList normalList;
  353. g_numvertnormalindices = 0;
  354. for( i = 0 ;i<numfaces ; i++ )
  355. {
  356. fn = &faceneighbor[i];
  357. f = &g_pFaces[i];
  358. for( j = 0; j < f->numedges; j++ )
  359. {
  360. Vector vNormal;
  361. if( fn->normal )
  362. {
  363. vNormal = fn->normal[j];
  364. }
  365. else
  366. {
  367. // original faces don't have normals
  368. vNormal.Init( 0, 0, 0 );
  369. }
  370. if( g_numvertnormalindices == MAX_MAP_VERTNORMALINDICES )
  371. {
  372. Error( "g_numvertnormalindices == MAX_MAP_VERTNORMALINDICES" );
  373. }
  374. g_vertnormalindices[g_numvertnormalindices] = (unsigned short)normalList.FindOrAddNormal( vNormal );
  375. g_numvertnormalindices++;
  376. }
  377. }
  378. if( normalList.m_Normals.Count() > MAX_MAP_VERTNORMALS )
  379. {
  380. Error( "g_numvertnormals > MAX_MAP_VERTNORMALS" );
  381. }
  382. // Copy the list of unique vert normals into g_vertnormals.
  383. g_numvertnormals = normalList.m_Normals.Count();
  384. memcpy( g_vertnormals, normalList.m_Normals.Base(), sizeof(g_vertnormals[0]) * normalList.m_Normals.Count() );
  385. }
  386. /*
  387. =================================================================
  388. LIGHTMAP SAMPLE GENERATION
  389. =================================================================
  390. */
  391. //-----------------------------------------------------------------------------
  392. // Purpose: Spits out an error message with information about a lightinfo_t.
  393. // Input : s - Error message string.
  394. // l - lightmap info struct.
  395. //-----------------------------------------------------------------------------
  396. void ErrorLightInfo(const char *s, lightinfo_t *l)
  397. {
  398. texinfo_t *tex = &texinfo[l->face->texinfo];
  399. winding_t *w = WindingFromFace(&g_pFaces[l->facenum], l->modelorg);
  400. //
  401. // Show the face center and material name if possible.
  402. //
  403. if (w != NULL)
  404. {
  405. // Don't exit, we'll try to recover...
  406. Vector vecCenter;
  407. WindingCenter(w, vecCenter);
  408. // FreeWinding(w);
  409. Warning("%s at (%g, %g, %g)\n\tmaterial=%s\n", s, (double)vecCenter.x, (double)vecCenter.y, (double)vecCenter.z, TexDataStringTable_GetString( dtexdata[tex->texdata].nameStringTableID ) );
  410. }
  411. //
  412. // If not, just show the material name.
  413. //
  414. else
  415. {
  416. Warning("%s at (degenerate face)\n\tmaterial=%s\n", TexDataStringTable_GetString( dtexdata[tex->texdata].nameStringTableID ));
  417. }
  418. }
  419. void CalcFaceVectors(lightinfo_t *l)
  420. {
  421. texinfo_t *tex;
  422. int i, j;
  423. tex = &texinfo[l->face->texinfo];
  424. // move into lightinfo_t
  425. for (i=0 ; i<2 ; i++)
  426. {
  427. for (j=0 ; j<3 ; j++)
  428. {
  429. l->worldToLuxelSpace[i][j] = tex->lightmapVecsLuxelsPerWorldUnits[i][j];
  430. }
  431. }
  432. //Solve[ { x * w00 + y * w01 + z * w02 - s == 0, x * w10 + y * w11 + z * w12 - t == 0, A * x + B * y + C * z + D == 0 }, { x, y, z } ]
  433. //Rule(x,( C*s*w11 - B*s*w12 + B*t*w02 - C*t*w01 + D*w02*w11 - D*w01*w12) / (+ A*w01*w12 - A*w02*w11 + B*w02*w10 - B*w00*w12 + C*w00*w11 - C*w01*w10 )),
  434. //Rule(y,( A*s*w12 - C*s*w10 + C*t*w00 - A*t*w02 + D*w00*w12 - D*w02*w10) / (+ A*w01*w12 - A*w02*w11 + B*w02*w10 - B*w00*w12 + C*w00*w11 - C*w01*w10 )),
  435. //Rule(z,( B*s*w10 - A*s*w11 + A*t*w01 - B*t*w00 + D*w01*w10 - D*w00*w11) / (+ A*w01*w12 - A*w02*w11 + B*w02*w10 - B*w00*w12 + C*w00*w11 - C*w01*w10 ))))
  436. Vector luxelSpaceCross;
  437. luxelSpaceCross[0] =
  438. tex->lightmapVecsLuxelsPerWorldUnits[1][1] * tex->lightmapVecsLuxelsPerWorldUnits[0][2] -
  439. tex->lightmapVecsLuxelsPerWorldUnits[1][2] * tex->lightmapVecsLuxelsPerWorldUnits[0][1];
  440. luxelSpaceCross[1] =
  441. tex->lightmapVecsLuxelsPerWorldUnits[1][2] * tex->lightmapVecsLuxelsPerWorldUnits[0][0] -
  442. tex->lightmapVecsLuxelsPerWorldUnits[1][0] * tex->lightmapVecsLuxelsPerWorldUnits[0][2];
  443. luxelSpaceCross[2] =
  444. tex->lightmapVecsLuxelsPerWorldUnits[1][0] * tex->lightmapVecsLuxelsPerWorldUnits[0][1] -
  445. tex->lightmapVecsLuxelsPerWorldUnits[1][1] * tex->lightmapVecsLuxelsPerWorldUnits[0][0];
  446. float det = -DotProduct( l->facenormal, luxelSpaceCross );
  447. if ( fabs( det ) < 1.0e-20 )
  448. {
  449. Warning(" warning - face vectors parallel to face normal. bad lighting will be produced\n" );
  450. l->luxelOrigin = vec3_origin;
  451. }
  452. else
  453. {
  454. // invert the matrix
  455. l->luxelToWorldSpace[0][0] = (l->facenormal[2] * l->worldToLuxelSpace[1][1] - l->facenormal[1] * l->worldToLuxelSpace[1][2]) / det;
  456. l->luxelToWorldSpace[1][0] = (l->facenormal[1] * l->worldToLuxelSpace[0][2] - l->facenormal[2] * l->worldToLuxelSpace[0][1]) / det;
  457. l->luxelOrigin[0] = -(l->facedist * luxelSpaceCross[0]) / det;
  458. l->luxelToWorldSpace[0][1] = (l->facenormal[0] * l->worldToLuxelSpace[1][2] - l->facenormal[2] * l->worldToLuxelSpace[1][0]) / det;
  459. l->luxelToWorldSpace[1][1] = (l->facenormal[2] * l->worldToLuxelSpace[0][0] - l->facenormal[0] * l->worldToLuxelSpace[0][2]) / det;
  460. l->luxelOrigin[1] = -(l->facedist * luxelSpaceCross[1]) / det;
  461. l->luxelToWorldSpace[0][2] = (l->facenormal[1] * l->worldToLuxelSpace[1][0] - l->facenormal[0] * l->worldToLuxelSpace[1][1]) / det;
  462. l->luxelToWorldSpace[1][2] = (l->facenormal[0] * l->worldToLuxelSpace[0][1] - l->facenormal[1] * l->worldToLuxelSpace[0][0]) / det;
  463. l->luxelOrigin[2] = -(l->facedist * luxelSpaceCross[2]) / det;
  464. // adjust for luxel offset
  465. VectorMA( l->luxelOrigin, -tex->lightmapVecsLuxelsPerWorldUnits[0][3], l->luxelToWorldSpace[0], l->luxelOrigin );
  466. VectorMA( l->luxelOrigin, -tex->lightmapVecsLuxelsPerWorldUnits[1][3], l->luxelToWorldSpace[1], l->luxelOrigin );
  467. }
  468. // compensate for org'd bmodels
  469. VectorAdd (l->luxelOrigin, l->modelorg, l->luxelOrigin);
  470. }
  471. winding_t *LightmapCoordWindingForFace( lightinfo_t *l )
  472. {
  473. int i;
  474. winding_t *w;
  475. w = WindingFromFace( l->face, l->modelorg );
  476. for (i = 0; i < w->numpoints; i++)
  477. {
  478. Vector2D coord;
  479. WorldToLuxelSpace( l, w->p[i], coord );
  480. w->p[i].x = coord.x;
  481. w->p[i].y = coord.y;
  482. w->p[i].z = 0;
  483. }
  484. return w;
  485. }
  486. void WriteCoordWinding (FILE *out, lightinfo_t *l, winding_t *w, Vector& color )
  487. {
  488. int i;
  489. Vector pos;
  490. fprintf (out, "%i\n", w->numpoints);
  491. for (i=0 ; i<w->numpoints ; i++)
  492. {
  493. LuxelSpaceToWorld( l, w->p[i][0], w->p[i][1], pos );
  494. fprintf (out, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
  495. pos[0],
  496. pos[1],
  497. pos[2],
  498. color[ 0 ] / 256,
  499. color[ 1 ] / 256,
  500. color[ 2 ] / 256 );
  501. }
  502. }
  503. //-----------------------------------------------------------------------------
  504. //-----------------------------------------------------------------------------
  505. void DumpFaces( lightinfo_t *pLightInfo, int ndxFace )
  506. {
  507. static FileHandle_t out;
  508. // get face data
  509. faceneighbor_t *fn = &faceneighbor[ndxFace];
  510. Vector &centroid = face_centroids[ndxFace];
  511. // disable threading (not a multi-threadable function!)
  512. ThreadLock();
  513. if( !out )
  514. {
  515. // open the file
  516. out = g_pFileSystem->Open( "face.txt", "w" );
  517. if( !out )
  518. return;
  519. }
  520. //
  521. // write out face
  522. //
  523. for( int ndxEdge = 0; ndxEdge < pLightInfo->face->numedges; ndxEdge++ )
  524. {
  525. // int edge = dsurfedges[pLightInfo->face->firstedge+ndxEdge];
  526. Vector p1, p2;
  527. VectorAdd( dvertexes[EdgeVertex( pLightInfo->face, ndxEdge )].point, pLightInfo->modelorg, p1 );
  528. VectorAdd( dvertexes[EdgeVertex( pLightInfo->face, ndxEdge+1 )].point, pLightInfo->modelorg, p2 );
  529. Vector &n1 = fn->normal[ndxEdge];
  530. Vector &n2 = fn->normal[(ndxEdge+1)%pLightInfo->face->numedges];
  531. CmdLib_FPrintf( out, "3\n");
  532. CmdLib_FPrintf(out, "%f %f %f %f %f %f\n", p1[0], p1[1], p1[2], n1[0] * 0.5 + 0.5, n1[1] * 0.5 + 0.5, n1[2] * 0.5 + 0.5 );
  533. CmdLib_FPrintf(out, "%f %f %f %f %f %f\n", p2[0], p2[1], p2[2], n2[0] * 0.5 + 0.5, n2[1] * 0.5 + 0.5, n2[2] * 0.5 + 0.5 );
  534. CmdLib_FPrintf(out, "%f %f %f %f %f %f\n", centroid[0] + pLightInfo->modelorg[0],
  535. centroid[1] + pLightInfo->modelorg[1],
  536. centroid[2] + pLightInfo->modelorg[2],
  537. fn->facenormal[0] * 0.5 + 0.5,
  538. fn->facenormal[1] * 0.5 + 0.5,
  539. fn->facenormal[2] * 0.5 + 0.5 );
  540. }
  541. // enable threading
  542. ThreadUnlock();
  543. }
  544. //-----------------------------------------------------------------------------
  545. //-----------------------------------------------------------------------------
  546. bool BuildFacesamplesAndLuxels_DoFast( lightinfo_t *pLightInfo, facelight_t *pFaceLight )
  547. {
  548. // lightmap size
  549. int width = pLightInfo->face->m_LightmapTextureSizeInLuxels[0]+1;
  550. int height = pLightInfo->face->m_LightmapTextureSizeInLuxels[1]+1;
  551. // ratio of world area / lightmap area
  552. texinfo_t *pTex = &texinfo[pLightInfo->face->texinfo];
  553. pFaceLight->worldAreaPerLuxel = 1.0 / ( sqrt( DotProduct( pTex->lightmapVecsLuxelsPerWorldUnits[0],
  554. pTex->lightmapVecsLuxelsPerWorldUnits[0] ) ) *
  555. sqrt( DotProduct( pTex->lightmapVecsLuxelsPerWorldUnits[1],
  556. pTex->lightmapVecsLuxelsPerWorldUnits[1] ) ) );
  557. //
  558. // quickly create samples and luxels (copy over samples)
  559. //
  560. pFaceLight->numsamples = width * height;
  561. pFaceLight->sample = ( sample_t* )calloc( pFaceLight->numsamples, sizeof( *pFaceLight->sample ) );
  562. if( !pFaceLight->sample )
  563. return false;
  564. pFaceLight->numluxels = width * height;
  565. pFaceLight->luxel = ( Vector* )calloc( pFaceLight->numluxels, sizeof( *pFaceLight->luxel ) );
  566. if( !pFaceLight->luxel )
  567. return false;
  568. sample_t *pSamples = pFaceLight->sample;
  569. Vector *pLuxels = pFaceLight->luxel;
  570. for( int t = 0; t < height; t++ )
  571. {
  572. for( int s = 0; s < width; s++ )
  573. {
  574. pSamples->s = s;
  575. pSamples->t = t;
  576. pSamples->coord[0] = s;
  577. pSamples->coord[1] = t;
  578. // unused but initialized anyway
  579. pSamples->mins[0] = s - 0.5;
  580. pSamples->mins[1] = t - 0.5;
  581. pSamples->maxs[0] = s + 0.5;
  582. pSamples->maxs[1] = t + 0.5;
  583. pSamples->area = pFaceLight->worldAreaPerLuxel;
  584. LuxelSpaceToWorld( pLightInfo, pSamples->coord[0], pSamples->coord[1], pSamples->pos );
  585. VectorCopy( pSamples->pos, *pLuxels );
  586. pSamples++;
  587. pLuxels++;
  588. }
  589. }
  590. return true;
  591. }
  592. //-----------------------------------------------------------------------------
  593. //-----------------------------------------------------------------------------
  594. bool BuildSamplesAndLuxels_DoFast( lightinfo_t *pLightInfo, facelight_t *pFaceLight, int ndxFace )
  595. {
  596. // build samples for a "face"
  597. if( pLightInfo->face->dispinfo == -1 )
  598. {
  599. return BuildFacesamplesAndLuxels_DoFast( pLightInfo, pFaceLight );
  600. }
  601. // build samples for a "displacement"
  602. else
  603. {
  604. return StaticDispMgr()->BuildDispSamplesAndLuxels_DoFast( pLightInfo, pFaceLight, ndxFace );
  605. }
  606. }
  607. //-----------------------------------------------------------------------------
  608. //-----------------------------------------------------------------------------
  609. bool BuildFacesamples( lightinfo_t *pLightInfo, facelight_t *pFaceLight )
  610. {
  611. // lightmap size
  612. int width = pLightInfo->face->m_LightmapTextureSizeInLuxels[0]+1;
  613. int height = pLightInfo->face->m_LightmapTextureSizeInLuxels[1]+1;
  614. // ratio of world area / lightmap area
  615. texinfo_t *pTex = &texinfo[pLightInfo->face->texinfo];
  616. pFaceLight->worldAreaPerLuxel = 1.0 / ( sqrt( DotProduct( pTex->lightmapVecsLuxelsPerWorldUnits[0],
  617. pTex->lightmapVecsLuxelsPerWorldUnits[0] ) ) *
  618. sqrt( DotProduct( pTex->lightmapVecsLuxelsPerWorldUnits[1],
  619. pTex->lightmapVecsLuxelsPerWorldUnits[1] ) ) );
  620. // allocate a large number of samples for creation -- get copied later!
  621. CUtlVector<sample_t> sampleData;
  622. sampleData.SetCount( SINGLE_BRUSH_MAP * 2 );
  623. sample_t *samples = sampleData.Base();
  624. sample_t *pSamples = samples;
  625. // lightmap space winding
  626. winding_t *pLightmapWinding = LightmapCoordWindingForFace( pLightInfo );
  627. //
  628. // build vector pointing along the lightmap cutting planes
  629. //
  630. Vector sNorm( 1.0f, 0.0f, 0.0f );
  631. Vector tNorm( 0.0f, 1.0f, 0.0f );
  632. // sample center offset
  633. float sampleOffset = ( do_centersamples ) ? 0.5 : 1.0;
  634. //
  635. // clip the lightmap "spaced" winding by the lightmap cutting planes
  636. //
  637. winding_t *pWindingT1, *pWindingT2;
  638. winding_t *pWindingS1, *pWindingS2;
  639. float dist;
  640. for( int t = 0; t < height && pLightmapWinding; t++ )
  641. {
  642. dist = t + sampleOffset;
  643. // lop off a sample in the t dimension
  644. // hack - need a separate epsilon for lightmap space since ON_EPSILON is for texture space
  645. ClipWindingEpsilon( pLightmapWinding, tNorm, dist, ON_EPSILON / 16.0f, &pWindingT1, &pWindingT2 );
  646. for( int s = 0; s < width && pWindingT2; s++ )
  647. {
  648. dist = s + sampleOffset;
  649. // lop off a sample in the s dimension, and put it in ws2
  650. // hack - need a separate epsilon for lightmap space since ON_EPSILON is for texture space
  651. ClipWindingEpsilon( pWindingT2, sNorm, dist, ON_EPSILON / 16.0f, &pWindingS1, &pWindingS2 );
  652. //
  653. // s2 winding is a single sample worth of winding
  654. //
  655. if( pWindingS2 )
  656. {
  657. // save the s, t positions
  658. pSamples->s = s;
  659. pSamples->t = t;
  660. // get the lightmap space area of ws2 and convert to world area
  661. // and find the center (then convert it to 2D)
  662. Vector center;
  663. pSamples->area = WindingAreaAndBalancePoint( pWindingS2, center ) * pFaceLight->worldAreaPerLuxel;
  664. pSamples->coord[0] = center.x;
  665. pSamples->coord[1] = center.y;
  666. // find winding bounds (then convert it to 2D)
  667. Vector minbounds, maxbounds;
  668. WindingBounds( pWindingS2, minbounds, maxbounds );
  669. pSamples->mins[0] = minbounds.x;
  670. pSamples->mins[1] = minbounds.y;
  671. pSamples->maxs[0] = maxbounds.x;
  672. pSamples->maxs[1] = maxbounds.y;
  673. // convert from lightmap space to world space
  674. LuxelSpaceToWorld( pLightInfo, pSamples->coord[0], pSamples->coord[1], pSamples->pos );
  675. if (g_bDumpPatches || (do_extra && pSamples->area < pFaceLight->worldAreaPerLuxel - EQUAL_EPSILON))
  676. {
  677. //
  678. // convert the winding from lightmaps space to world for debug rendering and sub-sampling
  679. //
  680. Vector worldPos;
  681. for( int ndxPt = 0; ndxPt < pWindingS2->numpoints; ndxPt++ )
  682. {
  683. LuxelSpaceToWorld( pLightInfo, pWindingS2->p[ndxPt].x, pWindingS2->p[ndxPt].y, worldPos );
  684. VectorCopy( worldPos, pWindingS2->p[ndxPt] );
  685. }
  686. pSamples->w = pWindingS2;
  687. }
  688. else
  689. {
  690. // winding isn't needed, free it.
  691. pSamples->w = NULL;
  692. FreeWinding( pWindingS2 );
  693. }
  694. pSamples++;
  695. }
  696. //
  697. // if winding T2 still exists free it and set it equal S1 (the rest of the row minus the sample just created)
  698. //
  699. if( pWindingT2 )
  700. {
  701. FreeWinding( pWindingT2 );
  702. }
  703. // clip the rest of "s"
  704. pWindingT2 = pWindingS1;
  705. }
  706. //
  707. // if the original lightmap winding exists free it and set it equal to T1 (the rest of the winding not cut into samples)
  708. //
  709. if( pLightmapWinding )
  710. {
  711. FreeWinding( pLightmapWinding );
  712. }
  713. if( pWindingT2 )
  714. {
  715. FreeWinding( pWindingT2 );
  716. }
  717. pLightmapWinding = pWindingT1;
  718. }
  719. //
  720. // copy over samples
  721. //
  722. pFaceLight->numsamples = pSamples - samples;
  723. pFaceLight->sample = ( sample_t* )calloc( pFaceLight->numsamples, sizeof( *pFaceLight->sample ) );
  724. if( !pFaceLight->sample )
  725. return false;
  726. memcpy( pFaceLight->sample, samples, pFaceLight->numsamples * sizeof( *pFaceLight->sample ) );
  727. // supply a default sample normal (face normal - assumed flat)
  728. for( int ndxSample = 0; ndxSample < pFaceLight->numsamples; ndxSample++ )
  729. {
  730. Assert ( VectorLength ( pLightInfo->facenormal ) > 1.0e-20);
  731. pFaceLight->sample[ndxSample].normal = pLightInfo->facenormal;
  732. }
  733. // statistics - warning?!
  734. if( pFaceLight->numsamples == 0 )
  735. {
  736. Msg( "no samples %d\n", pLightInfo->face - g_pFaces );
  737. }
  738. return true;
  739. }
  740. //-----------------------------------------------------------------------------
  741. // Purpose: Free any windings used by this facelight. It's currently assumed they're not needed again
  742. //-----------------------------------------------------------------------------
  743. void FreeSampleWindings( facelight_t *fl )
  744. {
  745. int i;
  746. for (i = 0; i < fl->numsamples; i++)
  747. {
  748. if (fl->sample[i].w)
  749. {
  750. FreeWinding( fl->sample[i].w );
  751. fl->sample[i].w = NULL;
  752. }
  753. }
  754. }
  755. //-----------------------------------------------------------------------------
  756. // Purpose: build the sample data for each lightmapped primitive type
  757. //-----------------------------------------------------------------------------
  758. bool BuildSamples( lightinfo_t *pLightInfo, facelight_t *pFaceLight, int ndxFace )
  759. {
  760. // build samples for a "face"
  761. if( pLightInfo->face->dispinfo == -1 )
  762. {
  763. return BuildFacesamples( pLightInfo, pFaceLight );
  764. }
  765. // build samples for a "displacement"
  766. else
  767. {
  768. return StaticDispMgr()->BuildDispSamples( pLightInfo, pFaceLight, ndxFace );
  769. }
  770. }
  771. //-----------------------------------------------------------------------------
  772. //-----------------------------------------------------------------------------
  773. bool BuildFaceLuxels( lightinfo_t *pLightInfo, facelight_t *pFaceLight )
  774. {
  775. // lightmap size
  776. int width = pLightInfo->face->m_LightmapTextureSizeInLuxels[0]+1;
  777. int height = pLightInfo->face->m_LightmapTextureSizeInLuxels[1]+1;
  778. // calcuate actual luxel points
  779. pFaceLight->numluxels = width * height;
  780. pFaceLight->luxel = ( Vector* )calloc( pFaceLight->numluxels, sizeof( *pFaceLight->luxel ) );
  781. if( !pFaceLight->luxel )
  782. return false;
  783. for( int t = 0; t < height; t++ )
  784. {
  785. for( int s = 0; s < width; s++ )
  786. {
  787. LuxelSpaceToWorld( pLightInfo, s, t, pFaceLight->luxel[s+t*width] );
  788. }
  789. }
  790. return true;
  791. }
  792. //-----------------------------------------------------------------------------
  793. // Purpose: build the luxels (find the luxel centers) for each lightmapped
  794. // primitive type
  795. //-----------------------------------------------------------------------------
  796. bool BuildLuxels( lightinfo_t *pLightInfo, facelight_t *pFaceLight, int ndxFace )
  797. {
  798. // build luxels for a "face"
  799. if( pLightInfo->face->dispinfo == -1 )
  800. {
  801. return BuildFaceLuxels( pLightInfo, pFaceLight );
  802. }
  803. // build luxels for a "displacement"
  804. else
  805. {
  806. return StaticDispMgr()->BuildDispLuxels( pLightInfo, pFaceLight, ndxFace );
  807. }
  808. }
  809. //-----------------------------------------------------------------------------
  810. // Purpose: for each face, find the center of each luxel; for each texture
  811. // aligned grid point, back project onto the plane and get the world
  812. // xyz value of the sample point
  813. // NOTE: ndxFace = facenum
  814. //-----------------------------------------------------------------------------
  815. void CalcPoints( lightinfo_t *pLightInfo, facelight_t *pFaceLight, int ndxFace )
  816. {
  817. // debugging!
  818. if( g_bDumpPatches )
  819. {
  820. DumpFaces( pLightInfo, ndxFace );
  821. }
  822. // quick and dirty!
  823. if( do_fast )
  824. {
  825. if( !BuildSamplesAndLuxels_DoFast( pLightInfo, pFaceLight, ndxFace ) )
  826. {
  827. Msg( "Face %d: (Fast)Error Building Samples and Luxels\n", ndxFace );
  828. }
  829. return;
  830. }
  831. // build the samples
  832. if( !BuildSamples( pLightInfo, pFaceLight, ndxFace ) )
  833. {
  834. Msg( "Face %d: Error Building Samples\n", ndxFace );
  835. }
  836. // build the luxels
  837. if( !BuildLuxels( pLightInfo, pFaceLight, ndxFace ) )
  838. {
  839. Msg( "Face %d: Error Building Luxels\n", ndxFace );
  840. }
  841. }
  842. //==============================================================
  843. directlight_t *activelights;
  844. directlight_t *freelights;
  845. facelight_t facelight[MAX_MAP_FACES];
  846. int numdlights;
  847. /*
  848. ==================
  849. FindTargetEntity
  850. ==================
  851. */
  852. entity_t *FindTargetEntity (char *target)
  853. {
  854. int i;
  855. char *n;
  856. for (i=0 ; i<num_entities ; i++)
  857. {
  858. n = ValueForKey (&entities[i], "targetname");
  859. if (!strcmp (n, target))
  860. return &entities[i];
  861. }
  862. return NULL;
  863. }
  864. /*
  865. =============
  866. AllocDLight
  867. =============
  868. */
  869. int GetVisCache( int lastoffset, int cluster, byte *pvs );
  870. void SetDLightVis( directlight_t *dl, int cluster );
  871. void MergeDLightVis( directlight_t *dl, int cluster );
  872. directlight_t *AllocDLight( Vector& origin, bool bAddToList )
  873. {
  874. directlight_t *dl;
  875. dl = ( directlight_t* )calloc(1, sizeof(directlight_t));
  876. dl->index = numdlights++;
  877. VectorCopy( origin, dl->light.origin );
  878. dl->light.cluster = ClusterFromPoint(dl->light.origin);
  879. SetDLightVis( dl, dl->light.cluster );
  880. dl->facenum = -1;
  881. if ( bAddToList )
  882. {
  883. dl->next = activelights;
  884. activelights = dl;
  885. }
  886. return dl;
  887. }
  888. void AddDLightToActiveList( directlight_t *dl )
  889. {
  890. dl->next = activelights;
  891. activelights = dl;
  892. }
  893. void FreeDLights()
  894. {
  895. gSkyLight = NULL;
  896. gAmbient = NULL;
  897. directlight_t *pNext;
  898. for( directlight_t *pCur=activelights; pCur; pCur=pNext )
  899. {
  900. pNext = pCur->next;
  901. free( pCur );
  902. }
  903. activelights = 0;
  904. }
  905. void SetDLightVis( directlight_t *dl, int cluster )
  906. {
  907. if (dl->pvs == NULL)
  908. {
  909. dl->pvs = (byte *)calloc( 1, (dvis->numclusters / 8) + 1 );
  910. }
  911. GetVisCache( -1, cluster, dl->pvs );
  912. }
  913. void MergeDLightVis( directlight_t *dl, int cluster )
  914. {
  915. if (dl->pvs == NULL)
  916. {
  917. SetDLightVis( dl, cluster );
  918. }
  919. else
  920. {
  921. byte pvs[MAX_MAP_CLUSTERS/8];
  922. GetVisCache( -1, cluster, pvs );
  923. // merge both vis graphs
  924. for (int i = 0; i < (dvis->numclusters / 8) + 1; i++)
  925. {
  926. dl->pvs[i] |= pvs[i];
  927. }
  928. }
  929. }
  930. /*
  931. =============
  932. LightForKey
  933. =============
  934. */
  935. int LightForKey (entity_t *ent, char *key, Vector& intensity )
  936. {
  937. char *pLight;
  938. pLight = ValueForKey( ent, key );
  939. return LightForString( pLight, intensity );
  940. }
  941. int LightForString( char *pLight, Vector& intensity )
  942. {
  943. double r, g, b, scaler;
  944. int argCnt;
  945. VectorFill( intensity, 0 );
  946. // scanf into doubles, then assign, so it is vec_t size independent
  947. r = g = b = scaler = 0;
  948. double r_hdr,g_hdr,b_hdr,scaler_hdr;
  949. argCnt = sscanf ( pLight, "%lf %lf %lf %lf %lf %lf %lf %lf",
  950. &r, &g, &b, &scaler, &r_hdr,&g_hdr,&b_hdr,&scaler_hdr );
  951. if (argCnt==8) // 2 4-tuples
  952. {
  953. if (g_bHDR)
  954. {
  955. r=r_hdr;
  956. g=g_hdr;
  957. b=b_hdr;
  958. scaler=scaler_hdr;
  959. }
  960. argCnt=4;
  961. }
  962. // make sure light is legal
  963. if( r < 0.0f || g < 0.0f || b < 0.0f || scaler < 0.0f )
  964. {
  965. intensity.Init( 0.0f, 0.0f, 0.0f );
  966. return false;
  967. }
  968. intensity[0] = pow( r / 255.0, 2.2 ) * 255; // convert to linear
  969. switch( argCnt)
  970. {
  971. case 1:
  972. // The R,G,B values are all equal.
  973. intensity[1] = intensity[2] = intensity[0];
  974. break;
  975. case 3:
  976. case 4:
  977. // Save the other two G,B values.
  978. intensity[1] = pow( g / 255.0, 2.2 ) * 255;
  979. intensity[2] = pow( b / 255.0, 2.2 ) * 255;
  980. // Did we also get an "intensity" scaler value too?
  981. if ( argCnt == 4 )
  982. {
  983. // Scale the normalized 0-255 R,G,B values by the intensity scaler
  984. VectorScale( intensity, scaler / 255.0, intensity );
  985. }
  986. break;
  987. default:
  988. printf("unknown light specifier type - %s\n",pLight);
  989. return false;
  990. }
  991. // scale up source lights by scaling factor
  992. VectorScale( intensity, lightscale, intensity );
  993. return true;
  994. }
  995. //-----------------------------------------------------------------------------
  996. // Various parsing methods
  997. //-----------------------------------------------------------------------------
  998. static void ParseLightGeneric( entity_t *e, directlight_t *dl )
  999. {
  1000. entity_t *e2;
  1001. char *target;
  1002. Vector dest;
  1003. dl->light.style = (int)FloatForKey (e, "style");
  1004. dl->m_bSkyLightIsDirectionalLight = false;
  1005. if( (int)FloatForKeyWithDefault(e, "_castentityshadow", 1.0f ) != 0 )
  1006. {
  1007. dl->light.flags |= DWL_FLAGS_CASTENTITYSHADOWS;
  1008. }
  1009. else
  1010. {
  1011. dl->light.flags &= ~DWL_FLAGS_CASTENTITYSHADOWS;
  1012. }
  1013. Vector shadowOffset( 0.0f, 0.0f, 0.0f );
  1014. GetVectorForKey (e, "_shadoworiginoffset", shadowOffset );
  1015. dl->light.shadow_cast_offset = shadowOffset;
  1016. // get intensity
  1017. if( g_bHDR && LightForKey( e, "_lightHDR", dl->light.intensity ) )
  1018. {
  1019. }
  1020. else
  1021. {
  1022. LightForKey( e, "_light", dl->light.intensity );
  1023. }
  1024. // check angle, targets
  1025. target = ValueForKey (e, "target");
  1026. if (target[0])
  1027. { // point towards target
  1028. e2 = FindTargetEntity (target);
  1029. if (!e2)
  1030. Warning("WARNING: light at (%i %i %i) has missing target\n",
  1031. (int)dl->light.origin[0], (int)dl->light.origin[1], (int)dl->light.origin[2]);
  1032. else
  1033. {
  1034. GetVectorForKey (e2, "origin", dest);
  1035. VectorSubtract (dest, dl->light.origin, dl->light.normal);
  1036. VectorNormalize (dl->light.normal);
  1037. }
  1038. }
  1039. else
  1040. {
  1041. // point down angle
  1042. Vector angles;
  1043. GetVectorForKey( e, "angles", angles );
  1044. float pitch = FloatForKey (e, "pitch");
  1045. float angle = FloatForKey (e, "angle");
  1046. SetupLightNormalFromProps( QAngle( angles.x, angles.y, angles.z ), angle, pitch, dl->light.normal );
  1047. }
  1048. if ( g_bHDR )
  1049. VectorScale( dl->light.intensity,
  1050. FloatForKeyWithDefault( e, "_lightscaleHDR", 1.0 ),
  1051. dl->light.intensity );
  1052. }
  1053. static void SetLightFalloffParams( entity_t * e, directlight_t * dl )
  1054. {
  1055. dl->m_flStartFadeDistance = 0;
  1056. dl->m_flEndFadeDistance = - 1;
  1057. dl->m_flCapDist = 1.0e22;
  1058. if ( g_bFiniteFalloffModel )
  1059. {
  1060. float d0 = FloatForKey( e, "_zero_percent_distance" );
  1061. dl->light.constant_attn = 1.0;
  1062. dl->light.linear_attn = 0; //-2.0 * ( 1.0 / d0 );
  1063. dl->light.quadratic_attn = -1.0 / ( d0 * d0 );
  1064. // for(float d=0;d<200;d+=20)
  1065. // printf("at %f, %f\n",d,1.0+d*d*dl->light.quadratic_attn );
  1066. }
  1067. else
  1068. {
  1069. float d50=FloatForKey( e, "_fifty_percent_distance" );
  1070. if ( d50 )
  1071. {
  1072. float d0 = FloatForKey( e, "_zero_percent_distance" );
  1073. if ( d0 < d50 )
  1074. {
  1075. Warning( "light has _fifty_percent_distance of %f but _zero_percent_distance of %f\n", d50, d0);
  1076. d0 = 2.0 * d50;
  1077. }
  1078. float a = 0, b = 1, c = 0;
  1079. if ( ! SolveInverseQuadraticMonotonic( 0, 1.0, d50, 2.0, d0, 256.0, a, b, c ))
  1080. {
  1081. Warning( "can't solve quadratic for light %f %f\n", d50, d0 );
  1082. }
  1083. // it it possible that the parameters couldn't be used because of enforing monoticity. If so, rescale so at
  1084. // least the 50 percent value is right
  1085. // printf("50 percent=%f 0 percent=%f\n",d50,d0);
  1086. // printf("a=%f b=%f c=%f\n",a,b,c);
  1087. float v50 = c + d50 * ( b + d50 * a );
  1088. float scale = 2.0 / v50;
  1089. a *= scale;
  1090. b *= scale;
  1091. c *= scale;
  1092. // printf("scaled=%f a=%f b=%f c=%f\n",scale,a,b,c);
  1093. // for(float d=0;d<200;d+=20)
  1094. // printf("at %f, %f\n",d,1.0/(c+d*(b+d*a)));
  1095. dl->light.quadratic_attn = a;
  1096. dl->light.linear_attn = b;
  1097. dl->light.constant_attn = c;
  1098. if ( IntForKey(e, "_hardfalloff" ) )
  1099. {
  1100. dl->m_flEndFadeDistance = d0;
  1101. dl->m_flStartFadeDistance = 0.75 * d0 + 0.25 * d50; // start fading 3/4 way between 50 and 0. could allow adjust
  1102. }
  1103. else
  1104. {
  1105. // now, we will find the point at which the 1/x term reaches its maximum value, and
  1106. // prevent the light from going past there. If a user specifes an extreme falloff, the
  1107. // quadratic will start making the light brighter at some distance. We handle this by
  1108. // fading it from the minimum brightess point down to zero at 10x the minimum distance
  1109. if ( fabs( a ) > 0. )
  1110. {
  1111. float flMax = b / ( - 2.0 * a ); // where f' = 0
  1112. if ( flMax > 0.0 )
  1113. {
  1114. dl->m_flCapDist = flMax;
  1115. dl->m_flStartFadeDistance = flMax;
  1116. dl->m_flEndFadeDistance = 10.0 * flMax;
  1117. }
  1118. }
  1119. }
  1120. }
  1121. else
  1122. {
  1123. dl->light.constant_attn = FloatForKey (e, "_constant_attn" );
  1124. dl->light.linear_attn = FloatForKey (e, "_linear_attn" );
  1125. dl->light.quadratic_attn = FloatForKey (e, "_quadratic_attn" );
  1126. dl->light.radius = FloatForKey (e, "_distance");
  1127. // clamp values to >= 0
  1128. if ( dl->light.constant_attn < EQUAL_EPSILON )
  1129. dl->light.constant_attn = 0;
  1130. if ( dl->light.linear_attn < EQUAL_EPSILON )
  1131. dl->light.linear_attn = 0;
  1132. if ( dl->light.quadratic_attn < EQUAL_EPSILON )
  1133. dl->light.quadratic_attn = 0;
  1134. if ( dl->light.constant_attn < EQUAL_EPSILON && dl->light.linear_attn < EQUAL_EPSILON && dl->light.quadratic_attn < EQUAL_EPSILON )
  1135. dl->light.constant_attn = 1;
  1136. // scale intensity for unit 100 distance
  1137. float ratio = ( dl->light.constant_attn + 100 * dl->light.linear_attn + 100 * 100 * dl->light.quadratic_attn );
  1138. if ( ratio > 0 )
  1139. {
  1140. VectorScale( dl->light.intensity, ratio, dl->light.intensity );
  1141. }
  1142. }
  1143. }
  1144. }
  1145. static void ParseLightSpot( entity_t* e, directlight_t* dl )
  1146. {
  1147. Vector dest;
  1148. GetVectorForKey (e, "origin", dest );
  1149. dl = AllocDLight( dest, true );
  1150. ParseLightGeneric( e, dl );
  1151. dl->light.type = emit_spotlight;
  1152. dl->light.stopdot = FloatForKey (e, "_inner_cone");
  1153. if (!dl->light.stopdot)
  1154. dl->light.stopdot = 10;
  1155. dl->light.stopdot2 = FloatForKey (e, "_cone");
  1156. if (!dl->light.stopdot2)
  1157. dl->light.stopdot2 = dl->light.stopdot;
  1158. if (dl->light.stopdot2 < dl->light.stopdot)
  1159. dl->light.stopdot2 = dl->light.stopdot;
  1160. // This is a point light if stop dots are 180...
  1161. if ((dl->light.stopdot == 180) && (dl->light.stopdot2 == 180))
  1162. {
  1163. dl->light.stopdot = dl->light.stopdot2 = 0;
  1164. dl->light.type = emit_point;
  1165. dl->light.exponent = 0;
  1166. }
  1167. else
  1168. {
  1169. // Clamp to 90, that's all DX8 can handle!
  1170. if (dl->light.stopdot > 90)
  1171. {
  1172. Warning("WARNING: light_spot at (%i %i %i) has inner angle larger than 90 degrees! Clamping to 90...\n",
  1173. (int)dl->light.origin[0], (int)dl->light.origin[1], (int)dl->light.origin[2]);
  1174. dl->light.stopdot = 90;
  1175. }
  1176. if (dl->light.stopdot2 > 90)
  1177. {
  1178. Warning("WARNING: light_spot at (%i %i %i) has outer angle larger than 90 degrees! Clamping to 90...\n",
  1179. (int)dl->light.origin[0], (int)dl->light.origin[1], (int)dl->light.origin[2]);
  1180. dl->light.stopdot2 = 90;
  1181. }
  1182. dl->light.stopdot2 = (float)cos(dl->light.stopdot2/180*M_PI);
  1183. dl->light.stopdot = (float)cos(dl->light.stopdot/180*M_PI);
  1184. dl->light.exponent = FloatForKey (e, "_exponent");
  1185. }
  1186. SetLightFalloffParams(e,dl);
  1187. }
  1188. // NOTE: This is just a heuristic. It traces a finite number of rays to find sky
  1189. // NOTE: Full vis is necessary to make this 100% correct.
  1190. bool CanLeafTraceToSky( int iLeaf )
  1191. {
  1192. // UNDONE: Really want a point inside the leaf here. Center is a guess, may not be in the leaf
  1193. // UNDONE: Clip this to each plane bounding the leaf to guarantee
  1194. Vector center = vec3_origin;
  1195. for ( int i = 0; i < 3; i++ )
  1196. {
  1197. center[i] = ( (float)(dleafs[iLeaf].mins[i] + dleafs[iLeaf].maxs[i]) ) * 0.5f;
  1198. }
  1199. FourVectors center4, delta;
  1200. fltx4 fractionVisible;
  1201. for ( int j = 0; j < NUMVERTEXNORMALS; j+=4 )
  1202. {
  1203. // search back to see if we can hit a sky brush
  1204. delta.LoadAndSwizzle( g_anorms[j], g_anorms[min( j+1, NUMVERTEXNORMALS-1 )],
  1205. g_anorms[min( j+2, NUMVERTEXNORMALS-1 )], g_anorms[min( j+3, NUMVERTEXNORMALS-1 )] );
  1206. delta *= -MAX_TRACE_LENGTH;
  1207. delta += center4;
  1208. // return true if any hits sky
  1209. TestLine_DoesHitSky ( center4, delta, &fractionVisible );
  1210. if ( TestSignSIMD ( CmpGtSIMD ( fractionVisible, Four_Zeros ) ) )
  1211. return true;
  1212. }
  1213. return false;
  1214. }
  1215. void BuildVisForLightEnvironment( int nNumLights, directlight_t** pLights )
  1216. {
  1217. // FIXME: The work in this function is executed redundantly for multiple emit_skylight lights.
  1218. // Create the vis.
  1219. for ( int iLeaf = 0; iLeaf < numleafs; ++iLeaf )
  1220. {
  1221. dleafs[iLeaf].flags &= ~( LEAF_FLAGS_SKY | LEAF_FLAGS_SKY2D );
  1222. unsigned int iFirstFace = dleafs[iLeaf].firstleafface;
  1223. for ( int iLeafFace = 0; iLeafFace < dleafs[iLeaf].numleaffaces; ++iLeafFace )
  1224. {
  1225. unsigned int iFace = dleaffaces[iFirstFace+iLeafFace];
  1226. texinfo_t &tex = texinfo[g_pFaces[iFace].texinfo];
  1227. if ( tex.flags & SURF_SKY )
  1228. {
  1229. if ( tex.flags & SURF_SKY2D )
  1230. {
  1231. dleafs[iLeaf].flags |= LEAF_FLAGS_SKY2D;
  1232. }
  1233. else
  1234. {
  1235. dleafs[iLeaf].flags |= LEAF_FLAGS_SKY;
  1236. }
  1237. for ( int iLight = 0; iLight < nNumLights; ++iLight )
  1238. {
  1239. MergeDLightVis( pLights[iLight], dleafs[iLeaf].cluster );
  1240. }
  1241. break;
  1242. }
  1243. }
  1244. }
  1245. // Second pass to set flags on leaves that don't contain sky, but touch leaves that
  1246. // contain sky.
  1247. byte pvs[MAX_MAP_CLUSTERS / 8];
  1248. int nLeafBytes = (numleafs >> 3) + 1;
  1249. unsigned char *pLeafBits = (unsigned char *)stackalloc( nLeafBytes * sizeof(unsigned char) );
  1250. unsigned char *pLeaf2DBits = (unsigned char *)stackalloc( nLeafBytes * sizeof(unsigned char) );
  1251. memset( pLeafBits, 0, nLeafBytes );
  1252. memset( pLeaf2DBits, 0, nLeafBytes );
  1253. for ( int iLeaf = 0; iLeaf < numleafs; ++iLeaf )
  1254. {
  1255. // If this leaf has light (3d skybox) in it, then don't bother
  1256. if ( dleafs[iLeaf].flags & LEAF_FLAGS_SKY )
  1257. continue;
  1258. // Don't bother with this leaf if it's solid
  1259. if ( dleafs[iLeaf].contents & CONTENTS_SOLID )
  1260. continue;
  1261. // See what other leaves are visible from this leaf
  1262. GetVisCache( -1, dleafs[iLeaf].cluster, pvs );
  1263. // Now check out all other leaves
  1264. int nByte = iLeaf >> 3;
  1265. int nBit = 1 << ( iLeaf & 0x7 );
  1266. for ( int iLeaf2 = 0; iLeaf2 < numleafs; ++iLeaf2 )
  1267. {
  1268. if ( iLeaf2 == iLeaf )
  1269. continue;
  1270. if ( !(dleafs[iLeaf2].flags & ( LEAF_FLAGS_SKY | LEAF_FLAGS_SKY2D ) ) )
  1271. continue;
  1272. // Can this leaf see into the leaf with the sky in it?
  1273. if ( !PVSCheck( pvs, dleafs[iLeaf2].cluster ) )
  1274. continue;
  1275. if ( dleafs[iLeaf2].flags & LEAF_FLAGS_SKY2D )
  1276. {
  1277. pLeaf2DBits[ nByte ] |= nBit;
  1278. }
  1279. if ( dleafs[iLeaf2].flags & LEAF_FLAGS_SKY )
  1280. {
  1281. pLeafBits[ nByte ] |= nBit;
  1282. // As soon as we know this leaf needs to draw the 3d skybox, we're done
  1283. break;
  1284. }
  1285. }
  1286. }
  1287. // Must set the bits in a separate pass so as to not flood-fill LEAF_FLAGS_SKY everywhere
  1288. // pLeafbits is a bit array of all leaves that need to be marked as seeing sky
  1289. for ( int iLeaf = 0; iLeaf < numleafs; ++iLeaf )
  1290. {
  1291. // If this leaf has light (3d skybox) in it, then don't bother
  1292. if ( dleafs[iLeaf].flags & LEAF_FLAGS_SKY )
  1293. continue;
  1294. // Don't bother with this leaf if it's solid
  1295. if ( dleafs[iLeaf].contents & CONTENTS_SOLID )
  1296. continue;
  1297. // Check to see if this is a 2D skybox leaf
  1298. if ( pLeaf2DBits[ iLeaf >> 3 ] & (1 << ( iLeaf & 0x7 )) )
  1299. {
  1300. dleafs[iLeaf].flags |= LEAF_FLAGS_SKY2D;
  1301. }
  1302. // If this is a 3D skybox leaf, then we don't care if it was previously a 2D skybox leaf
  1303. if ( pLeafBits[ iLeaf >> 3 ] & (1 << ( iLeaf & 0x7 )) )
  1304. {
  1305. dleafs[iLeaf].flags |= LEAF_FLAGS_SKY;
  1306. dleafs[iLeaf].flags &= ~LEAF_FLAGS_SKY2D;
  1307. }
  1308. else
  1309. {
  1310. // if radial vis was used on this leaf some of the portals leading
  1311. // to sky may have been culled. Try tracing to find sky.
  1312. if ( dleafs[iLeaf].flags & LEAF_FLAGS_RADIAL )
  1313. {
  1314. if ( CanLeafTraceToSky(iLeaf) )
  1315. {
  1316. // FIXME: Should make a version that checks if we hit 2D skyboxes.. oh well.
  1317. dleafs[iLeaf].flags |= LEAF_FLAGS_SKY;
  1318. }
  1319. }
  1320. }
  1321. }
  1322. }
  1323. static char *ValueForKeyWithDefault (entity_t *ent, char *key, char *default_value = NULL)
  1324. {
  1325. epair_t *ep;
  1326. for (ep=ent->epairs ; ep ; ep=ep->next)
  1327. if (!strcmp (ep->key, key) )
  1328. return ep->value;
  1329. return default_value;
  1330. }
  1331. static void ParseLightEnvironment( entity_t* e, directlight_t* dl )
  1332. {
  1333. Vector dest;
  1334. GetVectorForKey (e, "origin", dest );
  1335. dl = AllocDLight( dest, false );
  1336. ParseLightGeneric( e, dl );
  1337. if ( !gSkyLight )
  1338. {
  1339. char *angle_str=ValueForKeyWithDefault( e, "SunSpreadAngle" );
  1340. if (angle_str)
  1341. {
  1342. g_SunAngularExtent=atof(angle_str);
  1343. g_SunAngularExtent=sin((M_PI/180.0)*g_SunAngularExtent);
  1344. dl->m_flSkyLightSunAngularExtent = g_SunAngularExtent;
  1345. printf("sun extent from map=%f\n",g_SunAngularExtent);
  1346. }
  1347. // Sky light.
  1348. gSkyLight = dl;
  1349. dl->light.type = emit_skylight;
  1350. // Sky ambient light.
  1351. gAmbient = AllocDLight( dl->light.origin, false );
  1352. gAmbient->light.type = emit_skyambient;
  1353. if( g_bHDR && LightForKey( e, "_ambientHDR", gAmbient->light.intensity ) )
  1354. {
  1355. // we have a valid HDR ambient light value
  1356. }
  1357. else if ( !LightForKey( e, "_ambient", gAmbient->light.intensity ) )
  1358. {
  1359. VectorScale( dl->light.intensity, 0.5, gAmbient->light.intensity );
  1360. }
  1361. if ( g_bHDR )
  1362. {
  1363. VectorScale( gAmbient->light.intensity,
  1364. FloatForKeyWithDefault( e, "_AmbientScaleHDR", 1.0 ),
  1365. gAmbient->light.intensity );
  1366. }
  1367. // skylight and ambient light never cast entity shadows
  1368. gSkyLight->light.flags &= ~DWL_FLAGS_CASTENTITYSHADOWS;
  1369. gAmbient->light.flags &= ~DWL_FLAGS_CASTENTITYSHADOWS;
  1370. directlight_t* lights[] = { gSkyLight, gAmbient };
  1371. BuildVisForLightEnvironment( 2, lights );
  1372. // Add sky and sky ambient lights to the list.
  1373. AddDLightToActiveList( gSkyLight );
  1374. AddDLightToActiveList( gAmbient );
  1375. }
  1376. }
  1377. static void ParseLightDirectional( entity_t* e, directlight_t* dl )
  1378. {
  1379. Vector dest;
  1380. GetVectorForKey (e, "origin", dest );
  1381. dl = AllocDLight( dest, true );
  1382. ParseLightGeneric( e, dl );
  1383. char *angle_str=ValueForKeyWithDefault( e, "SunSpreadAngle" );
  1384. if (angle_str)
  1385. {
  1386. dl->m_flSkyLightSunAngularExtent = atof(angle_str);
  1387. dl->m_flSkyLightSunAngularExtent = sin((M_PI/180.0)*dl->m_flSkyLightSunAngularExtent);
  1388. }
  1389. dl->light.type = emit_skylight;
  1390. // For the engine, emit_skylight is the type we want.
  1391. // Set an additional flag identifying this as "not the global skylight" for vrad. This will cause it to use the angular extent associated with this light
  1392. // instead of the global one.
  1393. dl->m_bSkyLightIsDirectionalLight = true;
  1394. // directional lights never cast entity shadows
  1395. dl->light.flags &= ~DWL_FLAGS_CASTENTITYSHADOWS;
  1396. BuildVisForLightEnvironment( 1, &dl );
  1397. }
  1398. static void ParseLightPoint( entity_t* e, directlight_t* dl )
  1399. {
  1400. Vector dest;
  1401. GetVectorForKey (e, "origin", dest );
  1402. dl = AllocDLight( dest, true );
  1403. ParseLightGeneric( e, dl );
  1404. dl->light.type = emit_point;
  1405. SetLightFalloffParams(e,dl);
  1406. }
  1407. /*
  1408. =============
  1409. CreateDirectLights
  1410. =============
  1411. */
  1412. #define DIRECT_SCALE (100.0*100.0)
  1413. void CreateDirectLights (void)
  1414. {
  1415. unsigned i;
  1416. CPatch *p = NULL;
  1417. directlight_t *dl = NULL;
  1418. entity_t *e = NULL;
  1419. char *name;
  1420. Vector dest;
  1421. numdlights = 0;
  1422. FreeDLights();
  1423. //
  1424. // surfaces
  1425. //
  1426. unsigned int uiPatchCount = g_Patches.Count();
  1427. for (i=0; i< uiPatchCount; i++)
  1428. {
  1429. p = &g_Patches.Element( i );
  1430. // skip parent patches
  1431. if (p->child1 != g_Patches.InvalidIndex() )
  1432. continue;
  1433. if (p->basearea < 1e-6)
  1434. continue;
  1435. if( VectorAvg( p->baselight ) >= dlight_threshold )
  1436. {
  1437. dl = AllocDLight( p->origin, true );
  1438. dl->light.type = emit_surface;
  1439. dl->light.flags &= ~DWL_FLAGS_CASTENTITYSHADOWS;
  1440. VectorCopy (p->normal, dl->light.normal);
  1441. Assert( VectorLength( p->normal ) > 1.0e-20 );
  1442. // scale intensity by number of texture instances
  1443. VectorScale( p->baselight, lightscale * p->area * p->scale[0] * p->scale[1] / p->basearea, dl->light.intensity );
  1444. // scale to a range that results in actual light
  1445. VectorScale( dl->light.intensity, DIRECT_SCALE, dl->light.intensity );
  1446. }
  1447. }
  1448. //
  1449. // entities
  1450. //
  1451. for (i=0 ; i<(unsigned)num_entities ; i++)
  1452. {
  1453. e = &entities[i];
  1454. name = ValueForKey (e, "classname");
  1455. if (strncmp (name, "light", 5))
  1456. continue;
  1457. // Light_dynamic is actually a real entity; not to be included here...
  1458. if (!strcmp (name, "light_dynamic"))
  1459. continue;
  1460. if (!strcmp (name, "light_spot"))
  1461. {
  1462. ParseLightSpot( e, dl );
  1463. }
  1464. else if (!strcmp(name, "light_environment"))
  1465. {
  1466. ParseLightEnvironment( e, dl );
  1467. }
  1468. else if (!strcmp(name, "light_directional"))
  1469. {
  1470. ParseLightDirectional( e, dl );
  1471. }
  1472. else if (!strcmp(name, "light"))
  1473. {
  1474. ParseLightPoint( e, dl );
  1475. }
  1476. else
  1477. {
  1478. qprintf( "unsupported light entity: \"%s\"\n", name );
  1479. }
  1480. }
  1481. qprintf ("%i direct lights\n", numdlights);
  1482. // exit(1);
  1483. }
  1484. /*
  1485. =============
  1486. ExportDirectLightsToWorldLights
  1487. =============
  1488. */
  1489. void ExportDirectLightsToWorldLights()
  1490. {
  1491. directlight_t *dl;
  1492. // In case the level has already been VRADed.
  1493. *pNumworldlights = 0;
  1494. for (dl = activelights; dl != NULL; dl = dl->next )
  1495. {
  1496. dworldlight_t *wl = &dworldlights[(*pNumworldlights)++];
  1497. if (*pNumworldlights > MAX_MAP_WORLDLIGHTS)
  1498. {
  1499. Error("too many lights %d / %d\n", *pNumworldlights, MAX_MAP_WORLDLIGHTS );
  1500. }
  1501. wl->cluster = dl->light.cluster;
  1502. wl->type = dl->light.type;
  1503. wl->style = dl->light.style;
  1504. VectorCopy( dl->light.origin, wl->origin );
  1505. // FIXME: why does vrad want 0 to 255 and not 0 to 1??
  1506. VectorScale( dl->light.intensity, (1.0 / 255.0), wl->intensity );
  1507. VectorCopy( dl->light.normal, wl->normal );
  1508. VectorCopy( dl->light.shadow_cast_offset, wl->shadow_cast_offset );
  1509. wl->stopdot = dl->light.stopdot;
  1510. wl->stopdot2 = dl->light.stopdot2;
  1511. wl->exponent = dl->light.exponent;
  1512. wl->radius = dl->light.radius;
  1513. wl->constant_attn = dl->light.constant_attn;
  1514. wl->linear_attn = dl->light.linear_attn;
  1515. wl->quadratic_attn = dl->light.quadratic_attn;
  1516. wl->flags = dl->light.flags;
  1517. }
  1518. }
  1519. /*
  1520. =============
  1521. GatherSampleLight
  1522. =============
  1523. */
  1524. #define NORMALFORMFACTOR 40.156979 // accumuated dot products for hemisphere
  1525. #define CONSTANT_DOT (.7/2)
  1526. #define NSAMPLES_SUN_AREA_LIGHT 300 // number of samples to take for an
  1527. // non-point sun light
  1528. // Helper function - gathers light from sun (emit_skylight)
  1529. void GatherSampleSkyLightSSE( SSE_sampleLightOutput_t &out, directlight_t *dl, int facenum,
  1530. FourVectors const& pos, FourVectors *pNormals, int normalCount, int iThread,
  1531. int nLFlags, int static_prop_index_to_ignore,
  1532. float flEpsilon )
  1533. {
  1534. bool bIgnoreNormals = ( nLFlags & GATHERLFLAGS_IGNORE_NORMALS ) != 0;
  1535. bool force_fast = ( nLFlags & GATHERLFLAGS_FORCE_FAST ) != 0;
  1536. fltx4 dot;
  1537. float fSunAngularExtent = g_SunAngularExtent;
  1538. if ( dl->m_bSkyLightIsDirectionalLight )
  1539. {
  1540. fSunAngularExtent = dl->m_flSkyLightSunAngularExtent;
  1541. }
  1542. if ( bIgnoreNormals )
  1543. dot = ReplicateX4( CONSTANT_DOT );
  1544. else
  1545. dot = NegSIMD( pNormals[0] * dl->light.normal );
  1546. dot = MaxSIMD( dot, Four_Zeros );
  1547. dot = SoftenCosineTerm( dot );
  1548. int zeroMask = TestSignSIMD ( CmpEqSIMD( dot, Four_Zeros ) );
  1549. if (zeroMask == 0xF)
  1550. return;
  1551. int nsamples = 1;
  1552. if ( fSunAngularExtent > 0.0f )
  1553. {
  1554. nsamples = NSAMPLES_SUN_AREA_LIGHT;
  1555. if ( do_fast || force_fast )
  1556. nsamples /= 4;
  1557. }
  1558. fltx4 totalFractionVisible = Four_Zeros;
  1559. fltx4 fractionVisible = Four_Zeros;
  1560. DirectionalSampler_t sampler;
  1561. for ( int d = 0; d < nsamples; d++ )
  1562. {
  1563. // determine visibility of skylight
  1564. // serach back to see if we can hit a sky brush
  1565. Vector delta;
  1566. VectorScale( dl->light.normal, -MAX_TRACE_LENGTH, delta );
  1567. if ( d )
  1568. {
  1569. // jitter light source location
  1570. Vector ofs = sampler.NextValue();
  1571. ofs *= MAX_TRACE_LENGTH * fSunAngularExtent;
  1572. delta += ofs;
  1573. }
  1574. FourVectors delta4;
  1575. delta4.DuplicateVector ( delta );
  1576. delta4 += pos;
  1577. TestLine_DoesHitSky ( pos, delta4, &fractionVisible, true, static_prop_index_to_ignore );
  1578. totalFractionVisible = AddSIMD ( totalFractionVisible, fractionVisible );
  1579. }
  1580. fltx4 seeAmount = MulSIMD ( totalFractionVisible, ReplicateX4 ( 1.0f / nsamples ) );
  1581. out.m_flDot[0] = MulSIMD ( dot, seeAmount );
  1582. out.m_flFalloff = Four_Ones;
  1583. out.m_flSunAmount[0] = MulSIMD( out.m_flDot[0], out.m_flFalloff );
  1584. for ( int i = 1; i < normalCount; i++ )
  1585. {
  1586. if ( bIgnoreNormals )
  1587. {
  1588. out.m_flDot[i] = ReplicateX4( CONSTANT_DOT );
  1589. out.m_flSunAmount[i] = Four_Zeros;
  1590. }
  1591. else
  1592. {
  1593. out.m_flDot[i] = NegSIMD( pNormals[i] * dl->light.normal );
  1594. out.m_flDot[i] = MaxSIMD( out.m_flDot[i], Four_Zeros );
  1595. out.m_flDot[i] = SoftenCosineTerm( out.m_flDot[i] );
  1596. out.m_flDot[i] = MulSIMD( out.m_flDot[i], seeAmount );
  1597. out.m_flSunAmount[i] = MulSIMD( out.m_flDot[i], out.m_flFalloff );
  1598. }
  1599. }
  1600. }
  1601. // Helper function - gathers light from ambient sky light
  1602. void GatherSampleAmbientSkySSE( SSE_sampleLightOutput_t &out, directlight_t *dl, int facenum,
  1603. FourVectors const& pos, FourVectors *pNormals, int normalCount, int iThread,
  1604. int nLFlags, int static_prop_index_to_ignore,
  1605. float flEpsilon )
  1606. {
  1607. bool bIgnoreNormals = ( nLFlags & GATHERLFLAGS_IGNORE_NORMALS ) != 0;
  1608. bool force_fast = ( nLFlags & GATHERLFLAGS_FORCE_FAST ) != 0;
  1609. fltx4 sumdot = Four_Zeros;
  1610. fltx4 ambient_intensity[NUM_BUMP_VECTS+1];
  1611. fltx4 possibleHitCount[NUM_BUMP_VECTS+1];
  1612. fltx4 dots[NUM_BUMP_VECTS+1];
  1613. for ( int i = 0; i < normalCount; i++ )
  1614. {
  1615. ambient_intensity[i] = Four_Zeros;
  1616. possibleHitCount[i] = Four_Zeros;
  1617. }
  1618. DirectionalSampler_t sampler;
  1619. int nsky_samples = NUMVERTEXNORMALS;
  1620. if (do_fast || force_fast )
  1621. nsky_samples /= 4;
  1622. else
  1623. nsky_samples *= g_flSkySampleScale;
  1624. for (int j = 0; j < nsky_samples; j++)
  1625. {
  1626. FourVectors anorm;
  1627. anorm.DuplicateVector( sampler.NextValue() );
  1628. if ( bIgnoreNormals )
  1629. dots[0] = ReplicateX4( CONSTANT_DOT );
  1630. else
  1631. dots[0] = NegSIMD( pNormals[0] * anorm );
  1632. dots[0] = SoftenCosineTerm( dots[0] );
  1633. fltx4 validity = CmpGtSIMD( dots[0], ReplicateX4( EQUAL_EPSILON ) );
  1634. // No possibility of anybody getting lit
  1635. if ( !TestSignSIMD( validity ) )
  1636. continue;
  1637. dots[0] = AndSIMD( validity, dots[0] );
  1638. sumdot = AddSIMD( dots[0], sumdot );
  1639. possibleHitCount[0] = AddSIMD( AndSIMD( validity, Four_Ones ), possibleHitCount[0] );
  1640. for ( int i = 1; i < normalCount; i++ )
  1641. {
  1642. if ( bIgnoreNormals )
  1643. dots[i] = ReplicateX4( CONSTANT_DOT );
  1644. else
  1645. dots[i] = NegSIMD( pNormals[i] * anorm );
  1646. dots[i] = SoftenCosineTerm( dots[i] );
  1647. fltx4 validity2 = CmpGtSIMD( dots[i], ReplicateX4 ( EQUAL_EPSILON ) );
  1648. dots[i] = AndSIMD( validity2, dots[i] );
  1649. possibleHitCount[i] = AddSIMD( AndSIMD( AndSIMD( validity, validity2 ), Four_Ones ), possibleHitCount[i] );
  1650. }
  1651. // search back to see if we can hit a sky brush
  1652. FourVectors delta = anorm;
  1653. delta *= -MAX_TRACE_LENGTH;
  1654. delta += pos;
  1655. FourVectors surfacePos = pos;
  1656. FourVectors offset = anorm;
  1657. offset *= -flEpsilon;
  1658. surfacePos -= offset;
  1659. fltx4 fractionVisible = Four_Ones;
  1660. TestLine_DoesHitSky( surfacePos, delta, &fractionVisible, true, static_prop_index_to_ignore );
  1661. for ( int i = 0; i < normalCount; i++ )
  1662. {
  1663. fltx4 addedAmount = MulSIMD( fractionVisible, dots[i] );
  1664. ambient_intensity[i] = AddSIMD( ambient_intensity[i], addedAmount );
  1665. }
  1666. }
  1667. out.m_flFalloff = Four_Ones;
  1668. for ( int i = 0; i < normalCount; i++ )
  1669. {
  1670. // now scale out the missing parts of the hemisphere of this bump basis vector
  1671. fltx4 factor = ReciprocalSIMD( possibleHitCount[0] );
  1672. factor = MulSIMD( factor, possibleHitCount[i] );
  1673. out.m_flDot[i] = MulSIMD( factor, sumdot );
  1674. out.m_flDot[i] = ReciprocalSIMD( out.m_flDot[i] );
  1675. out.m_flDot[i] = MulSIMD( ambient_intensity[i], out.m_flDot[i] );
  1676. out.m_flSunAmount[i] = Four_Zeros;
  1677. }
  1678. }
  1679. // Helper function - gathers light from area lights, spot lights, and point lights
  1680. void GatherSampleStandardLightSSE( SSE_sampleLightOutput_t &out, directlight_t *dl, int facenum,
  1681. FourVectors const& pos, FourVectors *pNormals, int normalCount, int iThread,
  1682. int nLFlags, int static_prop_index_to_ignore,
  1683. float flEpsilon )
  1684. {
  1685. bool bIgnoreNormals = ( nLFlags & GATHERLFLAGS_IGNORE_NORMALS ) != 0;
  1686. FourVectors src;
  1687. src.DuplicateVector( vec3_origin );
  1688. if (dl->facenum == -1)
  1689. {
  1690. src.DuplicateVector( dl->light.origin );
  1691. }
  1692. // Find light vector
  1693. FourVectors delta;
  1694. delta = src;
  1695. delta -= pos;
  1696. fltx4 dist2 = delta.length2();
  1697. fltx4 rpcDist = ReciprocalSqrtSIMD( dist2 );
  1698. delta *= rpcDist;
  1699. fltx4 dist = SqrtEstSIMD( dist2 );//delta.VectorNormalize();
  1700. // Compute dot
  1701. fltx4 dot = ReplicateX4( (float) CONSTANT_DOT );
  1702. if ( !bIgnoreNormals )
  1703. dot = delta * pNormals[0];
  1704. dot = MaxSIMD( Four_Zeros, dot );
  1705. dot = SoftenCosineTerm( dot );
  1706. // Affix dot to zero if past fade distz
  1707. bool bHasHardFalloff = ( dl->m_flEndFadeDistance > dl->m_flStartFadeDistance );
  1708. if ( bHasHardFalloff )
  1709. {
  1710. fltx4 notPastFadeDist = CmpLeSIMD ( dist, ReplicateX4 ( dl->m_flEndFadeDistance ) );
  1711. dot = AndSIMD( dot, notPastFadeDist ); // dot = 0 if past fade distance
  1712. if ( !TestSignSIMD ( notPastFadeDist ) )
  1713. return;
  1714. }
  1715. dist = MaxSIMD( dist, Four_Ones );
  1716. fltx4 falloffEvalDist = MinSIMD( dist, ReplicateX4( dl->m_flCapDist ) );
  1717. fltx4 constant, linear, quadratic;
  1718. fltx4 dot2, inCone, inFringe, mult;
  1719. FourVectors offset;
  1720. switch (dl->light.type)
  1721. {
  1722. case emit_point:
  1723. constant = ReplicateX4( dl->light.constant_attn );
  1724. linear = ReplicateX4( dl->light.linear_attn );
  1725. quadratic = ReplicateX4( dl->light.quadratic_attn );
  1726. out.m_flFalloff = MulSIMD( falloffEvalDist, falloffEvalDist );
  1727. out.m_flFalloff = MulSIMD( out.m_flFalloff, quadratic );
  1728. out.m_flFalloff = AddSIMD( out.m_flFalloff, MulSIMD( linear, falloffEvalDist ) );
  1729. out.m_flFalloff = AddSIMD( out.m_flFalloff, constant );
  1730. if ( g_bFiniteFalloffModel )
  1731. {
  1732. out.m_flFalloff = MaxSIMD( Four_Zeros, out.m_flFalloff );
  1733. }
  1734. else
  1735. {
  1736. out.m_flFalloff = ReciprocalSIMD( out.m_flFalloff );
  1737. }
  1738. break;
  1739. case emit_surface:
  1740. dot2 = delta * dl->light.normal;
  1741. dot2 = NegSIMD( dot2 );
  1742. // Light behind surface yields zero dot
  1743. dot2 = MaxSIMD( Four_Zeros, dot2 );
  1744. if ( TestSignSIMD( CmpEqSIMD( Four_Zeros, dot ) ) == 0xF )
  1745. return;
  1746. out.m_flFalloff = ReciprocalSIMD ( dist2 );
  1747. out.m_flFalloff = MulSIMD( out.m_flFalloff, dot2 );
  1748. // move the endpoint away from the surface by epsilon to prevent hitting the surface with the trace
  1749. offset.DuplicateVector ( dl->light.normal );
  1750. offset *= DIST_EPSILON;
  1751. src += offset;
  1752. break;
  1753. case emit_spotlight:
  1754. dot2 = delta * dl->light.normal;
  1755. dot2 = NegSIMD( dot2 );
  1756. // Affix dot2 to zero if outside light cone
  1757. inCone = CmpGtSIMD( dot2, ReplicateX4( dl->light.stopdot2 ) );
  1758. if ( !TestSignSIMD ( inCone ) )
  1759. return;
  1760. dot = AndSIMD( inCone, dot );
  1761. constant = ReplicateX4( dl->light.constant_attn );
  1762. linear = ReplicateX4( dl->light.linear_attn );
  1763. quadratic = ReplicateX4( dl->light.quadratic_attn );
  1764. out.m_flFalloff = MulSIMD( falloffEvalDist, falloffEvalDist );
  1765. out.m_flFalloff = MulSIMD( out.m_flFalloff, quadratic );
  1766. out.m_flFalloff = AddSIMD( out.m_flFalloff, MulSIMD( linear, falloffEvalDist ) );
  1767. out.m_flFalloff = AddSIMD( out.m_flFalloff, constant );
  1768. if ( g_bFiniteFalloffModel )
  1769. {
  1770. out.m_flFalloff = MaxSIMD( Four_Zeros, out.m_flFalloff );
  1771. }
  1772. else
  1773. {
  1774. out.m_flFalloff = ReciprocalSIMD( out.m_flFalloff );
  1775. }
  1776. out.m_flFalloff = MulSIMD( out.m_flFalloff, dot2 );
  1777. // outside the inner cone
  1778. inFringe = CmpLeSIMD( dot2, ReplicateX4( dl->light.stopdot ) );
  1779. mult = ReplicateX4( dl->light.stopdot - dl->light.stopdot2 );
  1780. mult = ReciprocalSIMD( mult );
  1781. mult = MulSIMD( mult, SubSIMD( dot2, ReplicateX4( dl->light.stopdot2 ) ) );
  1782. mult = MinSIMD( mult, Four_Ones );
  1783. mult = MaxSIMD( mult, Four_Zeros );
  1784. // pow is fixed point, so this isn't the most accurate, but it doesn't need to be
  1785. if ( (dl->light.exponent != 0.0f ) && ( dl->light.exponent != 1.0f ) )
  1786. mult = PowSIMD( mult, dl->light.exponent );
  1787. // if not in between inner and outer cones, mult by 1
  1788. mult = AndSIMD( inFringe, mult );
  1789. mult = AddSIMD( mult, AndNotSIMD( inFringe, Four_Ones ) );
  1790. out.m_flFalloff = MulSIMD( mult, out.m_flFalloff );
  1791. break;
  1792. }
  1793. // we may be in the fade region - modulate lighting by the fade curve
  1794. //float t = ( dist - dl->m_flStartFadeDistance ) /
  1795. // ( dl->m_flEndFadeDistance - dl->m_flStartFadeDistance );
  1796. if ( bHasHardFalloff )
  1797. {
  1798. fltx4 t = ReplicateX4( dl->m_flEndFadeDistance - dl->m_flStartFadeDistance );
  1799. t = ReciprocalSIMD( t );
  1800. t = MulSIMD( t, SubSIMD( dist, ReplicateX4( dl->m_flStartFadeDistance ) ) );
  1801. // clamp t to [0...1]
  1802. t = MinSIMD( t, Four_Ones );
  1803. t = MaxSIMD( t, Four_Zeros );
  1804. t = SubSIMD( Four_Ones, t );
  1805. // Using QuinticInterpolatingPolynomial, SSE-ified
  1806. // t * t * t *( t * ( t* 6.0 - 15.0 ) + 10.0 )
  1807. mult = SubSIMD( MulSIMD( ReplicateX4( 6.0f ), t ), ReplicateX4( 15.0f ) );
  1808. mult = AddSIMD( MulSIMD( mult, t ), ReplicateX4( 10.0f ) );
  1809. mult = MulSIMD( MulSIMD( t, t), mult );
  1810. mult = MulSIMD( t, mult );
  1811. out.m_flFalloff = MulSIMD( mult, out.m_flFalloff );
  1812. }
  1813. if ( !( nLFlags & GATHERLFLAGS_NO_OCCLUSION ) )
  1814. {
  1815. // Raytrace for visibility function
  1816. fltx4 fractionVisible = Four_Ones;
  1817. TestLine( pos, src, &fractionVisible, static_prop_index_to_ignore);
  1818. dot = MulSIMD( fractionVisible, dot );
  1819. }
  1820. out.m_flDot[0] = dot;
  1821. for ( int i = 1; i < normalCount; i++ )
  1822. {
  1823. if ( bIgnoreNormals )
  1824. {
  1825. out.m_flDot[i] = ReplicateX4( (float)CONSTANT_DOT );
  1826. out.m_flSunAmount[i] = Four_Zeros;
  1827. }
  1828. else
  1829. {
  1830. out.m_flDot[i] = pNormals[i] * delta;
  1831. out.m_flDot[i] = MaxSIMD( Four_Zeros, out.m_flDot[i] );
  1832. out.m_flSunAmount[i] = Four_Zeros;
  1833. }
  1834. }
  1835. }
  1836. // returns dot product with normal and delta
  1837. // dl - light
  1838. // pos - position of sample
  1839. // normal - surface normal of sample
  1840. // out.m_flDot[] - returned dot products with light vector and each normal
  1841. // out.m_flFalloff - amount of light falloff
  1842. void GatherSampleLightSSE( SSE_sampleLightOutput_t &out, directlight_t *dl, int facenum,
  1843. FourVectors const& pos, FourVectors *pNormals, int normalCount, int iThread,
  1844. int nLFlags,
  1845. int static_prop_index_to_ignore,
  1846. float flEpsilon )
  1847. {
  1848. for ( int b = 0; b < normalCount; b++ )
  1849. {
  1850. out.m_flDot[b] = Four_Zeros;
  1851. out.m_flSunAmount[b] = Four_Zeros;
  1852. }
  1853. out.m_flFalloff = Four_Zeros;
  1854. Assert( normalCount <= (NUM_BUMP_VECTS+1) );
  1855. // skylights work fundamentally differently than normal lights
  1856. switch( dl->light.type )
  1857. {
  1858. case emit_skylight:
  1859. GatherSampleSkyLightSSE( out, dl, facenum, pos, pNormals, normalCount,
  1860. iThread, nLFlags, static_prop_index_to_ignore, flEpsilon );
  1861. break;
  1862. case emit_skyambient:
  1863. GatherSampleAmbientSkySSE( out, dl, facenum, pos, pNormals, normalCount,
  1864. iThread, nLFlags, static_prop_index_to_ignore, flEpsilon );
  1865. break;
  1866. case emit_point:
  1867. case emit_surface:
  1868. case emit_spotlight:
  1869. GatherSampleStandardLightSSE( out, dl, facenum, pos, pNormals, normalCount,
  1870. iThread, nLFlags, static_prop_index_to_ignore, flEpsilon );
  1871. break;
  1872. default:
  1873. Error ("Bad dl->light.type");
  1874. return;
  1875. }
  1876. // Ambient occlusion for the 4 sample positions & normals
  1877. fltx4 ao = Four_Ones;
  1878. bool bIgnoreNormals = (nLFlags & GATHERLFLAGS_IGNORE_NORMALS) != 0;
  1879. if ( !bIgnoreNormals ) // Don't calculate ambient occlusion for objects that ignore normals for gathering light
  1880. {
  1881. if ( nLFlags & GATHERLFLAGS_STATICPROP )
  1882. {
  1883. // for static props we want the sun amount for the basis normals to be mutliplied by the ao of the main vertex normal only.
  1884. // lightmaps using this path do not send basis normals here, we do so for static props to take advantage of the SIMD optimisation this path provides.
  1885. ao = CalculateAmbientOcclusion4( pos, *pNormals, static_prop_index_to_ignore );
  1886. fltx4 ao0 = SplatXSIMD( ao );
  1887. ao = ao0;
  1888. }
  1889. else
  1890. {
  1891. ao = CalculateAmbientOcclusion4( pos, *pNormals, static_prop_index_to_ignore );
  1892. }
  1893. }
  1894. // NOTE: Notice here that if the light is on the back side of the face
  1895. // (tested by checking the dot product of the face normal and the light position)
  1896. // we don't want it to contribute to *any* of the bumped lightmaps. It glows
  1897. // in disturbing ways if we don't do this.
  1898. out.m_flDot[0] = MaxSIMD ( out.m_flDot[0], Four_Zeros );
  1899. fltx4 notZero = CmpGtSIMD( out.m_flDot[0], Four_Zeros );
  1900. out.m_flDot[0] = MulSIMD( out.m_flDot[0], ao );
  1901. out.m_flSunAmount[0] = MulSIMD( out.m_flSunAmount[0], ao );
  1902. for ( int n = 1; n < normalCount; n++ )
  1903. {
  1904. out.m_flDot[n] = MaxSIMD( out.m_flDot[n], Four_Zeros );
  1905. out.m_flDot[n] = AndSIMD( out.m_flDot[n], notZero );
  1906. out.m_flDot[n] = MulSIMD( out.m_flDot[n], ao );
  1907. out.m_flSunAmount[n] = MulSIMD( out.m_flSunAmount[n], ao );
  1908. }
  1909. }
  1910. /*
  1911. =============
  1912. AddSampleToPatch
  1913. Take the sample's collected light and
  1914. add it back into the apropriate patch
  1915. for the radiosity pass.
  1916. =============
  1917. */
  1918. void AddSampleToPatch (sample_t *s, LightingValue_t& light, int facenum)
  1919. {
  1920. CPatch *patch;
  1921. Vector mins, maxs;
  1922. int i;
  1923. if (numbounce == 0)
  1924. return;
  1925. if( VectorAvg( light.m_vecLighting ) < 1)
  1926. return;
  1927. //
  1928. // fixed the sample position and normal -- need to find the equiv pos, etc to set up
  1929. // patches
  1930. //
  1931. if( g_FacePatches.Element( facenum ) == g_FacePatches.InvalidIndex() )
  1932. return;
  1933. float radius = sqrt( s->area ) / 2.0;
  1934. CPatch *pNextPatch = NULL;
  1935. for( patch = &g_Patches.Element( g_FacePatches.Element( facenum ) ); patch; patch = pNextPatch )
  1936. {
  1937. // next patch
  1938. pNextPatch = NULL;
  1939. if( patch->ndxNext != g_Patches.InvalidIndex() )
  1940. {
  1941. pNextPatch = &g_Patches.Element( patch->ndxNext );
  1942. }
  1943. if (patch->sky)
  1944. continue;
  1945. // skip patches with children
  1946. if ( patch->child1 != g_Patches.InvalidIndex() )
  1947. continue;
  1948. // see if the point is in this patch (roughly)
  1949. WindingBounds (patch->winding, mins, maxs);
  1950. for (i=0 ; i<3 ; i++)
  1951. {
  1952. if (mins[i] > s->pos[i] + radius)
  1953. goto nextpatch;
  1954. if (maxs[i] < s->pos[i] - radius)
  1955. goto nextpatch;
  1956. }
  1957. // add the sample to the patch
  1958. patch->samplearea += s->area;
  1959. VectorMA( patch->samplelight, s->area, light.m_vecLighting, patch->samplelight );
  1960. nextpatch:;
  1961. }
  1962. // don't worry if some samples don't find a patch
  1963. }
  1964. void GetPhongNormal( int facenum, Vector const& spot, Vector& phongnormal )
  1965. {
  1966. int j;
  1967. dface_t *f = &g_pFaces[facenum];
  1968. // dplane_t *p = &dplanes[f->planenum];
  1969. Vector facenormal, vspot;
  1970. VectorCopy( dplanes[f->planenum].normal, facenormal );
  1971. VectorCopy( facenormal, phongnormal );
  1972. if ( smoothing_threshold != 1 )
  1973. {
  1974. faceneighbor_t *fn = &faceneighbor[facenum];
  1975. // Calculate modified point normal for surface
  1976. // Use the edge normals iff they are defined. Bend the surface towards the edge normal(s)
  1977. // Crude first attempt: find nearest edge normal and do a simple interpolation with facenormal.
  1978. // Second attempt: find edge points+center that bound the point and do a three-point triangulation(baricentric)
  1979. // Better third attempt: generate the point normals for all vertices and do baricentric triangulation.
  1980. for (j=0 ; j<f->numedges ; j++)
  1981. {
  1982. Vector v1, v2;
  1983. //int e = dsurfedges[f->firstedge + j];
  1984. //int e1 = dsurfedges[f->firstedge + ((j+f->numedges-1)%f->numedges)];
  1985. //int e2 = dsurfedges[f->firstedge + ((j+1)%f->numedges)];
  1986. //edgeshare_t *es = &edgeshare[abs(e)];
  1987. //edgeshare_t *es1 = &edgeshare[abs(e1)];
  1988. //edgeshare_t *es2 = &edgeshare[abs(e2)];
  1989. // dface_t *f2;
  1990. float a1, a2, aa, bb, ab;
  1991. int vert1, vert2;
  1992. Vector& n1 = fn->normal[j];
  1993. Vector& n2 = fn->normal[(j+1)%f->numedges];
  1994. /*
  1995. if (VectorCompare( n1, fn->facenormal )
  1996. && VectorCompare( n2, fn->facenormal) )
  1997. continue;
  1998. */
  1999. vert1 = EdgeVertex( f, j );
  2000. vert2 = EdgeVertex( f, j+1 );
  2001. Vector& p1 = dvertexes[vert1].point;
  2002. Vector& p2 = dvertexes[vert2].point;
  2003. // Build vectors from the middle of the face to the edge vertexes and the sample pos.
  2004. VectorSubtract( p1, face_centroids[facenum], v1 );
  2005. VectorSubtract( p2, face_centroids[facenum], v2 );
  2006. VectorSubtract( spot, face_centroids[facenum], vspot );
  2007. aa = DotProduct( v1, v1 );
  2008. bb = DotProduct( v2, v2 );
  2009. ab = DotProduct( v1, v2 );
  2010. a1 = (bb * DotProduct( v1, vspot ) - ab * DotProduct( vspot, v2 )) / (aa * bb - ab * ab);
  2011. a2 = (DotProduct( vspot, v2 ) - a1 * ab) / bb;
  2012. // Test center to sample vector for inclusion between center to vertex vectors (Use dot product of vectors)
  2013. if ( a1 >= 0.0 && a2 >= 0.0)
  2014. {
  2015. // calculate distance from edge to pos
  2016. Vector temp;
  2017. float scale;
  2018. // Interpolate between the center and edge normals based on sample position
  2019. scale = 1.0 - a1 - a2;
  2020. VectorScale( fn->facenormal, scale, phongnormal );
  2021. VectorScale( n1, a1, temp );
  2022. VectorAdd( phongnormal, temp, phongnormal );
  2023. VectorScale( n2, a2, temp );
  2024. VectorAdd( phongnormal, temp, phongnormal );
  2025. Assert( VectorLength( phongnormal ) > 1.0e-20 );
  2026. VectorNormalize( phongnormal );
  2027. /*
  2028. if (a1 > 1 || a2 > 1 || a1 + a2 > 1)
  2029. {
  2030. Msg("\n%.2f %.2f\n", a1, a2 );
  2031. Msg("%.2f %.2f %.2f\n", v1[0], v1[1], v1[2] );
  2032. Msg("%.2f %.2f %.2f\n", v2[0], v2[1], v2[2] );
  2033. Msg("%.2f %.2f %.2f\n", vspot[0], vspot[1], vspot[2] );
  2034. exit(1);
  2035. a1 = 0;
  2036. }
  2037. */
  2038. /*
  2039. phongnormal[0] = (((j + 1) & 4) != 0) * 255;
  2040. phongnormal[1] = (((j + 1) & 2) != 0) * 255;
  2041. phongnormal[2] = (((j + 1) & 1) != 0) * 255;
  2042. */
  2043. return;
  2044. }
  2045. }
  2046. }
  2047. }
  2048. void GetPhongNormal( int facenum, FourVectors const& spot, FourVectors& phongnormal )
  2049. {
  2050. int j;
  2051. dface_t *f = &g_pFaces[facenum];
  2052. // dplane_t *p = &dplanes[f->planenum];
  2053. Vector facenormal;
  2054. FourVectors vspot;
  2055. VectorCopy( dplanes[f->planenum].normal, facenormal );
  2056. phongnormal.DuplicateVector( facenormal );
  2057. FourVectors faceCentroid;
  2058. faceCentroid.DuplicateVector( face_centroids[facenum] );
  2059. if ( smoothing_threshold != 1 )
  2060. {
  2061. faceneighbor_t *fn = &faceneighbor[facenum];
  2062. // Calculate modified point normal for surface
  2063. // Use the edge normals iff they are defined. Bend the surface towards the edge normal(s)
  2064. // Crude first attempt: find nearest edge normal and do a simple interpolation with facenormal.
  2065. // Second attempt: find edge points+center that bound the point and do a three-point triangulation(baricentric)
  2066. // Better third attempt: generate the point normals for all vertices and do baricentric triangulation.
  2067. for ( j = 0; j < f->numedges; ++j )
  2068. {
  2069. Vector v1, v2;
  2070. fltx4 a1, a2;
  2071. float aa, bb, ab;
  2072. int vert1, vert2;
  2073. Vector& n1 = fn->normal[j];
  2074. Vector& n2 = fn->normal[(j+1)%f->numedges];
  2075. vert1 = EdgeVertex( f, j );
  2076. vert2 = EdgeVertex( f, j+1 );
  2077. Vector& p1 = dvertexes[vert1].point;
  2078. Vector& p2 = dvertexes[vert2].point;
  2079. // Build vectors from the middle of the face to the edge vertexes and the sample pos.
  2080. VectorSubtract( p1, face_centroids[facenum], v1 );
  2081. VectorSubtract( p2, face_centroids[facenum], v2 );
  2082. //VectorSubtract( spot, face_centroids[facenum], vspot );
  2083. vspot = spot;
  2084. vspot -= faceCentroid;
  2085. aa = DotProduct( v1, v1 );
  2086. bb = DotProduct( v2, v2 );
  2087. ab = DotProduct( v1, v2 );
  2088. //a1 = (bb * DotProduct( v1, vspot ) - ab * DotProduct( vspot, v2 )) / (aa * bb - ab * ab);
  2089. a1 = ReciprocalSIMD( ReplicateX4( aa * bb - ab * ab ) );
  2090. a1 = MulSIMD( a1, SubSIMD( MulSIMD( ReplicateX4( bb ), vspot * v1 ), MulSIMD( ReplicateX4( ab ), vspot * v2 ) ) );
  2091. //a2 = (DotProduct( vspot, v2 ) - a1 * ab) / bb;
  2092. a2 = ReciprocalSIMD( ReplicateX4( bb ) );
  2093. a2 = MulSIMD( a2, SubSIMD( vspot * v2, MulSIMD( a1, ReplicateX4( ab ) ) ) );
  2094. fltx4 resultMask = AndSIMD( CmpGeSIMD( a1, Four_Zeros ), CmpGeSIMD( a2, Four_Zeros ) );
  2095. if ( !TestSignSIMD( resultMask ) )
  2096. continue;
  2097. // Store the old phong normal to avoid overwriting already computed phong normals
  2098. FourVectors oldPhongNormal = phongnormal;
  2099. // calculate distance from edge to pos
  2100. FourVectors temp;
  2101. fltx4 scale;
  2102. // Interpolate between the center and edge normals based on sample position
  2103. scale = SubSIMD( SubSIMD( Four_Ones, a1 ), a2 );
  2104. phongnormal.DuplicateVector( fn->facenormal );
  2105. phongnormal *= scale;
  2106. temp.DuplicateVector( n1 );
  2107. temp *= a1;
  2108. phongnormal += temp;
  2109. temp.DuplicateVector( n2 );
  2110. temp *= a2;
  2111. phongnormal += temp;
  2112. // restore the old phong normals
  2113. phongnormal.x = AddSIMD( AndSIMD( resultMask, phongnormal.x ), AndNotSIMD( resultMask, oldPhongNormal.x ) );
  2114. phongnormal.y = AddSIMD( AndSIMD( resultMask, phongnormal.y ), AndNotSIMD( resultMask, oldPhongNormal.y ) );
  2115. phongnormal.z = AddSIMD( AndSIMD( resultMask, phongnormal.z ), AndNotSIMD( resultMask, oldPhongNormal.z ) );
  2116. }
  2117. phongnormal.VectorNormalize();
  2118. }
  2119. }
  2120. int GetVisCache( int lastoffset, int cluster, byte *pvs )
  2121. {
  2122. // get the PVS for the pos to limit the number of checks
  2123. if ( !visdatasize )
  2124. {
  2125. memset (pvs, 255, (dvis->numclusters+7)/8 );
  2126. lastoffset = -1;
  2127. }
  2128. else
  2129. {
  2130. if (cluster < 0)
  2131. {
  2132. // Error, point embedded in wall
  2133. // sampled[0][1] = 255;
  2134. memset (pvs, 255, (dvis->numclusters+7)/8 );
  2135. lastoffset = -1;
  2136. }
  2137. else
  2138. {
  2139. int thisoffset = dvis->bitofs[ cluster ][DVIS_PVS];
  2140. if ( thisoffset != lastoffset )
  2141. {
  2142. if ( thisoffset == -1 )
  2143. {
  2144. Error ("visofs == -1");
  2145. }
  2146. DecompressVis (&dvisdata[thisoffset], pvs);
  2147. }
  2148. lastoffset = thisoffset;
  2149. }
  2150. }
  2151. return lastoffset;
  2152. }
  2153. void BuildPatchLights( int facenum );
  2154. void DumpSamples( int ndxFace, facelight_t *pFaceLight )
  2155. {
  2156. ThreadLock();
  2157. dface_t *pFace = &g_pFaces[ndxFace];
  2158. if( pFace )
  2159. {
  2160. bool bBumpped = ( ( texinfo[pFace->texinfo].flags & SURF_BUMPLIGHT ) != 0 );
  2161. for( int iStyle = 0; iStyle < 4; ++iStyle )
  2162. {
  2163. if( pFace->styles[iStyle] != 255 )
  2164. {
  2165. for ( int iBump = 0; iBump < 4; ++iBump )
  2166. {
  2167. if ( iBump == 0 || ( iBump > 0 && bBumpped ) )
  2168. {
  2169. for( int iSample = 0; iSample < pFaceLight->numsamples; ++iSample )
  2170. {
  2171. sample_t *pSample = &pFaceLight->sample[iSample];
  2172. WriteWinding( pFileSamples[iStyle][iBump], pSample->w, pFaceLight->light[iStyle][iBump][iSample].m_vecLighting );
  2173. if( bDumpNormals )
  2174. {
  2175. WriteNormal( pFileSamples[iStyle][iBump], pSample->pos, pSample->normal, 15.0f, pSample->normal * 255.0f );
  2176. }
  2177. }
  2178. }
  2179. }
  2180. }
  2181. }
  2182. }
  2183. ThreadUnlock();
  2184. }
  2185. //-----------------------------------------------------------------------------
  2186. // Allocates light sample data
  2187. //-----------------------------------------------------------------------------
  2188. static inline void AllocateLightstyleSamples( facelight_t* fl, int styleIndex, int numnormals )
  2189. {
  2190. for (int n = 0; n < numnormals; ++n)
  2191. {
  2192. fl->light[styleIndex][n] = ( LightingValue_t* )calloc( fl->numsamples, sizeof(LightingValue_t ) );
  2193. }
  2194. }
  2195. //-----------------------------------------------------------------------------
  2196. // Used to find an existing lightstyle on a face
  2197. //-----------------------------------------------------------------------------
  2198. static inline int FindLightstyle( dface_t* f, int lightstyle )
  2199. {
  2200. for (int k = 0; k < MAXLIGHTMAPS; k++)
  2201. {
  2202. if (f->styles[k] == lightstyle)
  2203. return k;
  2204. }
  2205. return -1;
  2206. }
  2207. static int FindOrAllocateLightstyleSamples( dface_t* f, facelight_t *fl, int lightstyle, int numnormals )
  2208. {
  2209. // Search the lightstyles associated with the face for a match
  2210. int k;
  2211. for (k = 0; k < MAXLIGHTMAPS; k++)
  2212. {
  2213. if (f->styles[k] == lightstyle)
  2214. break;
  2215. // Found an empty entry, we can use it for a new lightstyle
  2216. if (f->styles[k] == 255)
  2217. {
  2218. AllocateLightstyleSamples( fl, k, numnormals );
  2219. f->styles[k] = lightstyle;
  2220. break;
  2221. }
  2222. }
  2223. // Check for overflow
  2224. if (k >= MAXLIGHTMAPS)
  2225. return -1;
  2226. return k;
  2227. }
  2228. //-----------------------------------------------------------------------------
  2229. // Compute the illumination point + normal for the sample
  2230. //-----------------------------------------------------------------------------
  2231. static void ComputeIlluminationPointAndNormalsSSE( lightinfo_t const& l, FourVectors const &pos, FourVectors const &norm, SSE_SampleInfo_t* pInfo, int numSamples )
  2232. {
  2233. Vector v[4];
  2234. pInfo->m_Points = pos;
  2235. bool computeNormals = ( pInfo->m_NormalCount > 1 && ( pInfo->m_IsDispFace || !l.isflat ) );
  2236. // FIXME: move sample point off the surface a bit, this is done so that
  2237. // light sampling will not be affected by a bug where raycasts will
  2238. // intersect with the face being lit. We really should just have that
  2239. // logic in GatherSampleLight
  2240. FourVectors faceNormal;
  2241. faceNormal.DuplicateVector( l.facenormal );
  2242. pInfo->m_Points += faceNormal;
  2243. if ( pInfo->m_IsDispFace )
  2244. {
  2245. pInfo->m_PointNormals[0] = norm;
  2246. }
  2247. else if ( !l.isflat )
  2248. {
  2249. // If the face isn't flat, use a phong-based normal instead
  2250. FourVectors modelorg;
  2251. modelorg.DuplicateVector( l.modelorg );
  2252. FourVectors vecSample = pos;
  2253. vecSample -= modelorg;
  2254. GetPhongNormal( pInfo->m_FaceNum, vecSample, pInfo->m_PointNormals[0] );
  2255. }
  2256. if ( computeNormals )
  2257. {
  2258. Vector bv[4][NUM_BUMP_VECTS];
  2259. for ( int i = 0; i < 4; ++i )
  2260. {
  2261. // TODO: using Vec may slow things down a bit
  2262. GetBumpNormals( pInfo->m_pTexInfo->textureVecsTexelsPerWorldUnits[0],
  2263. pInfo->m_pTexInfo->textureVecsTexelsPerWorldUnits[1],
  2264. l.facenormal, pInfo->m_PointNormals[0].Vec( i ), bv[i] );
  2265. }
  2266. for ( int b = 0; b < NUM_BUMP_VECTS; ++b )
  2267. {
  2268. pInfo->m_PointNormals[b+1].LoadAndSwizzle ( bv[0][b], bv[1][b], bv[2][b], bv[3][b] );
  2269. }
  2270. }
  2271. // TODO: this may slow things down a bit ( using Vec )
  2272. for ( int i = 0; i < 4; ++i )
  2273. pInfo->m_Clusters[i] = ClusterFromPoint( pos.Vec( i ) );
  2274. }
  2275. //-----------------------------------------------------------------------------
  2276. // Compute the illumination point + normal for the sample on a displacement
  2277. // (see ComputeIlluminationPointAndNormalsSSE above)
  2278. //-----------------------------------------------------------------------------
  2279. static void ComputeIlluminationPointAndNormalsForDisp( lightinfo_t const& l, FourVectors &pos, FourVectors &norm, SSE_SampleInfo_t* pInfo )
  2280. {
  2281. pInfo->m_PointNormals[ 0 ] = norm;
  2282. if ( pInfo->m_NormalCount > 1 )
  2283. {
  2284. Vector bv[ 4 ][ NUM_BUMP_VECTS ];
  2285. for ( int j = 0; j < 4; j++ )
  2286. {
  2287. // TODO: using Vec may slow things down a bit
  2288. GetBumpNormals( pInfo->m_pTexInfo->textureVecsTexelsPerWorldUnits[ 0 ],
  2289. pInfo->m_pTexInfo->textureVecsTexelsPerWorldUnits[ 1 ],
  2290. l.facenormal, norm.Vec( j ), bv[ j ] );
  2291. }
  2292. for ( int b = 0; b < NUM_BUMP_VECTS; b++ )
  2293. {
  2294. pInfo->m_PointNormals[ b + 1 ].LoadAndSwizzle( bv[ 0 ][ b ], bv[ 1 ][ b ], bv[ 2 ][ b ], bv[ 3 ][ b ] );
  2295. }
  2296. }
  2297. pInfo->m_Points = pos;
  2298. // FIXME: move sample point off the surface a bit, this is done so that
  2299. // light sampling will not be affected by a bug where raycasts will
  2300. // intersect with the face being lit. We really should just have that
  2301. // logic in GatherSampleLight
  2302. FourVectors faceNormal = norm;
  2303. pInfo->m_Points += faceNormal;
  2304. // TODO: this may slow things down a bit ( using Vec )
  2305. for ( int j = 0; j < 4; j++ )
  2306. pInfo->m_Clusters[ j ] = ClusterFromPoint( pos.Vec( j ) );
  2307. }
  2308. //-----------------------------------------------------------------------------
  2309. // Iterates over all lights and computes lighting at up to 4 sample points
  2310. //-----------------------------------------------------------------------------
  2311. static void GatherSampleLightAt4Points( SSE_SampleInfo_t& info, int sampleIdx, int numSamples )
  2312. {
  2313. SSE_sampleLightOutput_t out;
  2314. // Iterate over all direct lights and add them to the particular sample
  2315. for (directlight_t *dl = activelights; dl != NULL; dl = dl->next)
  2316. {
  2317. // is this lights cluster visible?
  2318. fltx4 dotMask = Four_Zeros;
  2319. bool skipLight = true;
  2320. for( int s = 0; s < numSamples; s++ )
  2321. {
  2322. if( PVSCheck( dl->pvs, info.m_Clusters[s] ) )
  2323. {
  2324. dotMask = SetComponentSIMD( dotMask, s, 1.0f );
  2325. skipLight = false;
  2326. }
  2327. }
  2328. if ( skipLight )
  2329. continue;
  2330. GatherSampleLightSSE( out, dl, info.m_FaceNum, info.m_Points, info.m_PointNormals, info.m_NormalCount, info.m_iThread );
  2331. // Apply the PVS check filter and compute falloff x dot
  2332. fltx4 fxdot[NUM_BUMP_VECTS + 1];
  2333. skipLight = true;
  2334. for ( int b = 0; b < info.m_NormalCount; b++ )
  2335. {
  2336. fxdot[b] = MulSIMD( out.m_flDot[b], dotMask );
  2337. fxdot[b] = MulSIMD( fxdot[b], out.m_flFalloff );
  2338. if ( !IsAllZeros( fxdot[b] ) )
  2339. {
  2340. skipLight = false;
  2341. }
  2342. }
  2343. if ( skipLight )
  2344. continue;
  2345. // Figure out the lightstyle for this particular sample
  2346. int lightStyleIndex = FindOrAllocateLightstyleSamples( info.m_pFace, info.m_pFaceLight,
  2347. dl->light.style, info.m_NormalCount );
  2348. if (lightStyleIndex < 0)
  2349. {
  2350. if (info.m_WarnFace != info.m_FaceNum)
  2351. {
  2352. Warning ("\nWARNING: Too many light styles on a face at (%f, %f, %f)\n",
  2353. info.m_Points.x.m128_f32[0], info.m_Points.y.m128_f32[0], info.m_Points.z.m128_f32[0] );
  2354. info.m_WarnFace = info.m_FaceNum;
  2355. }
  2356. continue;
  2357. }
  2358. // pLightmaps is an array of the lightmaps for each normal direction,
  2359. // here's where the result of the sample gathering goes
  2360. LightingValue_t** pLightmaps = info.m_pFaceLight->light[lightStyleIndex];
  2361. // Incremental lighting only cares about lightstyle zero
  2362. if( g_pIncremental && (dl->light.style == 0) )
  2363. {
  2364. for ( int i = 0; i < numSamples; i++ )
  2365. {
  2366. g_pIncremental->AddLightToFace( dl->m_IncrementalID, info.m_FaceNum, sampleIdx + i,
  2367. info.m_LightmapSize, SubFloat( fxdot[0], i ), info.m_iThread );
  2368. }
  2369. }
  2370. for( int n = 0; n < info.m_NormalCount; ++n )
  2371. {
  2372. for ( int i = 0; i < numSamples; i++ )
  2373. {
  2374. pLightmaps[n][sampleIdx + i].AddLight( SubFloat( fxdot[n], i ), dl->light.intensity, SubFloat( out.m_flSunAmount[n], i ) );
  2375. }
  2376. }
  2377. }
  2378. }
  2379. //-----------------------------------------------------------------------------
  2380. // Iterates over all lights and computes lighting at a sample point
  2381. //-----------------------------------------------------------------------------
  2382. static void ResampleLightAt4Points( SSE_SampleInfo_t& info, int lightStyleIndex, int flags, LightingValue_t pLightmap[4][NUM_BUMP_VECTS+1] )
  2383. {
  2384. SSE_sampleLightOutput_t out;
  2385. // Clear result
  2386. for ( int i = 0; i < 4; ++i )
  2387. {
  2388. for ( int n = 0; n < info.m_NormalCount; ++n )
  2389. {
  2390. pLightmap[i][n].Zero();
  2391. }
  2392. }
  2393. // Iterate over all direct lights and add them to the particular sample
  2394. for (directlight_t *dl = activelights; dl != NULL; dl = dl->next)
  2395. {
  2396. if ((flags & AMBIENT_ONLY) && (dl->light.type != emit_skyambient))
  2397. continue;
  2398. if ((flags & NON_AMBIENT_ONLY) && (dl->light.type == emit_skyambient))
  2399. continue;
  2400. // Only add contributions that match the lightstyle
  2401. Assert( lightStyleIndex <= MAXLIGHTMAPS );
  2402. Assert( info.m_pFace->styles[lightStyleIndex] != 255 );
  2403. if (dl->light.style != info.m_pFace->styles[lightStyleIndex])
  2404. continue;
  2405. // is this lights cluster visible?
  2406. fltx4 dotMask = Four_Zeros;
  2407. bool skipLight = true;
  2408. for( int s = 0; s < 4; s++ )
  2409. {
  2410. if( PVSCheck( dl->pvs, info.m_Clusters[s] ) )
  2411. {
  2412. dotMask = SetComponentSIMD( dotMask, s, 1.0f );
  2413. skipLight = false;
  2414. }
  2415. }
  2416. if ( skipLight )
  2417. continue;
  2418. // NOTE: Notice here that if the light is on the back side of the face
  2419. // (tested by checking the dot product of the face normal and the light position)
  2420. // we don't want it to contribute to *any* of the bumped lightmaps. It glows
  2421. // in disturbing ways if we don't do this.
  2422. GatherSampleLightSSE( out, dl, info.m_FaceNum, info.m_Points, info.m_PointNormals, info.m_NormalCount, info.m_iThread );
  2423. // Apply the PVS check filter and compute falloff x dot
  2424. fltx4 fxdot[NUM_BUMP_VECTS + 1];
  2425. for ( int b = 0; b < info.m_NormalCount; b++ )
  2426. {
  2427. fxdot[b] = MulSIMD( out.m_flFalloff, out.m_flDot[b] );
  2428. fxdot[b] = MulSIMD( fxdot[b], dotMask );
  2429. }
  2430. // Compute the contributions to each of the bumped lightmaps
  2431. // The first sample is for non-bumped lighting.
  2432. // The other sample are for bumpmapping.
  2433. for( int i = 0; i < 4; ++i )
  2434. {
  2435. for( int n = 0; n < info.m_NormalCount; ++n )
  2436. {
  2437. pLightmap[i][n].AddLight( SubFloat( fxdot[n], i ), dl->light.intensity, SubFloat( out.m_flSunAmount[n], i ) );
  2438. }
  2439. }
  2440. }
  2441. }
  2442. bool PointsInWinding( FourVectors const & point, winding_t *w, int &invalidBits )
  2443. {
  2444. FourVectors edge, toPt, cross, testCross, p0, p1;
  2445. fltx4 invalidMask = Four_Zeros;
  2446. //
  2447. // get the first normal to test
  2448. //
  2449. p0.DuplicateVector( w->p[0] );
  2450. p1.DuplicateVector( w->p[1] );
  2451. toPt = point;
  2452. toPt -= p0;
  2453. edge = p1;
  2454. edge -= p0;
  2455. testCross = edge ^ toPt;
  2456. // safer against /0 - testCross.VectorNormalizeFast();
  2457. fltx4 mag_sq = testCross * testCross;
  2458. testCross *= ReciprocalSqrtEstSaturateSIMD( mag_sq );
  2459. for ( int ndxPt = 1; ndxPt < w->numpoints; ndxPt++ )
  2460. {
  2461. p0.DuplicateVector( w->p[ndxPt] );
  2462. p1.DuplicateVector( w->p[(ndxPt+1)%w->numpoints] );
  2463. toPt = point;
  2464. toPt -= p0;
  2465. edge = p1;
  2466. edge -= p0;
  2467. cross = edge ^ toPt;
  2468. // safer against /0 - cross.VectorNormalizeFast();
  2469. mag_sq = cross * cross;
  2470. cross *= ReciprocalSqrtEstSaturateSIMD( mag_sq );
  2471. fltx4 dot = cross * testCross;
  2472. invalidMask = OrSIMD( invalidMask, CmpLtSIMD( dot, Four_Zeros ) );
  2473. invalidBits = TestSignSIMD ( invalidMask );
  2474. if ( invalidBits == 0xF )
  2475. return false;
  2476. }
  2477. return true;
  2478. }
  2479. //-----------------------------------------------------------------------------
  2480. // Perform supersampling at a particular point
  2481. //-----------------------------------------------------------------------------
  2482. static int SupersampleLightAtPoint( lightinfo_t& l, SSE_SampleInfo_t& info,
  2483. int sampleIndex, int lightStyleIndex, LightingValue_t *pLight, int flags )
  2484. {
  2485. sample_t& sample = info.m_pFaceLight->sample[sampleIndex];
  2486. // Get the position of the original sample in lightmapspace
  2487. Vector2D temp;
  2488. WorldToLuxelSpace( &l, sample.pos, temp );
  2489. Vector sampleLightOrigin( temp[0], temp[1], 0.0f );
  2490. // Some parameters related to supersampling
  2491. float sampleWidth = ( flags & NON_AMBIENT_ONLY ) ? 4 : 2;
  2492. float cscale = 1.0f / sampleWidth;
  2493. float csshift = -( ( sampleWidth - 1 ) * cscale ) / 2.0;
  2494. // Clear out the light values
  2495. for (int i = 0; i < info.m_NormalCount; ++i )
  2496. pLight[i].Zero();
  2497. int subsampleCount = 0;
  2498. FourVectors superSampleNormal;
  2499. superSampleNormal.DuplicateVector( sample.normal );
  2500. FourVectors superSampleLightCoord;
  2501. FourVectors superSamplePosition;
  2502. superSamplePosition.DuplicateVector( sample.pos );
  2503. Vector wsError;
  2504. FourVectors superSampleWorldSpaceError;
  2505. float stepU = 0.0f;
  2506. float stepV = 0.0f;
  2507. if ( info.m_IsDispFace )
  2508. {
  2509. // compensate for error when transforming back to worldspace (only enabled for displacements)
  2510. Vector toWorld;
  2511. LuxelSpaceToWorld( &l, temp.x, temp.y, toWorld );
  2512. VectorSubtract( sample.pos, toWorld, wsError );
  2513. superSampleWorldSpaceError.DuplicateVector( wsError );
  2514. // lightmap size
  2515. int width = l.face->m_LightmapTextureSizeInLuxels[ 0 ] + 1;
  2516. int height = l.face->m_LightmapTextureSizeInLuxels[ 1 ] + 1;
  2517. // calculate the steps in uv space
  2518. stepU = 1.0f / (float)width;
  2519. stepV = 1.0f / (float)height;
  2520. }
  2521. if ( flags & NON_AMBIENT_ONLY )
  2522. {
  2523. float aRow[4];
  2524. for ( int coord = 0; coord < 4; ++coord )
  2525. aRow[ coord ] = csshift + coord * cscale;
  2526. fltx4 sseRow = LoadUnalignedSIMD( aRow );
  2527. for (int s = 0; s < 4; ++s)
  2528. {
  2529. // make sure the coordinate is inside of the sample's winding and when normalizing
  2530. // below use the number of samples used, not just numsamples and some of them
  2531. // will be skipped if they are not inside of the winding
  2532. superSampleLightCoord.DuplicateVector( sampleLightOrigin );
  2533. superSampleLightCoord.x = AddSIMD( superSampleLightCoord.x, ReplicateX4( aRow[s] ) );
  2534. superSampleLightCoord.y = AddSIMD( superSampleLightCoord.y, sseRow );
  2535. // Figure out where the supersample exists in the world, and make sure
  2536. // it lies within the sample winding
  2537. LuxelSpaceToWorld( &l, superSampleLightCoord[0], superSampleLightCoord[1], superSamplePosition );
  2538. if ( info.m_IsDispFace )
  2539. {
  2540. // Fix up error from world to luxel and back again
  2541. superSamplePosition += superSampleWorldSpaceError;
  2542. // Find pos and norm for disp from uv supersample offsets
  2543. Vector vDispP[4], vDispN[4];
  2544. for ( int i = 0; i < 4; i++ )
  2545. {
  2546. vDispP[ i ] = superSamplePosition.Vec( i );
  2547. Vector2D uv;
  2548. uv.x = sample.coord[0] + ( aRow[ s ] * stepU );
  2549. uv.y = sample.coord[1] + ( aRow[ i ] * stepV );
  2550. StaticDispMgr()->GetDispSurfPointAndNormalFromUV( info.m_FaceNum, vDispP[ i ], vDispN[ i ], uv, false );
  2551. }
  2552. superSamplePosition = FourVectors( vDispP[ 0 ], vDispP[ 1 ], vDispP[ 2 ], vDispP[ 3 ] );
  2553. superSampleNormal = FourVectors( vDispN[ 0 ], vDispN[ 1 ], vDispN[ 2 ], vDispN[ 3 ] );
  2554. ComputeIlluminationPointAndNormalsForDisp( l, superSamplePosition, superSampleNormal, &info );
  2555. }
  2556. // A winding should exist only if the sample wasn't a uniform luxel, or if g_bDumpPatches is true.
  2557. int invalidBits = 0;
  2558. if ( sample.w && !PointsInWinding( superSamplePosition, sample.w, invalidBits ) )
  2559. continue;
  2560. // Compute the super-sample illumination point and normal
  2561. // We're assuming the flat normal is the same for all supersamples
  2562. if ( !info.m_IsDispFace )
  2563. ComputeIlluminationPointAndNormalsSSE( l, superSamplePosition, superSampleNormal, &info, 4 );
  2564. // Resample the non-ambient light at this point...
  2565. LightingValue_t result[4][NUM_BUMP_VECTS+1];
  2566. ResampleLightAt4Points( info, lightStyleIndex, NON_AMBIENT_ONLY, result );
  2567. // Got more subsamples
  2568. for ( int i = 0; i < 4; i++ )
  2569. {
  2570. if ( !( ( invalidBits >> i ) & 0x1 ) )
  2571. {
  2572. for ( int n = 0; n < info.m_NormalCount; ++n )
  2573. {
  2574. pLight[ n ].AddLight( result[ i ][ n ] );
  2575. }
  2576. ++subsampleCount;
  2577. }
  2578. }
  2579. }
  2580. }
  2581. else
  2582. {
  2583. FourVectors superSampleOffsets;
  2584. superSampleOffsets.LoadAndSwizzle( Vector( csshift, csshift, 0 ), Vector( csshift, csshift + cscale, 0),
  2585. Vector( csshift + cscale, csshift, 0 ), Vector( csshift + cscale, csshift + cscale, 0 ) );
  2586. superSampleLightCoord.DuplicateVector( sampleLightOrigin );
  2587. superSampleLightCoord += superSampleOffsets;
  2588. LuxelSpaceToWorld( &l, superSampleLightCoord[0], superSampleLightCoord[1], superSamplePosition );
  2589. if ( info.m_IsDispFace )
  2590. {
  2591. // Fix up error from world to luxel and back again
  2592. superSamplePosition += superSampleWorldSpaceError;
  2593. // Find pos and norm for disp from uv supersample offsets
  2594. Vector vDispP[ 4 ], vDispN[ 4 ];
  2595. for ( int i = 0; i < 4; i++ )
  2596. {
  2597. vDispP[ i ] = superSamplePosition.Vec( i );
  2598. Vector uvOffsets = superSampleOffsets.Vec( i );
  2599. Vector2D uv;
  2600. uv.x = sample.coord[ 0 ] + ( uvOffsets.x * stepU );
  2601. uv.y = sample.coord[ 1 ] + ( uvOffsets.y * stepV );
  2602. StaticDispMgr()->GetDispSurfPointAndNormalFromUV( info.m_FaceNum, vDispP[ i ], vDispN[ i ], uv, false );
  2603. }
  2604. superSamplePosition = FourVectors( vDispP[ 0 ], vDispP[ 1 ], vDispP[ 2 ], vDispP[ 3 ] );
  2605. superSampleNormal = FourVectors( vDispN[ 0 ], vDispN[ 1 ], vDispN[ 2 ], vDispN[ 3 ] );
  2606. ComputeIlluminationPointAndNormalsForDisp( l, superSamplePosition, superSampleNormal, &info );
  2607. }
  2608. int invalidBits = 0;
  2609. if ( sample.w && !PointsInWinding( superSamplePosition, sample.w, invalidBits ) )
  2610. return 0;
  2611. if ( !info.m_IsDispFace )
  2612. ComputeIlluminationPointAndNormalsSSE( l, superSamplePosition, superSampleNormal, &info, 4 );
  2613. LightingValue_t result[4][NUM_BUMP_VECTS+1];
  2614. ResampleLightAt4Points( info, lightStyleIndex, AMBIENT_ONLY, result );
  2615. // Got more subsamples
  2616. for ( int i = 0; i < 4; i++ )
  2617. {
  2618. if ( !( ( invalidBits >> i ) & 0x1 ) )
  2619. {
  2620. for ( int n = 0; n < info.m_NormalCount; ++n )
  2621. {
  2622. pLight[ n ].AddLight( result[ i ][ n ] );
  2623. }
  2624. ++subsampleCount;
  2625. }
  2626. }
  2627. }
  2628. return subsampleCount;
  2629. }
  2630. //-----------------------------------------------------------------------------
  2631. // Compute gradients of a lightmap
  2632. //-----------------------------------------------------------------------------
  2633. static void ComputeLightmapGradients( SSE_SampleInfo_t& info, bool const* pHasProcessedSample,
  2634. float* pIntensity, float* gradient )
  2635. {
  2636. int w = info.m_LightmapWidth;
  2637. int h = info.m_LightmapHeight;
  2638. facelight_t* fl = info.m_pFaceLight;
  2639. for (int i=0 ; i<fl->numsamples ; i++)
  2640. {
  2641. // Don't supersample the same sample twice
  2642. if (pHasProcessedSample[i])
  2643. continue;
  2644. gradient[i] = 0.0f;
  2645. sample_t& sample = fl->sample[i];
  2646. // Choose the maximum gradient of all bumped lightmap intensities
  2647. for ( int n = 0; n < info.m_NormalCount; ++n )
  2648. {
  2649. int j = n * info.m_LightmapSize + sample.s + sample.t * w;
  2650. if (sample.t > 0)
  2651. {
  2652. if (sample.s > 0) gradient[i] = max( gradient[i], fabs( pIntensity[j] - pIntensity[j-1-w] ) );
  2653. gradient[i] = max( gradient[i], fabs( pIntensity[j] - pIntensity[j-w] ) );
  2654. if (sample.s < w-1) gradient[i] = max( gradient[i], fabs( pIntensity[j] - pIntensity[j+1-w] ) );
  2655. }
  2656. if (sample.t < h-1)
  2657. {
  2658. if (sample.s > 0) gradient[i] = max( gradient[i], fabs( pIntensity[j] - pIntensity[j-1+w] ) );
  2659. gradient[i] = max( gradient[i], fabs( pIntensity[j] - pIntensity[j+w] ) );
  2660. if (sample.s < w-1) gradient[i] = max( gradient[i], fabs( pIntensity[j] - pIntensity[j+1+w] ) );
  2661. }
  2662. if (sample.s > 0) gradient[i] = max( gradient[i], fabs( pIntensity[j] - pIntensity[j-1] ) );
  2663. if (sample.s < w-1) gradient[i] = max( gradient[i], fabs( pIntensity[j] - pIntensity[j+1] ) );
  2664. }
  2665. }
  2666. }
  2667. //-----------------------------------------------------------------------------
  2668. // ComputeLuxelIntensity...
  2669. //-----------------------------------------------------------------------------
  2670. static inline void ComputeLuxelIntensity( SSE_SampleInfo_t& info, int sampleIdx,
  2671. LightingValue_t **ppLightSamples, float* pSampleIntensity )
  2672. {
  2673. // Compute a separate intensity for each
  2674. sample_t& sample = info.m_pFaceLight->sample[sampleIdx];
  2675. int destIdx = sample.s + sample.t * info.m_LightmapWidth;
  2676. for (int n = 0; n < info.m_NormalCount; ++n)
  2677. {
  2678. float intensity = ppLightSamples[n][sampleIdx].Intensity();
  2679. // convert to a linear perception space
  2680. pSampleIntensity[n * info.m_LightmapSize + destIdx] = pow( intensity / 256.0, 1.0 / 2.2 );
  2681. }
  2682. }
  2683. //-----------------------------------------------------------------------------
  2684. // Compute the maximum intensity based on all bumped lighting
  2685. //-----------------------------------------------------------------------------
  2686. static void ComputeSampleIntensities( SSE_SampleInfo_t& info, LightingValue_t **ppLightSamples, float* pSampleIntensity )
  2687. {
  2688. for (int i=0; i<info.m_pFaceLight->numsamples; i++)
  2689. {
  2690. ComputeLuxelIntensity( info, i, ppLightSamples, pSampleIntensity );
  2691. }
  2692. }
  2693. //-----------------------------------------------------------------------------
  2694. // Perform supersampling on a particular lightstyle
  2695. //-----------------------------------------------------------------------------
  2696. static void BuildSupersampleFaceLights( lightinfo_t& l, SSE_SampleInfo_t& info, int lightstyleIndex )
  2697. {
  2698. LightingValue_t pAmbientLight[NUM_BUMP_VECTS+1];
  2699. LightingValue_t pDirectLight[NUM_BUMP_VECTS+1];
  2700. // This is used to make sure we don't supersample a light sample more than once
  2701. int processedSampleSize = info.m_LightmapSize * sizeof(bool);
  2702. bool* pHasProcessedSample = (bool*)stackalloc( processedSampleSize );
  2703. memset( pHasProcessedSample, 0, processedSampleSize );
  2704. // This is used to compute a simple gradient computation of the light samples
  2705. // We're going to store the maximum intensity of all bumped samples at each sample location
  2706. float* pGradient = (float*)stackalloc( info.m_pFaceLight->numsamples * sizeof(float) );
  2707. float* pSampleIntensity = (float*)stackalloc( info.m_NormalCount * info.m_LightmapSize * sizeof(float) );
  2708. // Compute the maximum intensity of all lighting associated with this lightstyle
  2709. // for all bumped lighting
  2710. LightingValue_t **ppLightSamples = info.m_pFaceLight->light[lightstyleIndex];
  2711. ComputeSampleIntensities( info, ppLightSamples, pSampleIntensity );
  2712. Vector *pVisualizePass = NULL;
  2713. if (debug_extra)
  2714. {
  2715. int visualizationSize = info.m_pFaceLight->numsamples * sizeof(Vector);
  2716. pVisualizePass = (Vector*)stackalloc( visualizationSize );
  2717. memset( pVisualizePass, 0, visualizationSize );
  2718. }
  2719. // What's going on here is that we're looking for large lighting discontinuities
  2720. // (large light intensity gradients) as a clue that we should probably be supersampling
  2721. // in that area. Because the supersampling operation will cause lighting changes,
  2722. // we've found that it's good to re-check the gradients again and see if any other
  2723. // areas should be supersampled as a result of the previous pass. Keep going
  2724. // until all the gradients are reasonable or until we hit a max number of passes
  2725. bool do_anotherpass = true;
  2726. int pass = 1;
  2727. while (do_anotherpass && pass <= extrapasses)
  2728. {
  2729. // Look for lighting discontinuities to see what we should be supersampling
  2730. ComputeLightmapGradients( info, pHasProcessedSample, pSampleIntensity, pGradient );
  2731. do_anotherpass = false;
  2732. // Now check all of the samples and supersample those which we have
  2733. // marked as having high gradients
  2734. for (int i=0 ; i<info.m_pFaceLight->numsamples; ++i)
  2735. {
  2736. // Don't supersample the same sample twice
  2737. if (pHasProcessedSample[i])
  2738. continue;
  2739. // Don't supersample if the lighting is pretty uniform near the sample
  2740. if (pGradient[i] < 0.0625)
  2741. continue;
  2742. // Joy! We're supersampling now, and we therefore must do another pass
  2743. // Also, we need never bother with this sample again
  2744. pHasProcessedSample[i] = true;
  2745. do_anotherpass = true;
  2746. if (debug_extra)
  2747. {
  2748. // Mark the little visualization bitmap with a color indicating
  2749. // which pass it was updated on.
  2750. pVisualizePass[i][0] = (pass & 1) * 255;
  2751. pVisualizePass[i][1] = (pass & 2) * 128;
  2752. pVisualizePass[i][2] = (pass & 4) * 64;
  2753. }
  2754. // Supersample the ambient light for each bump direction vector
  2755. int ambientSupersampleCount = SupersampleLightAtPoint( l, info, i, lightstyleIndex, pAmbientLight, AMBIENT_ONLY );
  2756. // Supersample the non-ambient light for each bump direction vector
  2757. int directSupersampleCount = SupersampleLightAtPoint( l, info, i, lightstyleIndex, pDirectLight, NON_AMBIENT_ONLY );
  2758. // Because of sampling problems, small area triangles may have no samples.
  2759. // In this case, just use what we already have
  2760. if ( ambientSupersampleCount > 0 && directSupersampleCount > 0 )
  2761. {
  2762. // Add the ambient + directional terms together, stick it back into the lightmap
  2763. for ( int n = 0; n < info.m_NormalCount; ++n )
  2764. {
  2765. ppLightSamples[ n ][ i ].Zero();
  2766. ppLightSamples[ n ][ i ].AddWeighted( pDirectLight[ n ], 1.0f / directSupersampleCount );
  2767. ppLightSamples[ n ][ i ].AddWeighted( pAmbientLight[ n ], 1.0f / ambientSupersampleCount );
  2768. }
  2769. // Recompute the luxel intensity based on the supersampling
  2770. ComputeLuxelIntensity( info, i, ppLightSamples, pSampleIntensity );
  2771. }
  2772. }
  2773. // We've finished another pass
  2774. pass++;
  2775. }
  2776. if (debug_extra)
  2777. {
  2778. // Copy colors representing which supersample pass the sample was messed with
  2779. // into the actual lighting values so we can visualize it
  2780. for (int i=0 ; i<info.m_pFaceLight->numsamples ; ++i)
  2781. {
  2782. for (int j = 0; j <info.m_NormalCount; ++j)
  2783. {
  2784. VectorCopy( pVisualizePass[i], ppLightSamples[j][i].m_vecLighting );
  2785. }
  2786. }
  2787. }
  2788. }
  2789. void InitLightinfo( lightinfo_t *pl, int facenum )
  2790. {
  2791. dface_t *f;
  2792. f = &g_pFaces[facenum];
  2793. memset (pl, 0, sizeof(*pl));
  2794. pl->facenum = facenum;
  2795. pl->face = f;
  2796. //
  2797. // rotate plane
  2798. //
  2799. VectorCopy (dplanes[f->planenum].normal, pl->facenormal);
  2800. pl->facedist = dplanes[f->planenum].dist;
  2801. // get the origin offset for rotating bmodels
  2802. VectorCopy (face_offset[facenum], pl->modelorg);
  2803. CalcFaceVectors( pl );
  2804. // figure out if the surface is flat
  2805. pl->isflat = true;
  2806. if (smoothing_threshold != 1)
  2807. {
  2808. faceneighbor_t *fn = &faceneighbor[facenum];
  2809. for (int j=0 ; j<f->numedges ; j++)
  2810. {
  2811. float dot = DotProduct( pl->facenormal, fn->normal[j] );
  2812. if (dot < 1.0 - EQUAL_EPSILON)
  2813. {
  2814. pl->isflat = false;
  2815. break;
  2816. }
  2817. }
  2818. }
  2819. }
  2820. static void InitSampleInfo( lightinfo_t const& l, int iThread, SSE_SampleInfo_t& info )
  2821. {
  2822. info.m_LightmapWidth = l.face->m_LightmapTextureSizeInLuxels[0]+1;
  2823. info.m_LightmapHeight = l.face->m_LightmapTextureSizeInLuxels[1]+1;
  2824. info.m_LightmapSize = info.m_LightmapWidth * info.m_LightmapHeight;
  2825. // How many lightmaps are we going to need?
  2826. info.m_pTexInfo = &texinfo[l.face->texinfo];
  2827. info.m_NormalCount = (info.m_pTexInfo->flags & SURF_BUMPLIGHT) ? NUM_BUMP_VECTS + 1 : 1;
  2828. info.m_FaceNum = l.facenum;
  2829. info.m_pFace = l.face;
  2830. info.m_pFaceLight = &facelight[info.m_FaceNum];
  2831. info.m_IsDispFace = ValidDispFace( info.m_pFace );
  2832. info.m_iThread = iThread;
  2833. info.m_WarnFace = -1;
  2834. info.m_NumSamples = info.m_pFaceLight->numsamples;
  2835. info.m_NumSampleGroups = ( info.m_NumSamples & 0x3) ? ( info.m_NumSamples / 4 ) + 1 : ( info.m_NumSamples / 4 );
  2836. // initialize normals if the surface is flat
  2837. if (l.isflat)
  2838. {
  2839. info.m_PointNormals[0].DuplicateVector( l.facenormal );
  2840. // use facenormal along with the smooth normal to build the three bump map vectors
  2841. if( info.m_NormalCount > 1 )
  2842. {
  2843. Vector bumpVects[NUM_BUMP_VECTS];
  2844. GetBumpNormals( info.m_pTexInfo->textureVecsTexelsPerWorldUnits[0],
  2845. info.m_pTexInfo->textureVecsTexelsPerWorldUnits[1], l.facenormal,
  2846. l.facenormal, bumpVects );//&info.m_PointNormal[1] );
  2847. for ( int b = 0; b < NUM_BUMP_VECTS; ++b )
  2848. {
  2849. info.m_PointNormals[b + 1].DuplicateVector( bumpVects[b] );
  2850. }
  2851. }
  2852. }
  2853. }
  2854. void BuildFacelights (int iThread, int facenum)
  2855. {
  2856. int i, j;
  2857. lightinfo_t l;
  2858. dface_t *f;
  2859. facelight_t *fl;
  2860. SSE_SampleInfo_t sampleInfo;
  2861. directlight_t *dl;
  2862. Vector spot;
  2863. Vector v[4], n[4];
  2864. if( g_bInterrupt )
  2865. return;
  2866. // FIXME: Is there a better way to do this? Like, in RunThreadsOn, for instance?
  2867. // Don't pay this cost unless we have to; this is super perf-critical code.
  2868. if (g_pIncremental)
  2869. {
  2870. // Both threads will be accessing this so it needs to be protected or else thread A
  2871. // will load it in and thread B will increment it but its increment will be
  2872. // overwritten by thread A when thread A writes it back.
  2873. ThreadLock();
  2874. ++g_iCurFace;
  2875. ThreadUnlock();
  2876. }
  2877. // some surfaces don't need lightmaps
  2878. f = &g_pFaces[facenum];
  2879. f->lightofs = -1;
  2880. for (j=0 ; j<MAXLIGHTMAPS ; j++)
  2881. f->styles[j] = 255;
  2882. // Trivial-reject the whole face?
  2883. if( !( g_FacesVisibleToLights[facenum>>3] & (1 << (facenum & 7)) ) )
  2884. return;
  2885. if ( texinfo[f->texinfo].flags & TEX_SPECIAL)
  2886. return; // non-lit texture
  2887. // check for patches for this face. If none it must be degenerate. Ignore.
  2888. if( g_FacePatches.Element( facenum ) == g_FacePatches.InvalidIndex() )
  2889. return;
  2890. fl = &facelight[facenum];
  2891. InitLightinfo( &l, facenum );
  2892. CalcPoints( &l, fl, facenum );
  2893. InitSampleInfo( l, iThread, sampleInfo );
  2894. // Allocate sample positions/normals to SSE
  2895. int numGroups = ( fl->numsamples & 0x3) ? ( fl->numsamples / 4 ) + 1 : ( fl->numsamples / 4 );
  2896. // always allocate style 0 lightmap
  2897. f->styles[0] = 0;
  2898. AllocateLightstyleSamples( fl, 0, sampleInfo.m_NormalCount );
  2899. // sample the lights at each sample location
  2900. for ( int grp = 0; grp < numGroups; ++grp )
  2901. {
  2902. int nSample = 4 * grp;
  2903. sample_t *sample = sampleInfo.m_pFaceLight->sample + nSample;
  2904. int numSamples = min ( 4, sampleInfo.m_pFaceLight->numsamples - nSample );
  2905. FourVectors positions;
  2906. FourVectors normals;
  2907. for ( i = 0; i < 4; i++ )
  2908. {
  2909. v[i] = ( i < numSamples ) ? sample[i].pos : sample[numSamples - 1].pos;
  2910. n[i] = ( i < numSamples ) ? sample[i].normal : sample[numSamples - 1].normal;
  2911. }
  2912. positions.LoadAndSwizzle( v[0], v[1], v[2], v[3] );
  2913. normals.LoadAndSwizzle( n[0], n[1], n[2], n[3] );
  2914. ComputeIlluminationPointAndNormalsSSE( l, positions, normals, &sampleInfo, numSamples );
  2915. // Fixup sample normals in case of smooth faces
  2916. if ( !l.isflat )
  2917. {
  2918. for ( i = 0; i < numSamples; i++ )
  2919. sample[i].normal = sampleInfo.m_PointNormals[0].Vec( i );
  2920. }
  2921. // Iterate over all the lights and add their contribution to this group of spots
  2922. GatherSampleLightAt4Points( sampleInfo, nSample, numSamples );
  2923. }
  2924. // Tell the incremental light manager that we're done with this face.
  2925. if( g_pIncremental )
  2926. {
  2927. for (dl = activelights; dl != NULL; dl = dl->next)
  2928. {
  2929. // Only deal with lightstyle 0 for incremental lighting
  2930. if (dl->light.style == 0)
  2931. g_pIncremental->FinishFace( dl->m_IncrementalID, facenum, iThread );
  2932. }
  2933. // Don't have to deal with patch lights (only direct lighting is used)
  2934. // or supersampling
  2935. return;
  2936. }
  2937. // Enabling supersampling for displacements (previous revision always disabled do_extra for disp)
  2938. // improves continuity significantly between disp and brush surfaces, especially when using high frequency alpha shadow materials
  2939. if ( do_extra )
  2940. {
  2941. // For each lightstyle, perform a supersampling pass
  2942. for ( i = 0; i < MAXLIGHTMAPS; ++i )
  2943. {
  2944. // Stop when we run out of lightstyles
  2945. if (f->styles[i] == 255)
  2946. break;
  2947. BuildSupersampleFaceLights( l, sampleInfo, i );
  2948. }
  2949. }
  2950. if (!g_bUseMPI)
  2951. {
  2952. //
  2953. // This is done on the master node when MPI is used
  2954. //
  2955. BuildPatchLights( facenum );
  2956. }
  2957. if( g_bDumpPatches )
  2958. {
  2959. DumpSamples( facenum, fl );
  2960. }
  2961. else
  2962. {
  2963. FreeSampleWindings( fl );
  2964. }
  2965. }
  2966. void BuildPatchLights( int facenum )
  2967. {
  2968. int i, k;
  2969. CPatch *patch;
  2970. dface_t *f = &g_pFaces[facenum];
  2971. facelight_t *fl = &facelight[facenum];
  2972. for( k = 0; k < MAXLIGHTMAPS; k++ )
  2973. {
  2974. if (f->styles[k] == 0)
  2975. break;
  2976. }
  2977. if (k >= MAXLIGHTMAPS)
  2978. return;
  2979. for (i = 0; i < fl->numsamples; i++)
  2980. {
  2981. AddSampleToPatch( &fl->sample[i], fl->light[k][0][i], facenum);
  2982. }
  2983. // check for a valid face
  2984. if( g_FacePatches.Element( facenum ) == g_FacePatches.InvalidIndex() )
  2985. return;
  2986. // push up sampled light to parents (children always exist first in the list)
  2987. CPatch *pNextPatch;
  2988. for( patch = &g_Patches.Element( g_FacePatches.Element( facenum ) ); patch; patch = pNextPatch )
  2989. {
  2990. // next patch
  2991. pNextPatch = NULL;
  2992. if( patch->ndxNext != g_Patches.InvalidIndex() )
  2993. {
  2994. pNextPatch = &g_Patches.Element( patch->ndxNext );
  2995. }
  2996. // skip patches without parents
  2997. if( patch->parent == g_Patches.InvalidIndex() )
  2998. // if (patch->parent == -1)
  2999. continue;
  3000. CPatch *parent = &g_Patches.Element( patch->parent );
  3001. parent->samplearea += patch->samplearea;
  3002. VectorAdd( parent->samplelight, patch->samplelight, parent->samplelight );
  3003. }
  3004. // average up the direct light on each patch for radiosity
  3005. if (numbounce > 0)
  3006. {
  3007. for( patch = &g_Patches.Element( g_FacePatches.Element( facenum ) ); patch; patch = pNextPatch )
  3008. {
  3009. // next patch
  3010. pNextPatch = NULL;
  3011. if( patch->ndxNext != g_Patches.InvalidIndex() )
  3012. {
  3013. pNextPatch = &g_Patches.Element( patch->ndxNext );
  3014. }
  3015. if (patch->samplearea)
  3016. {
  3017. float scale;
  3018. Vector v;
  3019. scale = 1.0 / patch->samplearea;
  3020. VectorScale( patch->samplelight, scale, v );
  3021. VectorAdd( patch->totallight.light[0], v, patch->totallight.light[0] );
  3022. VectorAdd( patch->directlight, v, patch->directlight );
  3023. }
  3024. }
  3025. }
  3026. // pull totallight from children (children always exist first in the list)
  3027. for( patch = &g_Patches.Element( g_FacePatches.Element( facenum ) ); patch; patch = pNextPatch )
  3028. {
  3029. // next patch
  3030. pNextPatch = NULL;
  3031. if( patch->ndxNext != g_Patches.InvalidIndex() )
  3032. {
  3033. pNextPatch = &g_Patches.Element( patch->ndxNext );
  3034. }
  3035. if ( patch->child1 != g_Patches.InvalidIndex() )
  3036. {
  3037. float s1, s2;
  3038. CPatch *child1;
  3039. CPatch *child2;
  3040. child1 = &g_Patches.Element( patch->child1 );
  3041. child2 = &g_Patches.Element( patch->child2 );
  3042. s1 = child1->area / (child1->area + child2->area);
  3043. s2 = child2->area / (child1->area + child2->area);
  3044. VectorScale( child1->totallight.light[0], s1, patch->totallight.light[0] );
  3045. VectorMA( patch->totallight.light[0], s2, child2->totallight.light[0], patch->totallight.light[0] );
  3046. VectorCopy( patch->totallight.light[0], patch->directlight );
  3047. }
  3048. }
  3049. bool needsBumpmap = false;
  3050. if( texinfo[f->texinfo].flags & SURF_BUMPLIGHT )
  3051. {
  3052. needsBumpmap = true;
  3053. }
  3054. // add an ambient term if desired
  3055. if (ambient[0] || ambient[1] || ambient[2])
  3056. {
  3057. for( int j=0; j < MAXLIGHTMAPS && f->styles[j] != 255; j++ )
  3058. {
  3059. if ( f->styles[j] == 0 )
  3060. {
  3061. for (i = 0; i < fl->numsamples; i++)
  3062. {
  3063. fl->light[j][0][i].m_vecLighting += ambient;
  3064. if( needsBumpmap )
  3065. {
  3066. fl->light[j][1][i].m_vecLighting += ambient;
  3067. fl->light[j][2][i].m_vecLighting += ambient;
  3068. fl->light[j][3][i].m_vecLighting += ambient;
  3069. }
  3070. }
  3071. break;
  3072. }
  3073. }
  3074. }
  3075. // light from dlight_threshold and above is sent out, but the
  3076. // texture itself should still be full bright
  3077. #if 0
  3078. // if( VectorAvg( g_FacePatches[facenum]->baselight ) >= dlight_threshold) // Now all lighted surfaces glow
  3079. {
  3080. for( j=0; j < MAXLIGHTMAPS && f->styles[j] != 255; j++ )
  3081. {
  3082. if ( f->styles[j] == 0 )
  3083. {
  3084. // BUG: shouldn't this be done for all patches on the face?
  3085. for (i=0 ; i<fl->numsamples ; i++)
  3086. {
  3087. // garymctchange
  3088. VectorAdd( fl->light[j][0][i], g_FacePatches[facenum]->baselight, fl->light[j][0][i] );
  3089. if( needsBumpmap )
  3090. {
  3091. for( bumpSample = 1; bumpSample < NUM_BUMP_VECTS + 1; bumpSample++ )
  3092. {
  3093. VectorAdd( fl->light[j][bumpSample][i], g_FacePatches[facenum]->baselight, fl->light[j][bumpSample][i] );
  3094. }
  3095. }
  3096. }
  3097. break;
  3098. }
  3099. }
  3100. }
  3101. #endif
  3102. }
  3103. void BuildStaticPropPatchlights( int iThread, int nPatch )
  3104. {
  3105. if ( g_Patches[ nPatch ].faceNumber >= 0 )
  3106. {
  3107. // Not a static prop patch
  3108. return;
  3109. }
  3110. CPatch &patch = g_Patches[ nPatch ];
  3111. // Random sample locations
  3112. Vector vecOrigin = patch.winding->p[ 0 ];
  3113. Vector vecU = patch.winding->p[ 2 ] - patch.winding->p[ 0 ];
  3114. Vector vecV = patch.winding->p[ 1 ] - patch.winding->p[ 0 ];
  3115. int nSampleCount = Max( 1, int( patch.area / 16.0f ) );
  3116. float flSampleArea = patch.area / float( nSampleCount );
  3117. float flSampleFrac = 1.0f / float( nSampleCount );
  3118. sample_t *pSamples = new sample_t[ nSampleCount ];
  3119. memset( pSamples, 0, sizeof( sample_t )*nSampleCount );
  3120. for ( int i = 0; i < nSampleCount; i++ )
  3121. {
  3122. // Shitty. Should be jittered instead or some other better distribution over the triangle.
  3123. float flU = RandomFloat();
  3124. float flV = RandomFloat();
  3125. if ( flU + flV > 1.0f )
  3126. {
  3127. flU = 1.0f - flU;
  3128. flV = 1.0f - flV;
  3129. Swap( flU, flV );
  3130. }
  3131. pSamples[ i ].pos = vecOrigin + flU * vecU + flV * vecV;
  3132. pSamples[ i ].normal = patch.normal;
  3133. pSamples[ i ].area = flSampleArea;
  3134. }
  3135. Vector directColor( 0.0f, 0.0f, 0.0f );
  3136. float flSunAmount = 0.0f;
  3137. // sample the lights at each sample location
  3138. for ( int i = 0; i < nSampleCount; i++ )
  3139. {
  3140. sample_t *sample = pSamples + i;
  3141. directColor.Init( 0.0f, 0.0f, 0.0f );
  3142. flSunAmount = 0.0f;
  3143. ComputeDirectLightingAtPoint( sample->pos, &sample->normal, &directColor, &flSunAmount, 1, false, iThread, -1, 0 );
  3144. directColor *= g_flStaticPropBounceBoost;
  3145. patch.totallight.light[ 0 ] += directColor * flSampleFrac;
  3146. patch.directlight += directColor * flSampleFrac;
  3147. }
  3148. delete[] pSamples;
  3149. }
  3150. /*
  3151. =============
  3152. PrecompLightmapOffsets
  3153. =============
  3154. */
  3155. void PrecompLightmapOffsets()
  3156. {
  3157. int facenum;
  3158. dface_t *f;
  3159. int lightstyles;
  3160. int lightdatasize = 0;
  3161. // NOTE: We store avg face light data in this lump *before* the lightmap data itself
  3162. // in *reverse order* of the way the lightstyles appear in the styles array.
  3163. for( facenum = 0; facenum < numfaces; facenum++ )
  3164. {
  3165. f = &g_pFaces[facenum];
  3166. if ( texinfo[f->texinfo].flags & TEX_SPECIAL)
  3167. continue; // non-lit texture
  3168. if ( dlight_map != 0 )
  3169. f->styles[1] = 0;
  3170. for (lightstyles=0; lightstyles < MAXLIGHTMAPS; lightstyles++ )
  3171. {
  3172. if ( f->styles[lightstyles] == 255 )
  3173. break;
  3174. }
  3175. if ( !lightstyles )
  3176. continue;
  3177. // Reserve room for the avg light color data
  3178. lightdatasize += lightstyles * 4;
  3179. f->lightofs = lightdatasize;
  3180. bool needsBumpmap = false;
  3181. if( texinfo[f->texinfo].flags & SURF_BUMPLIGHT )
  3182. {
  3183. needsBumpmap = true;
  3184. }
  3185. int nLuxels = (f->m_LightmapTextureSizeInLuxels[0]+1) * (f->m_LightmapTextureSizeInLuxels[1]+1);
  3186. if( needsBumpmap )
  3187. {
  3188. lightdatasize += nLuxels * 4 * lightstyles * ( NUM_BUMP_VECTS + 1 );
  3189. }
  3190. else
  3191. {
  3192. lightdatasize += nLuxels * 4 * lightstyles;
  3193. }
  3194. // Add room for additional light data here that will be packed into lightmap alpha
  3195. lightdatasize += nLuxels * 4 * lightstyles;
  3196. }
  3197. // The incremental lighting code needs us to preserve the contents of dlightdata
  3198. // since it only recomposites lighting for faces that have lights that touch them.
  3199. if( g_pIncremental && pdlightdata->Count() )
  3200. return;
  3201. pdlightdata->SetSize( lightdatasize );
  3202. }
  3203. // Clamp the three values for bumped lighting such that we trade off directionality for brightness.
  3204. static void ColorClampBumped( Vector& color1, Vector& color2, Vector& color3 )
  3205. {
  3206. Vector maxs;
  3207. Vector *colors[3] = { &color1, &color2, &color3 };
  3208. maxs[0] = VectorMaximum( color1 );
  3209. maxs[1] = VectorMaximum( color2 );
  3210. maxs[2] = VectorMaximum( color3 );
  3211. // HACK! Clean this up, and add some else statements
  3212. #define CONDITION(a,b,c) do { if( maxs[a] >= maxs[b] && maxs[b] >= maxs[c] ) { order[0] = a; order[1] = b; order[2] = c; } } while( 0 )
  3213. int order[3];
  3214. CONDITION(0,1,2);
  3215. CONDITION(0,2,1);
  3216. CONDITION(1,0,2);
  3217. CONDITION(1,2,0);
  3218. CONDITION(2,0,1);
  3219. CONDITION(2,1,0);
  3220. int i;
  3221. for( i = 0; i < 3; i++ )
  3222. {
  3223. float max = VectorMaximum( *colors[order[i]] );
  3224. if( max <= 1.0f )
  3225. {
  3226. continue;
  3227. }
  3228. // This channel is too bright. . take half of the amount that we are over and
  3229. // add it to the other two channel.
  3230. float factorToRedist = ( max - 1.0f ) / max;
  3231. Vector colorToRedist = factorToRedist * *colors[order[i]];
  3232. *colors[order[i]] -= colorToRedist;
  3233. colorToRedist *= 0.5f;
  3234. *colors[order[(i+1)%3]] += colorToRedist;
  3235. *colors[order[(i+2)%3]] += colorToRedist;
  3236. }
  3237. ColorClamp( color1 );
  3238. ColorClamp( color2 );
  3239. ColorClamp( color3 );
  3240. if( color1[0] < 0.f ) color1[0] = 0.f;
  3241. if( color1[1] < 0.f ) color1[1] = 0.f;
  3242. if( color1[2] < 0.f ) color1[2] = 0.f;
  3243. if( color2[0] < 0.f ) color2[0] = 0.f;
  3244. if( color2[1] < 0.f ) color2[1] = 0.f;
  3245. if( color2[2] < 0.f ) color2[2] = 0.f;
  3246. if( color3[0] < 0.f ) color3[0] = 0.f;
  3247. if( color3[1] < 0.f ) color3[1] = 0.f;
  3248. if( color3[2] < 0.f ) color3[2] = 0.f;
  3249. }
  3250. static void LinearToBumpedLightmap(
  3251. const float *linearColor,
  3252. const float *linearBumpColor1,
  3253. const float *linearBumpColor2,
  3254. const float *linearBumpColor3,
  3255. unsigned char *ret,
  3256. unsigned char *retBump1,
  3257. unsigned char *retBump2,
  3258. unsigned char *retBump3 )
  3259. {
  3260. const Vector &linearBump1 = *( ( const Vector * )linearBumpColor1 );
  3261. const Vector &linearBump2 = *( ( const Vector * )linearBumpColor2 );
  3262. const Vector &linearBump3 = *( ( const Vector * )linearBumpColor3 );
  3263. Vector gammaGoal;
  3264. // gammaGoal is premultiplied by 1/overbright, which we want
  3265. gammaGoal[0] = LinearToVertexLight( linearColor[0] );
  3266. gammaGoal[1] = LinearToVertexLight( linearColor[1] );
  3267. gammaGoal[2] = LinearToVertexLight( linearColor[2] );
  3268. Vector bumpAverage = linearBump1;
  3269. bumpAverage += linearBump2;
  3270. bumpAverage += linearBump3;
  3271. bumpAverage *= ( 1.0f / 3.0f );
  3272. Vector correctionScale;
  3273. if( *( int * )&bumpAverage[0] != 0 && *( int * )&bumpAverage[1] != 0 && *( int * )&bumpAverage[2] != 0 )
  3274. {
  3275. // fast path when we know that we don't have to worry about divide by zero.
  3276. VectorDivide( gammaGoal, bumpAverage, correctionScale );
  3277. // correctionScale = gammaGoal / bumpSum;
  3278. }
  3279. else
  3280. {
  3281. correctionScale.Init( 0.0f, 0.0f, 0.0f );
  3282. if( bumpAverage[0] != 0.0f )
  3283. {
  3284. correctionScale[0] = gammaGoal[0] / bumpAverage[0];
  3285. }
  3286. if( bumpAverage[1] != 0.0f )
  3287. {
  3288. correctionScale[1] = gammaGoal[1] / bumpAverage[1];
  3289. }
  3290. if( bumpAverage[2] != 0.0f )
  3291. {
  3292. correctionScale[2] = gammaGoal[2] / bumpAverage[2];
  3293. }
  3294. }
  3295. Vector correctedBumpColor1;
  3296. Vector correctedBumpColor2;
  3297. Vector correctedBumpColor3;
  3298. VectorMultiply( linearBump1, correctionScale, correctedBumpColor1 );
  3299. VectorMultiply( linearBump2, correctionScale, correctedBumpColor2 );
  3300. VectorMultiply( linearBump3, correctionScale, correctedBumpColor3 );
  3301. Vector check = ( correctedBumpColor1 + correctedBumpColor2 + correctedBumpColor3 ) / 3.0f;
  3302. ColorClampBumped( correctedBumpColor1, correctedBumpColor2, correctedBumpColor3 );
  3303. ret[0] = RoundFloatToByte( gammaGoal[0] * 255.0f );
  3304. ret[1] = RoundFloatToByte( gammaGoal[1] * 255.0f );
  3305. ret[2] = RoundFloatToByte( gammaGoal[2] * 255.0f );
  3306. retBump1[0] = RoundFloatToByte( correctedBumpColor1[0] * 255.0f );
  3307. retBump1[1] = RoundFloatToByte( correctedBumpColor1[1] * 255.0f );
  3308. retBump1[2] = RoundFloatToByte( correctedBumpColor1[2] * 255.0f );
  3309. retBump2[0] = RoundFloatToByte( correctedBumpColor2[0] * 255.0f );
  3310. retBump2[1] = RoundFloatToByte( correctedBumpColor2[1] * 255.0f );
  3311. retBump2[2] = RoundFloatToByte( correctedBumpColor2[2] * 255.0f );
  3312. retBump3[0] = RoundFloatToByte( correctedBumpColor3[0] * 255.0f );
  3313. retBump3[1] = RoundFloatToByte( correctedBumpColor3[1] * 255.0f );
  3314. retBump3[2] = RoundFloatToByte( correctedBumpColor3[2] * 255.0f );
  3315. }
  3316. //-----------------------------------------------------------------------------
  3317. // Convert a RGBExp32 to a RGBA8888
  3318. // This matches the engine's conversion, so the lighting result is consistent.
  3319. //-----------------------------------------------------------------------------
  3320. void ConvertRGBExp32ToRGBA8888( const ColorRGBExp32 *pSrc, unsigned char *pDst )
  3321. {
  3322. Vector linearColor;
  3323. Vector vertexColor;
  3324. // convert from ColorRGBExp32 to linear space
  3325. linearColor[0] = TexLightToLinear( ((ColorRGBExp32 *)pSrc)->r, ((ColorRGBExp32 *)pSrc)->exponent );
  3326. linearColor[1] = TexLightToLinear( ((ColorRGBExp32 *)pSrc)->g, ((ColorRGBExp32 *)pSrc)->exponent );
  3327. linearColor[2] = TexLightToLinear( ((ColorRGBExp32 *)pSrc)->b, ((ColorRGBExp32 *)pSrc)->exponent );
  3328. // convert from linear space to lightmap space
  3329. // cannot use mathlib routine directly because it doesn't match
  3330. // the colorspace version found in the engine, which *is* the same sequence here
  3331. vertexColor[0] = LinearToVertexLight( linearColor[0] );
  3332. vertexColor[1] = LinearToVertexLight( linearColor[1] );
  3333. vertexColor[2] = LinearToVertexLight( linearColor[2] );
  3334. // this is really a color normalization with a floor
  3335. ColorClamp( vertexColor );
  3336. // final [0..255] scale
  3337. pDst[0] = RoundFloatToByte( vertexColor[0] * 255.0f );
  3338. pDst[1] = RoundFloatToByte( vertexColor[1] * 255.0f );
  3339. pDst[2] = RoundFloatToByte( vertexColor[2] * 255.0f );
  3340. pDst[3] = 255;
  3341. }