Team Fortress 2 Source Code as on 22/4/2020
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.

864 lines
25 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: The thread which performs lighting preview
  4. //
  5. //===========================================================================//
  6. #include "stdafx.h"
  7. #include "lpreview_thread.h"
  8. #include "mathlib/simdvectormatrix.h"
  9. #include "raytrace.h"
  10. #include "hammer.h"
  11. #include "mainfrm.h"
  12. #include "lprvwindow.h"
  13. // memdbgon must be the last include file in a .cpp file!!!
  14. #include <tier0/memdbgon.h>
  15. CInterlockedInt n_gbufs_queued;
  16. CInterlockedInt n_result_bms_queued;
  17. // the current lighting preview output, if we have one
  18. Bitmap_t *g_pLPreviewOutputBitmap;
  19. enum IncrementalLightState
  20. {
  21. INCR_STATE_NO_RESULTS=0, // we threw away the results for this light
  22. INCR_STATE_PARTIAL_RESULTS=1, // have done some but not all
  23. INCR_STATE_NEW=2, // we know nothing about this light
  24. INCR_STATE_HAVE_FULL_RESULTS=3, // we are done
  25. };
  26. class CLightingPreviewThread;
  27. class CIncrementalLightInfo
  28. {
  29. public:
  30. CIncrementalLightInfo *m_pNext;
  31. CLightingPreviewLightDescription *m_pLight;
  32. // incremental lighting tracking information
  33. int m_nObjectID;
  34. int m_PartialResultsStage;
  35. IncrementalLightState m_eIncrState;
  36. CSIMDVectorMatrix m_CalculatedContribution;
  37. float m_fTotalContribution; // current magnitude of light effect
  38. int m_nBitmapGenerationCounter; // set on receive of new data from master
  39. float m_fDistanceToEye;
  40. int m_nMostRecentNonZeroContributionTimeStamp;
  41. CIncrementalLightInfo( void )
  42. {
  43. m_nObjectID = -1;
  44. m_pNext = NULL;
  45. m_eIncrState = INCR_STATE_NEW;
  46. m_fTotalContribution = 0.;
  47. m_PartialResultsStage = 0;
  48. m_nMostRecentNonZeroContributionTimeStamp = 0;
  49. }
  50. void DiscardResults( void )
  51. {
  52. m_CalculatedContribution.SetSize(0,0);
  53. if ( m_eIncrState != INCR_STATE_NEW )
  54. m_eIncrState = INCR_STATE_NO_RESULTS;
  55. }
  56. void ClearIncremental( void )
  57. {
  58. m_eIncrState = INCR_STATE_NEW;
  59. // free calculated lighting matrix
  60. DiscardResults();
  61. }
  62. bool HasWorkToDo( void ) const
  63. {
  64. return ( m_eIncrState != INCR_STATE_HAVE_FULL_RESULTS );
  65. }
  66. bool IsLowerPriorityThan( CLightingPreviewThread *pLPV,
  67. CIncrementalLightInfo const &other ) const;
  68. bool IsHighPriority( CLightingPreviewThread *pLPV ) const;
  69. };
  70. #define N_INCREMENTAL_STEPS 32
  71. class CLightingPreviewThread
  72. {
  73. public:
  74. CUtlVector<CLightingPreviewLightDescription> *m_pLightList;
  75. CSIMDVectorMatrix m_Positions;
  76. CSIMDVectorMatrix m_Normals;
  77. CSIMDVectorMatrix m_Albedos;
  78. CSIMDVectorMatrix m_ResultImage;
  79. RayTracingEnvironment *m_pRtEnv;
  80. CIncrementalLightInfo *m_pIncrementalLightInfoList;
  81. bool m_bAccStructureBuilt;
  82. Vector m_LastEyePosition;
  83. bool m_bResultChangedSinceLastSend;
  84. float m_fLastSendTime;
  85. int m_LineMask[N_INCREMENTAL_STEPS];
  86. int m_ClosestLineOffset[N_INCREMENTAL_STEPS][N_INCREMENTAL_STEPS];
  87. int m_nBitmapGenerationCounter;
  88. int m_nContributionCounter;
  89. // bounidng box of the rendered scene+ the eye
  90. Vector m_MinViewCoords;
  91. Vector m_MaxViewCoords;
  92. CLightingPreviewThread(void)
  93. {
  94. m_nBitmapGenerationCounter = -1;
  95. m_pLightList = NULL;
  96. m_pRtEnv = NULL;
  97. m_bAccStructureBuilt = false;
  98. m_pIncrementalLightInfoList = NULL;
  99. m_fLastSendTime = -1.0e6;
  100. m_bResultChangedSinceLastSend = false;
  101. m_nContributionCounter = 1000000;
  102. InitIncrementalInformation();
  103. }
  104. void InitIncrementalInformation( void );
  105. ~CLightingPreviewThread( void )
  106. {
  107. if ( m_pLightList )
  108. delete m_pLightList;
  109. while ( m_pIncrementalLightInfoList )
  110. {
  111. CIncrementalLightInfo *n=m_pIncrementalLightInfoList->m_pNext;
  112. delete m_pIncrementalLightInfoList;
  113. m_pIncrementalLightInfoList = n;
  114. }
  115. }
  116. // check if the master has new work for us to do, meaning we should abort rendering
  117. bool ShouldAbort( void )
  118. {
  119. return g_HammerToLPreviewMsgQueue.MessageWaiting();
  120. }
  121. // main loop
  122. void Run(void);
  123. // handle new g-buffers from master
  124. void HandleGBuffersMessage( MessageToLPreview &msg_in );
  125. // accept triangle list from master
  126. void HandleGeomMessage( MessageToLPreview &msg_in );
  127. // send one of our output images back
  128. void SendVectorMatrixAsRendering( CSIMDVectorMatrix const &src );
  129. // calculate m_MinViewCoords, m_MaxViewCoords - the bounding box of the rendered pixels+the eye
  130. void CalculateSceneBounds( void );
  131. // inner lighting loop. meant to be multithreaded on dual-core (or more)
  132. void CalculateForLightTask( int nLineMask, int nLineMatch,
  133. CLightingPreviewLightDescription &l,
  134. int calc_mask,
  135. float *fContributionOut );
  136. void CalculateForLight( CLightingPreviewLightDescription &l );
  137. // send our current output back
  138. void SendResult( void );
  139. void UpdateIncrementalForNewLightList( void );
  140. void DiscardResults( void )
  141. {
  142. // invalidate all per light result data
  143. for( CIncrementalLightInfo *i=m_pIncrementalLightInfoList; i; i=i->m_pNext)
  144. {
  145. i->DiscardResults();
  146. }
  147. // bump time stamp
  148. m_nContributionCounter++;
  149. // update distances to lights
  150. if ( m_pLightList )
  151. for(int i=0;i<m_pLightList->Count();i++)
  152. {
  153. CLightingPreviewLightDescription &l=(*m_pLightList)[i];
  154. CIncrementalLightInfo *l_info=l.m_pIncrementalInfo;
  155. if ( l.m_Type == MATERIAL_LIGHT_DIRECTIONAL )
  156. l_info->m_fDistanceToEye = 0; // high priority
  157. else
  158. l_info->m_fDistanceToEye = m_LastEyePosition.DistTo( l.m_Position );
  159. }
  160. m_bResultChangedSinceLastSend = true;
  161. m_fLastSendTime = Plat_FloatTime()-9; // force send
  162. }
  163. // handle a message. returns true if the thread shuold exit
  164. bool HandleAMessage( void );
  165. // returns whether or not there is useful work to do
  166. bool AnyUsefulWorkToDo( void );
  167. // do some work, like a rendering for one light
  168. void DoWork(void);
  169. Vector EstimatedUnshotAmbient( void )
  170. {
  171. // return Vector( 1,1,1 );
  172. float sum_weights=0.0001;
  173. Vector sum_colors( sum_weights, sum_weights, sum_weights);
  174. // calculate an ambient color based on light calculcated so far
  175. if ( m_pLightList )
  176. for(int i=0;i<m_pLightList->Count();i++)
  177. {
  178. CLightingPreviewLightDescription &l=(*m_pLightList)[i];
  179. CIncrementalLightInfo *l_info=l.m_pIncrementalInfo;
  180. if ( l_info &&
  181. ( l_info->m_eIncrState==INCR_STATE_HAVE_FULL_RESULTS ) ||
  182. ( l_info->m_eIncrState==INCR_STATE_PARTIAL_RESULTS) )
  183. {
  184. sum_weights+=l_info->m_fTotalContribution;
  185. sum_colors.x+=l_info->m_fTotalContribution*l.m_Color.x;
  186. sum_colors.y+=l_info->m_fTotalContribution*l.m_Color.y;
  187. sum_colors.z+=l_info->m_fTotalContribution*l.m_Color.z;
  188. }
  189. }
  190. sum_colors.NormalizeInPlace();
  191. sum_colors *= 0.05;
  192. return sum_colors;
  193. }
  194. };
  195. bool CIncrementalLightInfo::IsHighPriority( CLightingPreviewThread *pLPV ) const
  196. {
  197. // is this lighjt prioirty-boosted in some way?
  198. if ( m_eIncrState == INCR_STATE_NEW )
  199. {
  200. // uncalculated lights within the view range are highest priority
  201. if ( m_pLight->m_Position.WithinAABox( pLPV->m_MinViewCoords,
  202. pLPV->m_MaxViewCoords ) )
  203. return true;
  204. }
  205. return false;
  206. }
  207. bool CIncrementalLightInfo::IsLowerPriorityThan( CLightingPreviewThread *pLPV,
  208. CIncrementalLightInfo const &other ) const
  209. {
  210. // a NEW light within the view volume is highest priority
  211. bool highpriority=IsHighPriority( pLPV );
  212. bool other_highpriority=other.IsHighPriority( pLPV );
  213. if ( highpriority && (! other_highpriority ) )
  214. return false;
  215. if ( other_highpriority && (! highpriority ) )
  216. return true;
  217. int state_combo = m_eIncrState + 16*other.m_eIncrState;
  218. switch ( state_combo )
  219. {
  220. case INCR_STATE_NEW+16*INCR_STATE_NEW:
  221. {
  222. // if both are new, closest to eye is best
  223. return ( m_fDistanceToEye > other.m_fDistanceToEye );
  224. }
  225. case INCR_STATE_NEW+16*INCR_STATE_NO_RESULTS:
  226. {
  227. // new loses to something we know is probably going to contribute light
  228. return ( other.m_fTotalContribution > 0 );
  229. }
  230. case INCR_STATE_NEW+16*INCR_STATE_PARTIAL_RESULTS:
  231. {
  232. return false;
  233. }
  234. case INCR_STATE_PARTIAL_RESULTS+16*INCR_STATE_NEW:
  235. {
  236. return true;
  237. }
  238. case INCR_STATE_NO_RESULTS+16*INCR_STATE_NEW:
  239. {
  240. // partial or discarded with no brightness loses to new
  241. return ( m_fTotalContribution == 0 );
  242. }
  243. case INCR_STATE_PARTIAL_RESULTS+16*INCR_STATE_PARTIAL_RESULTS:
  244. {
  245. // if incrmental vs incremental, and no light from either, do most recently lit one
  246. if (( m_fTotalContribution == 0.0) && (other.m_fTotalContribution == 0.0) &&
  247. ( other.m_nMostRecentNonZeroContributionTimeStamp > m_nMostRecentNonZeroContributionTimeStamp ) )
  248. return true;
  249. // if other is black, keep this one
  250. if ( (other.m_fTotalContribution == 0.0) && (m_fTotalContribution >0 ) )
  251. return false;
  252. if ( (m_fTotalContribution == 0.0) && (other.m_fTotalContribution >0 ) )
  253. return true;
  254. // if incremental states are close, do brightest
  255. if ( abs( m_PartialResultsStage-other.m_PartialResultsStage)<=1 )
  256. return ( m_fTotalContribution < other.m_fTotalContribution );
  257. // else do least refined
  258. return ( m_PartialResultsStage > other.m_PartialResultsStage );
  259. }
  260. case INCR_STATE_PARTIAL_RESULTS+16*INCR_STATE_NO_RESULTS:
  261. {
  262. if ( other.m_fTotalContribution )
  263. return true;
  264. if (( m_fTotalContribution == 0.0) && (other.m_fTotalContribution == 0.0) )
  265. return ( other.m_nMostRecentNonZeroContributionTimeStamp > m_nMostRecentNonZeroContributionTimeStamp );
  266. return ( m_fTotalContribution < other.m_fTotalContribution );
  267. }
  268. case INCR_STATE_NO_RESULTS+16*INCR_STATE_PARTIAL_RESULTS:
  269. {
  270. if ( m_fTotalContribution )
  271. return false;
  272. if (( m_fTotalContribution == 0.0) && (other.m_fTotalContribution == 0.0) )
  273. return ( other.m_nMostRecentNonZeroContributionTimeStamp > m_nMostRecentNonZeroContributionTimeStamp );
  274. return ( m_fTotalContribution < other.m_fTotalContribution );
  275. }
  276. case INCR_STATE_NO_RESULTS*16+INCR_STATE_NO_RESULTS:
  277. {
  278. // if incrmental vs discarded, brightest or most recently bright wins
  279. if (( m_fTotalContribution == 0.0) && (other.m_fTotalContribution == 0.0) )
  280. return ( other.m_nMostRecentNonZeroContributionTimeStamp > m_nMostRecentNonZeroContributionTimeStamp );
  281. return ( m_fTotalContribution < other.m_fTotalContribution );
  282. }
  283. }
  284. return false;
  285. }
  286. void CLightingPreviewThread::InitIncrementalInformation( void )
  287. {
  288. int calculated_bit_mask=0;
  289. for(int i=0;i<N_INCREMENTAL_STEPS;i++)
  290. {
  291. // bit reverse i
  292. int msk=0;
  293. int msk_or=1;
  294. int msk_test=(N_INCREMENTAL_STEPS >> 1);
  295. while( msk_test )
  296. {
  297. if ( i & msk_test )
  298. msk |= msk_or;
  299. msk_or <<= 1;
  300. msk_test >>= 1;
  301. }
  302. calculated_bit_mask |= (1<< msk);
  303. m_LineMask[i] = calculated_bit_mask;
  304. }
  305. // now, find which line to use when resampling a partial result
  306. for( int lvl=0; lvl < N_INCREMENTAL_STEPS; lvl++)
  307. {
  308. for(int linemod=0; linemod <=N_INCREMENTAL_STEPS; linemod++)
  309. {
  310. int closest_line=1000000;
  311. for( int chk=0; chk <= linemod; chk++)
  312. if ( m_LineMask[lvl] & ( 1 << chk ))
  313. {
  314. if (abs( chk-linemod ) < abs( closest_line-linemod ) )
  315. closest_line = chk;
  316. }
  317. m_ClosestLineOffset[lvl][linemod] = closest_line;
  318. }
  319. }
  320. }
  321. float cg[3]={ 1,0,0};
  322. float cr[3]={ 0,1,0 };
  323. float cb[3]={ 0,0,1 };
  324. void CLightingPreviewThread::HandleGeomMessage( MessageToLPreview &msg_in )
  325. {
  326. if (m_pRtEnv)
  327. {
  328. delete m_pRtEnv;
  329. m_pRtEnv = NULL;
  330. }
  331. CUtlVector<Vector> &tris=*( msg_in.m_pShadowTriangleList);
  332. if (tris.Count())
  333. {
  334. // FILE *fp = fopen( "c:\\gl.out", "w" );
  335. m_pRtEnv = new RayTracingEnvironment;
  336. for(int i=0;i<tris.Count();i+=3)
  337. {
  338. // fprintf(fp,"3\n");
  339. // for(int j=0;j<3;j++)
  340. // fprintf( fp,"%f %f %f %f %f %f\n", tris[j+i].x,tris[j+i].y,tris[j+i].z, cr[j],cg[j],cb[j] );
  341. m_pRtEnv->AddTriangle( i, tris[i],tris[1+i],tris[2+i], Vector( .5,.5,.5) );
  342. }
  343. // fclose( fp );
  344. }
  345. delete msg_in.m_pShadowTriangleList;
  346. m_bAccStructureBuilt = false;
  347. DiscardResults();
  348. }
  349. void CLightingPreviewThread::CalculateSceneBounds( void )
  350. {
  351. FourVectors minbound, maxbound;
  352. minbound.DuplicateVector( m_LastEyePosition );
  353. maxbound.DuplicateVector( m_LastEyePosition );
  354. for(int y=0;y<m_Positions.m_nHeight;y++)
  355. {
  356. FourVectors const *cptr= &(m_Positions.CompoundElement(0, y ) );
  357. for(int x=0; x<m_Positions.m_nPaddedWidth; x++)
  358. {
  359. minbound.x=MinSIMD( cptr->x, minbound.x);
  360. minbound.y=MinSIMD( cptr->y, minbound.y);
  361. minbound.z=MinSIMD( cptr->z, minbound.z);
  362. maxbound.x=MaxSIMD( cptr->x, maxbound.x);
  363. maxbound.y=MaxSIMD( cptr->y, maxbound.y);
  364. maxbound.z=MaxSIMD( cptr->z, maxbound.z);
  365. cptr++;
  366. }
  367. }
  368. m_MinViewCoords=minbound.Vec(0);
  369. m_MaxViewCoords=maxbound.Vec(0);
  370. for(int v=1; v<4; v++)
  371. {
  372. m_MinViewCoords=m_MinViewCoords.Min( minbound.Vec(v) );
  373. m_MaxViewCoords=m_MaxViewCoords.Max( maxbound.Vec(v) );
  374. }
  375. }
  376. void CLightingPreviewThread::UpdateIncrementalForNewLightList( void )
  377. {
  378. for( int iLight=0; iLight<m_pLightList->Count(); iLight++)
  379. {
  380. CLightingPreviewLightDescription &descr=(*m_pLightList)[iLight];
  381. // see if we know about this light
  382. for( CIncrementalLightInfo *i=m_pIncrementalLightInfoList; i; i=i->m_pNext)
  383. {
  384. if (i->m_nObjectID == descr.m_nObjectID )
  385. {
  386. // found it!
  387. descr.m_pIncrementalInfo = i;
  388. i->m_pLight = &descr;
  389. break;
  390. }
  391. }
  392. if ( ! descr.m_pIncrementalInfo )
  393. {
  394. descr.m_pIncrementalInfo = new CIncrementalLightInfo;
  395. descr.m_pIncrementalInfo->m_nObjectID = descr.m_nObjectID;
  396. descr.m_pIncrementalInfo->m_pLight = &descr;
  397. // add to list
  398. descr.m_pIncrementalInfo->m_pNext = m_pIncrementalLightInfoList;
  399. m_pIncrementalLightInfoList = descr.m_pIncrementalInfo;
  400. }
  401. }
  402. }
  403. void CLightingPreviewThread::Run(void)
  404. {
  405. bool should_quit = false;
  406. while(! should_quit )
  407. {
  408. while (
  409. (! should_quit ) &&
  410. ( (! AnyUsefulWorkToDo() ) || ( g_HammerToLPreviewMsgQueue.MessageWaiting() ) ) )
  411. should_quit |= HandleAMessage();
  412. if ( (! should_quit) && (AnyUsefulWorkToDo() ) )
  413. DoWork();
  414. if ( m_bResultChangedSinceLastSend )
  415. {
  416. float newtime=Plat_FloatTime();
  417. if ( (newtime-m_fLastSendTime > 10.0) || ( ! AnyUsefulWorkToDo() ) )
  418. {
  419. SendResult();
  420. m_bResultChangedSinceLastSend = false;
  421. m_fLastSendTime = newtime;
  422. }
  423. }
  424. }
  425. }
  426. bool CLightingPreviewThread::HandleAMessage( void )
  427. {
  428. MessageToLPreview msg_in;
  429. g_HammerToLPreviewMsgQueue.WaitMessage( &msg_in );
  430. switch( msg_in.m_MsgType)
  431. {
  432. case LPREVIEW_MSG_EXIT:
  433. return true; // return from thread
  434. case LPREVIEW_MSG_LIGHT_DATA:
  435. {
  436. if ( m_pLightList )
  437. delete m_pLightList;
  438. m_pLightList = msg_in.m_pLightList;
  439. m_LastEyePosition = msg_in.m_EyePosition;
  440. UpdateIncrementalForNewLightList();
  441. DiscardResults();
  442. }
  443. break;
  444. case LPREVIEW_MSG_GEOM_DATA:
  445. HandleGeomMessage( msg_in );
  446. DiscardResults();
  447. break;
  448. case LPREVIEW_MSG_G_BUFFERS:
  449. HandleGBuffersMessage( msg_in );
  450. DiscardResults();
  451. break;
  452. }
  453. return false;
  454. }
  455. bool CLightingPreviewThread::AnyUsefulWorkToDo( void )
  456. {
  457. if ( m_pLightList )
  458. {
  459. for(int i=0;i<m_pLightList->Count();i++)
  460. {
  461. CLightingPreviewLightDescription &l=(*m_pLightList)[i];
  462. CIncrementalLightInfo *l_info=l.m_pIncrementalInfo;
  463. if ( l_info->HasWorkToDo() )
  464. return true;
  465. }
  466. }
  467. return false;
  468. }
  469. void CLightingPreviewThread::DoWork( void )
  470. {
  471. if ( m_pLightList )
  472. {
  473. CLightingPreviewLightDescription *best_l=NULL;
  474. CIncrementalLightInfo *best_l_info=NULL;
  475. for(int i=0;i<m_pLightList->Count();i++)
  476. {
  477. CLightingPreviewLightDescription &l=(*m_pLightList)[i];
  478. CIncrementalLightInfo *l_info=l.m_pIncrementalInfo;
  479. if ( l_info->HasWorkToDo() )
  480. {
  481. if ( (! best_l) ||
  482. (best_l->m_pIncrementalInfo->IsLowerPriorityThan( this, *l_info )) )
  483. {
  484. best_l_info=l_info;
  485. best_l=&l;
  486. }
  487. }
  488. }
  489. if ( best_l )
  490. {
  491. CalculateForLight( *best_l );
  492. if ( best_l->m_pIncrementalInfo->m_fTotalContribution )
  493. {
  494. m_bResultChangedSinceLastSend = true;
  495. }
  496. return;
  497. }
  498. }
  499. }
  500. void CLightingPreviewThread::HandleGBuffersMessage( MessageToLPreview &msg_in )
  501. {
  502. m_Albedos.CreateFromRGBA_FloatImageData(
  503. msg_in.m_pDefferedRenderingBMs[0]->Width,msg_in.m_pDefferedRenderingBMs[0]->Height,
  504. msg_in.m_pDefferedRenderingBMs[0]->RGBAData);
  505. m_Normals.CreateFromRGBA_FloatImageData(
  506. msg_in.m_pDefferedRenderingBMs[1]->Width,msg_in.m_pDefferedRenderingBMs[1]->Height,
  507. msg_in.m_pDefferedRenderingBMs[1]->RGBAData);
  508. m_Positions.CreateFromRGBA_FloatImageData(
  509. msg_in.m_pDefferedRenderingBMs[2]->Width,msg_in.m_pDefferedRenderingBMs[2]->Height,
  510. msg_in.m_pDefferedRenderingBMs[2]->RGBAData);
  511. m_LastEyePosition = msg_in.m_EyePosition;
  512. for( int i = 0;i < ARRAYSIZE( msg_in.m_pDefferedRenderingBMs ); i++ )
  513. delete msg_in.m_pDefferedRenderingBMs[i];
  514. n_gbufs_queued--;
  515. m_nBitmapGenerationCounter = msg_in.m_nBitmapGenerationCounter;
  516. CalculateSceneBounds();
  517. }
  518. void CLightingPreviewThread::SendResult( void )
  519. {
  520. m_ResultImage = m_Albedos;
  521. m_ResultImage *= EstimatedUnshotAmbient();
  522. for( int i = 0 ; i < m_pLightList->Count(); i ++ )
  523. {
  524. CLightingPreviewLightDescription & l = ( *m_pLightList )[i];
  525. CIncrementalLightInfo * l_info = l.m_pIncrementalInfo;
  526. if ( ( l_info->m_fTotalContribution > 0.0 ) &&
  527. ( l_info->m_eIncrState >= INCR_STATE_PARTIAL_RESULTS ) )
  528. {
  529. // need to add partials, replicated to handle undone lines
  530. CSIMDVectorMatrix & src = l_info->m_CalculatedContribution;
  531. for( int y = 0;y < m_ResultImage.m_nHeight;y ++ )
  532. {
  533. int yo = y & ( N_INCREMENTAL_STEPS - 1 );
  534. int src_y = ( y & ~( N_INCREMENTAL_STEPS - 1 ))
  535. + m_ClosestLineOffset[l_info->m_PartialResultsStage][yo];
  536. FourVectors const * cptr = &( src.CompoundElement( 0, src_y ));
  537. FourVectors * dest =& ( m_ResultImage.CompoundElement( 0, y ));
  538. FourVectors const *pAlbedo =&( m_Albedos.CompoundElement( 0, y ));
  539. for( int x = 0;x < m_ResultImage.m_nPaddedWidth;x ++ )
  540. {
  541. FourVectors albedo_value = *( pAlbedo++ );
  542. albedo_value *= *( cptr++ );
  543. * ( dest++ ) += albedo_value;
  544. }
  545. }
  546. }
  547. }
  548. SendVectorMatrixAsRendering( m_ResultImage );
  549. m_fLastSendTime = Plat_FloatTime();
  550. m_bResultChangedSinceLastSend = false;
  551. }
  552. void CLightingPreviewThread::CalculateForLightTask( int nLineMask, int nLineMatch,
  553. CLightingPreviewLightDescription &l,
  554. int calc_mask,
  555. float *fContributionOut )
  556. {
  557. FourVectors zero_vector;
  558. zero_vector.x=Four_Zeros;
  559. zero_vector.y=Four_Zeros;
  560. zero_vector.z=Four_Zeros;
  561. FourVectors total_light=zero_vector;
  562. CIncrementalLightInfo *l_info=l.m_pIncrementalInfo;
  563. CSIMDVectorMatrix &rslt=l_info->m_CalculatedContribution;
  564. // figure out what lines to do
  565. fltx4 ThresholdBrightness=ReplicateX4( 0.1 / 1024.0 );
  566. FourVectors LastLinesTotalLight=zero_vector;
  567. int work_line_number=0; // for task masking
  568. for(int y=0;y<rslt.m_nHeight;y++)
  569. {
  570. FourVectors ThisLinesTotalLight=zero_vector;
  571. int ybit=(1<<(y & (N_INCREMENTAL_STEPS-1) ) );
  572. if ( (ybit & calc_mask)==0) // do this line?
  573. ThisLinesTotalLight=LastLinesTotalLight;
  574. else
  575. {
  576. if ( (work_line_number & nLineMatch) == nLineMatch)
  577. {
  578. for(int x=0;x<rslt.m_nPaddedWidth;x++)
  579. {
  580. // shadow check
  581. FourVectors pos=m_Positions.CompoundElement( x, y );
  582. FourVectors normal=m_Normals.CompoundElement( x, y );
  583. FourVectors l_add=zero_vector;
  584. l.ComputeLightAtPoints( pos, normal, l_add, false );
  585. fltx4 v_or=OrSIMD( l_add.x, OrSIMD( l_add.y, l_add.z ) );
  586. if ( ! IsAllZeros( v_or ) )
  587. {
  588. FourVectors lpos;
  589. lpos.DuplicateVector( l.m_Position );
  590. FourRays myray;
  591. myray.direction=lpos;
  592. myray.direction-=pos;
  593. fltx4 len=myray.direction.length();
  594. myray.direction *= ReciprocalSIMD( len );
  595. // slide towards light to avoid self-intersection
  596. myray.origin=myray.direction;
  597. myray.origin *= 0.02;
  598. myray.origin += pos;
  599. RayTracingResult r_rslt;
  600. m_pRtEnv->Trace4Rays( myray, Four_Zeros, ReplicateX4( 1.0e9 ), &r_rslt );
  601. for(int c=0;c<4;c++) // !!speed!! use sse logic ops here
  602. {
  603. if ( (r_rslt.HitIds[c] != -1) &&
  604. (r_rslt.HitDistance.m128_f32[c] < len.m128_f32[c] ) )
  605. {
  606. l_add.x.m128_f32[c]=0.0;
  607. l_add.y.m128_f32[c]=0.0;
  608. l_add.z.m128_f32[c]=0.0;
  609. }
  610. }
  611. rslt.CompoundElement( x, y ) = l_add;
  612. l_add *= m_Albedos.CompoundElement( x, y );
  613. // now, supress brightness < threshold so as to not falsely think
  614. // far away lights are interesting
  615. l_add.x = AndSIMD( l_add.x, CmpGtSIMD( l_add.x, ThresholdBrightness ) );
  616. l_add.y = AndSIMD( l_add.y, CmpGtSIMD( l_add.y, ThresholdBrightness ) );
  617. l_add.z = AndSIMD( l_add.z, CmpGtSIMD( l_add.z, ThresholdBrightness ) );
  618. ThisLinesTotalLight += l_add;
  619. }
  620. else
  621. rslt.CompoundElement( x, y ) = l_add;
  622. }
  623. total_light += ThisLinesTotalLight;
  624. }
  625. work_line_number++;
  626. }
  627. }
  628. fltx4 lmag=total_light.length();
  629. *(fContributionOut)=lmag.m128_f32[0]+lmag.m128_f32[1]+lmag.m128_f32[2]+lmag.m128_f32[3];
  630. }
  631. void CLightingPreviewThread::CalculateForLight( CLightingPreviewLightDescription &l )
  632. {
  633. if ( m_pRtEnv && (! m_bAccStructureBuilt ) )
  634. {
  635. m_bAccStructureBuilt = true;
  636. m_pRtEnv->SetupAccelerationStructure();
  637. }
  638. CIncrementalLightInfo *l_info=l.m_pIncrementalInfo;
  639. Assert( l_info );
  640. l_info->m_CalculatedContribution.SetSize( m_Albedos.m_nWidth, m_Albedos.m_nHeight );
  641. // figure out which lines need to be calculated
  642. int prev_msk=0;
  643. int new_incr_level=0;
  644. if ( l_info->m_eIncrState == INCR_STATE_PARTIAL_RESULTS )
  645. {
  646. new_incr_level = 1+l_info->m_PartialResultsStage;
  647. prev_msk = m_LineMask[l_info->m_PartialResultsStage];
  648. }
  649. int calc_mask=m_LineMask[new_incr_level] &~ prev_msk;
  650. // multihread here
  651. float total_light;
  652. CalculateForLightTask( 0, 0, l, calc_mask, &total_light );
  653. l_info->m_fTotalContribution = total_light;
  654. // throw away light array if no contribution
  655. if ( l_info->m_fTotalContribution == 0.0 )
  656. l_info->m_CalculatedContribution.SetSize( 0, 0 );
  657. else
  658. {
  659. l_info->m_nMostRecentNonZeroContributionTimeStamp = m_nContributionCounter;
  660. }
  661. l_info->m_PartialResultsStage = new_incr_level;
  662. if ( new_incr_level == N_INCREMENTAL_STEPS-1)
  663. l_info->m_eIncrState = INCR_STATE_HAVE_FULL_RESULTS;
  664. else
  665. l_info->m_eIncrState = INCR_STATE_PARTIAL_RESULTS;
  666. }
  667. void CLightingPreviewThread::SendVectorMatrixAsRendering( CSIMDVectorMatrix const &src )
  668. {
  669. Bitmap_t *ret_bm=new Bitmap_t;
  670. ret_bm->Init( src.m_nWidth, src.m_nHeight, IMAGE_FORMAT_RGBA8888 );
  671. // lets copy into the output bitmap
  672. for(int y=0;y<src.m_nHeight;y++)
  673. for(int x=0;x<src.m_nWidth;x++)
  674. {
  675. Vector color=src.Element( x, y );
  676. *(ret_bm->GetPixel( x, y )+0)= (uint8) min(255, (int)(255.0*pow(color.z,(float) (1/2.2))));
  677. *(ret_bm->GetPixel( x, y )+1)= (uint8) min(255, (int)(255.0*pow(color.y,(float) (1/2.2))));
  678. *(ret_bm->GetPixel( x, y )+2)= (uint8) min(255, (int)(255.0*pow(color.x,(float) (1/2.2))));
  679. *(ret_bm->GetPixel( x, y )+3)=0;
  680. }
  681. MessageFromLPreview ret_msg( LPREVIEW_MSG_DISPLAY_RESULT );
  682. // n_result_bms_queued++;
  683. ret_msg.m_pBitmapToDisplay = ret_bm;
  684. ret_msg.m_nBitmapGenerationCounter = m_nBitmapGenerationCounter;
  685. g_LPreviewToHammerMsgQueue.QueueMessage( ret_msg );
  686. }
  687. // master side of lighting preview
  688. unsigned LightingPreviewThreadFN( void *thread_start_arg )
  689. {
  690. CLightingPreviewThread LPreviewObject;
  691. ThreadSetPriority( -2 ); // low
  692. LPreviewObject.Run();
  693. return 0;
  694. }
  695. void HandleLightingPreview( void )
  696. {
  697. if ( GetMainWnd()->m_pLightingPreviewOutputWindow && !GetMainWnd()->m_bLightingPreviewOutputWindowShowing )
  698. {
  699. delete GetMainWnd()->m_pLightingPreviewOutputWindow;
  700. GetMainWnd()->m_pLightingPreviewOutputWindow = NULL;
  701. }
  702. // called during main loop
  703. while ( g_LPreviewToHammerMsgQueue.MessageWaiting() )
  704. {
  705. MessageFromLPreview msg;
  706. g_LPreviewToHammerMsgQueue.WaitMessage( &msg );
  707. switch( msg.m_MsgType )
  708. {
  709. case LPREVIEW_MSG_DISPLAY_RESULT:
  710. {
  711. n_result_bms_queued--;
  712. if (g_pLPreviewOutputBitmap)
  713. delete g_pLPreviewOutputBitmap;
  714. g_pLPreviewOutputBitmap = NULL;
  715. // if ( msg.m_nBitmapGenerationCounter == g_nBitmapGenerationCounter )
  716. {
  717. g_pLPreviewOutputBitmap = msg.m_pBitmapToDisplay;
  718. if ( g_pLPreviewOutputBitmap && (g_pLPreviewOutputBitmap->Width() > 10) )
  719. {
  720. SignalUpdate( EVTYPE_BITMAP_RECEIVED_FROM_LPREVIEW );
  721. CLightingPreviewResultsWindow *w=GetMainWnd()->m_pLightingPreviewOutputWindow;
  722. if ( !GetMainWnd()->m_bLightingPreviewOutputWindowShowing )
  723. {
  724. w = new CLightingPreviewResultsWindow;
  725. GetMainWnd()->m_pLightingPreviewOutputWindow = w;
  726. w->Create( GetMainWnd() );
  727. GetMainWnd()->m_bLightingPreviewOutputWindowShowing = true;
  728. }
  729. if (! w->IsWindowVisible() )
  730. w->ShowWindow( SW_SHOW );
  731. RECT existing_rect;
  732. w->GetClientRect( &existing_rect );
  733. if (
  734. (existing_rect.right != g_pLPreviewOutputBitmap->Width()-1) ||
  735. (existing_rect.bottom != g_pLPreviewOutputBitmap->Height()-1) )
  736. {
  737. CRect myRect;
  738. myRect.top=0;
  739. myRect.left=0;
  740. myRect.right=g_pLPreviewOutputBitmap->Width()-1;
  741. myRect.bottom=g_pLPreviewOutputBitmap->Height()-1;
  742. w->CalcWindowRect(&myRect);
  743. w->SetWindowPos(
  744. NULL,0,0,
  745. myRect.Width(), myRect.Height(),
  746. SWP_NOMOVE | SWP_NOZORDER );
  747. }
  748. w->Invalidate( false );
  749. w->UpdateWindow();
  750. }
  751. }
  752. // else
  753. // delete msg.m_pBitmapToDisplay; // its old
  754. break;
  755. }
  756. }
  757. }
  758. }