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.

354 lines
11 KiB

  1. //===== Copyright � 1996-2006, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include <tier0/platform.h>
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <math.h>
  10. #include <stdlib.h>
  11. #include "bitmap/floatbitmap.h"
  12. #include "vstdlib/vstdlib.h"
  13. #include "raytrace.h"
  14. #include "mathlib/bumpvects.h"
  15. #include "mathlib/halton.h"
  16. #include "tier0/threadtools.h"
  17. #include "tier0/progressbar.h"
  18. // NOTE: This has to be the last file included!
  19. #include "tier0/memdbgon.h"
  20. // In order to handle intersections with wrapped copies, we repeat the bitmap triangles this many
  21. // times
  22. #define NREPS_TILE 1
  23. extern int n_intersection_calculations;
  24. struct SSBumpCalculationContext // what each thread needs to see
  25. {
  26. RayTracingEnvironment * m_pRtEnv;
  27. FloatBitMap_t * ret_bm; // the bitmnap we are building
  28. FloatBitMap_t const * src_bm;
  29. int nrays_to_trace_per_pixel;
  30. float bump_scale;
  31. Vector *trace_directions; // light source directions to trace
  32. Vector *normals;
  33. int min_y; // range of scanlines to computer for
  34. int max_y;
  35. uint32 m_nOptionFlags;
  36. int thread_number;
  37. };
  38. static uintp SSBumpCalculationThreadFN( void * ctx1 )
  39. {
  40. SSBumpCalculationContext * ctx = ( SSBumpCalculationContext * ) ctx1;
  41. RayStream ray_trace_stream_ctx;
  42. RayTracingSingleResult * rslts = new
  43. RayTracingSingleResult[ctx->ret_bm->NumCols() * ctx->nrays_to_trace_per_pixel];
  44. for( int y = ctx->min_y; y <= ctx->max_y; y++ )
  45. {
  46. if ( ctx->thread_number == 0 )
  47. ReportProgress("Computing output",(1+ctx->max_y-ctx->min_y),y-ctx->min_y);
  48. for( int r = 0; r < ctx->nrays_to_trace_per_pixel; r++ )
  49. {
  50. for( int x = 0; x < ctx->ret_bm->NumCols(); x++ )
  51. {
  52. Vector surf_pnt( x, y, ctx->bump_scale * ctx->src_bm->Pixel( x, y, 0, 3 ) );
  53. // move the ray origin up a hair
  54. surf_pnt.z += 0.55;
  55. Vector trace_end = surf_pnt;
  56. Vector trace_dir = ctx->trace_directions[ r ];
  57. trace_dir *= ( 1 + NREPS_TILE * 2 ) * MAX( ctx->src_bm->NumCols(), ctx->src_bm->NumRows() );
  58. trace_end += trace_dir;
  59. ctx->m_pRtEnv->AddToRayStream( ray_trace_stream_ctx, surf_pnt, trace_end,
  60. & ( rslts[ r + ctx->nrays_to_trace_per_pixel * ( x )] ) );
  61. }
  62. }
  63. if ( ctx->nrays_to_trace_per_pixel )
  64. ctx->m_pRtEnv->FinishRayStream( ray_trace_stream_ctx );
  65. // now, all ray tracing results are in the results buffer. Determine the visible self-shadowed
  66. // bump map lighting at each vertex in each basis direction
  67. for( int x = 0; x < ctx->src_bm->NumCols(); x++ )
  68. {
  69. int nNumChannels = ( ctx->m_nOptionFlags & SSBUMP_OPTION_NONDIRECTIONAL ) ? 1 : 3;
  70. for( int c = 0; c < nNumChannels; c++ )
  71. {
  72. float sum_dots = 0;
  73. float sum_possible_dots = 0;
  74. Vector ldir = g_localBumpBasis[c];
  75. float ndotl = DotProduct( ldir, ctx->normals[x + y * ctx->src_bm->NumCols()] );
  76. if ( ndotl < 0 )
  77. ctx->ret_bm->Pixel( x, y, 0, c ) = 0;
  78. else
  79. {
  80. if ( ctx->nrays_to_trace_per_pixel )
  81. {
  82. RayTracingSingleResult * this_rslt =
  83. rslts + ctx->nrays_to_trace_per_pixel * ( x );
  84. for( int r = 0; r < ctx->nrays_to_trace_per_pixel; r++ )
  85. {
  86. float dot;
  87. if ( ctx->m_nOptionFlags & SSBUMP_OPTION_NONDIRECTIONAL )
  88. dot = ctx->trace_directions[r].z;
  89. else
  90. dot = DotProduct( ldir, ctx->trace_directions[r] );
  91. if ( dot > 0 )
  92. {
  93. sum_possible_dots += dot;
  94. if ( this_rslt[r].HitID == - 1 )
  95. sum_dots += dot;
  96. }
  97. }
  98. }
  99. else
  100. {
  101. sum_dots = sum_possible_dots = 1.0;
  102. }
  103. ctx->ret_bm->Pixel( x, y, 0, c ) = ( ndotl * sum_dots ) / sum_possible_dots;
  104. }
  105. }
  106. if ( ctx->m_nOptionFlags & SSBUMP_OPTION_NONDIRECTIONAL )
  107. {
  108. ctx->ret_bm->Pixel( x, y, 0, 1 ) = ctx->ret_bm->Pixel( x, y, 0, 0 ); // copy height
  109. ctx->ret_bm->Pixel( x, y, 0, 2 ) = ctx->ret_bm->Pixel( x, y, 0, 0 ); // copy height
  110. ctx->ret_bm->Pixel( x, y, 0, 3 ) = ctx->ret_bm->Pixel( x, y, 0, 0 ); // copy height
  111. }
  112. else
  113. {
  114. ctx->ret_bm->Pixel( x, y, 0, 3 ) = ctx->src_bm->Pixel( x, y, 0, 3 ); // copy height
  115. }
  116. }
  117. }
  118. delete[] rslts;
  119. return 0;
  120. }
  121. void FloatBitMap_t::ComputeVertexPositionsAndNormals( float flHeightScale, Vector ** ppPosOut, Vector ** ppNormalOut ) const
  122. {
  123. Vector * verts = new Vector[NumCols() * NumRows()];
  124. // first, calculate vertex positions
  125. for( int y = 0; y < NumRows(); y++ )
  126. for( int x = 0; x < NumCols(); x++ )
  127. {
  128. Vector * out = verts + x + y * NumCols();
  129. out->x = x;
  130. out->y = y;
  131. out->z = flHeightScale * Pixel( x, y, 0, 3 );
  132. }
  133. Vector * normals = new Vector[NumCols() * NumRows()];
  134. // now, calculate normals, smoothed
  135. for( int y = 0; y < NumRows(); y++ )
  136. for( int x = 0; x < NumCols(); x++ )
  137. {
  138. // now, calculcate average normal
  139. Vector avg_normal( 0, 0, 0 );
  140. for( int xofs =- 1;xofs <= 1;xofs++ )
  141. for( int yofs =- 1;yofs <= 1;yofs++ )
  142. {
  143. int x0 = ( x + xofs );
  144. if ( x0 < 0 )
  145. x0 += NumCols();
  146. int y0 = ( y + yofs );
  147. if ( y0 < 0 )
  148. y0 += NumRows();
  149. x0 = x0 % NumCols();
  150. y0 = y0 % NumRows();
  151. int x1 = ( x0 + 1 ) % NumCols();
  152. int y1 = ( y0 + 1 ) % NumRows();
  153. // now, form the two triangles from this vertex
  154. Vector p0 = verts[x0 + y0 * NumCols()];
  155. Vector e1 = verts[x1 + y0 * NumCols()];
  156. e1 -= p0;
  157. Vector e2 = verts[x0 + y1 * NumCols()];
  158. e2 -= p0;
  159. Vector n1;
  160. CrossProduct( e1, e2, n1 );
  161. if ( n1.z < 0 )
  162. n1.Negate();
  163. e1 = verts[x + y1 * NumCols()];
  164. e1 -= p0;
  165. e2 = verts[x1 + y1 * NumCols()];
  166. e2 -= p0;
  167. Vector n2;
  168. CrossProduct( e1, e2, n2 );
  169. if ( n2.z < 0 )
  170. n2.Negate();
  171. n1.NormalizeInPlace();
  172. n2.NormalizeInPlace();
  173. avg_normal += n1;
  174. avg_normal += n2;
  175. }
  176. avg_normal.NormalizeInPlace();
  177. normals[x + y * NumCols()]= avg_normal;
  178. }
  179. * ppPosOut = verts;
  180. * ppNormalOut = normals;
  181. }
  182. FloatBitMap_t * FloatBitMap_t::ComputeSelfShadowedBumpmapFromHeightInAlphaChannel(
  183. float bump_scale, int nrays_to_trace_per_pixel,
  184. uint32 nOptionFlags ) const
  185. {
  186. // first, add all the triangles from the height map to the "world".
  187. // we will make multiple copies to handle wrapping
  188. int tcnt = 1;
  189. Vector * verts;
  190. Vector * normals;
  191. ComputeVertexPositionsAndNormals( bump_scale, & verts, & normals );
  192. RayTracingEnvironment rtEnv;
  193. rtEnv.Flags |= RTE_FLAGS_DONT_STORE_TRIANGLE_COLORS; // save some ram
  194. if ( nrays_to_trace_per_pixel )
  195. {
  196. rtEnv.MakeRoomForTriangles( ( 1 + 2 * NREPS_TILE ) * ( 1 + 2 * NREPS_TILE ) * 2 * NumRows() * NumCols() );
  197. // now, add a whole mess of triangles to trace against
  198. for( int tilex =- NREPS_TILE; tilex <= NREPS_TILE; tilex++ )
  199. for( int tiley =- NREPS_TILE; tiley <= NREPS_TILE; tiley++ )
  200. {
  201. int min_x = 0;
  202. int max_x = NumCols() - 1;
  203. int min_y = 0;
  204. int max_y = NumRows() - 1;
  205. if ( tilex < 0 )
  206. min_x = NumCols() / 2;
  207. if ( tilex > 0 )
  208. max_x = NumCols() / 2;
  209. if ( tiley < 0 )
  210. min_y = NumRows() / 2;
  211. if ( tiley > 0 )
  212. max_y = NumRows() / 2;
  213. for( int y = min_y; y <= max_y; y++ )
  214. for( int x = min_x; x <= max_x; x++ )
  215. {
  216. Vector ofs( tilex * NumCols(), tiley * NumRows(), 0 );
  217. int x1 = ( x + 1 ) % NumCols();
  218. int y1 = ( y + 1 ) % NumRows();
  219. Vector v0 = verts[x + y * NumCols()];
  220. Vector v1 = verts[x1 + y * NumCols()];
  221. Vector v2 = verts[x1 + y1 * NumCols()];
  222. Vector v3 = verts[x + y1 * NumCols()];
  223. v0.x = x; v0.y = y;
  224. v1.x = x + 1; v1.y = y;
  225. v2.x = x + 1; v2.y = y + 1;
  226. v3.x = x; v3.y = y + 1;
  227. v0 += ofs; v1 += ofs; v2 += ofs; v3 += ofs;
  228. rtEnv.AddTriangle( tcnt++, v0, v1, v2, Vector( 1, 1, 1 ) );
  229. rtEnv.AddTriangle( tcnt++, v0, v3, v2, Vector( 1, 1, 1 ) );
  230. }
  231. }
  232. //printf("added %d triangles\n",tcnt-1);
  233. ReportProgress("Creating kd-tree",0,0);
  234. rtEnv.SetupAccelerationStructure();
  235. // ok, now we have built a structure for ray intersection. we will take advantage
  236. // of the SSE ray tracing code by intersecting rays as a batch.
  237. }
  238. // We need to calculate for each vertex (i.e. pixel) of the heightmap, how "much" of the world
  239. // it can see in each basis direction. we will do this by sampling a sphere of rays around the
  240. // vertex, and using dot-product weighting to measure the lighting contribution in each basis
  241. // direction. note that the surface normal is not used here. The surface normal will end up
  242. // being reflected in the result because of rays being blocked when they try to pass through
  243. // the planes of the triangles touching the vertex.
  244. // note that there is no reason inter-bounced lighting could not be folded into this
  245. // calculation.
  246. FloatBitMap_t * ret = new FloatBitMap_t( NumCols(), NumRows() );
  247. Vector * trace_directions = new Vector[nrays_to_trace_per_pixel];
  248. DirectionalSampler_t my_sphere_sampler;
  249. for( int r = 0; r < nrays_to_trace_per_pixel; r++ )
  250. {
  251. Vector trace_dir = my_sphere_sampler.NextValue();
  252. // trace_dir=Vector(1,0,0);
  253. trace_dir.z = fabs( trace_dir.z ); // upwards facing only
  254. trace_directions[ r ]= trace_dir;
  255. }
  256. volatile SSBumpCalculationContext ctxs[32];
  257. ctxs[0].m_pRtEnv =& rtEnv;
  258. ctxs[0].ret_bm = ret;
  259. ctxs[0].src_bm = this;
  260. ctxs[0].nrays_to_trace_per_pixel = nrays_to_trace_per_pixel;
  261. ctxs[0].bump_scale = bump_scale;
  262. ctxs[0].trace_directions = trace_directions;
  263. ctxs[0].normals = normals;
  264. ctxs[0].min_y = 0;
  265. ctxs[0].max_y = NumRows() - 1;
  266. ctxs[0].m_nOptionFlags = nOptionFlags;
  267. int nthreads = MIN( 32, GetCPUInformation().m_nPhysicalProcessors );
  268. ThreadHandle_t waithandles[32];
  269. int starty = 0;
  270. int ystep = NumRows() / nthreads;
  271. for( int t = 0;t < nthreads; t++ )
  272. {
  273. if ( t )
  274. memcpy( ( void * ) ( & ctxs[t] ), ( void * ) & ctxs[0], sizeof( ctxs[0] ) );
  275. ctxs[t].thread_number = t;
  276. ctxs[t].min_y = starty;
  277. if ( t != nthreads - 1 )
  278. ctxs[t].max_y = MIN( NumRows() - 1, starty + ystep - 1 );
  279. else
  280. ctxs[t].max_y = NumRows() - 1;
  281. waithandles[t]= CreateSimpleThread( SSBumpCalculationThreadFN, ( SSBumpCalculationContext * ) & ctxs[t] );
  282. starty += ystep;
  283. }
  284. for( int t = 0;t < nthreads;t++ )
  285. {
  286. ThreadJoin( waithandles[t] );
  287. }
  288. if ( nOptionFlags & SSBUMP_MOD2X_DETAIL_TEXTURE )
  289. {
  290. const float flOutputScale = 0.5 * ( 1.0 / .57735026 ); // normalize so that a flat normal yields 0.5
  291. // scale output weights by color channel
  292. for( int nY = 0; nY < NumRows(); nY++ )
  293. for( int nX = 0; nX < NumCols(); nX++ )
  294. {
  295. float flScale = flOutputScale * ( 2.0 / 3.0 ) * ( Pixel( nX, nY, 0, 0 ) + Pixel( nX, nY, 0, 1 ) + Pixel( nX, nY, 0, 2 ) );
  296. ret->Pixel( nX, nY, 0, 0 ) *= flScale;
  297. ret->Pixel( nX, nY, 0, 1 ) *= flScale;
  298. ret->Pixel( nX, nY, 0, 2 ) *= flScale;
  299. }
  300. }
  301. delete[] verts;
  302. delete[] trace_directions;
  303. delete[] normals;
  304. return ret; // destructor will clean up rtenv
  305. }
  306. // generate a conventional normal map from a source with height stored in alpha.
  307. FloatBitMap_t * FloatBitMap_t::ComputeBumpmapFromHeightInAlphaChannel( float flBumpScale ) const
  308. {
  309. Vector * verts;
  310. Vector * normals;
  311. ComputeVertexPositionsAndNormals( flBumpScale, & verts, & normals );
  312. FloatBitMap_t * ret = new FloatBitMap_t( NumCols(), NumRows() );
  313. for( int y = 0; y < NumRows(); y++ )
  314. for( int x = 0; x < NumCols(); x++ )
  315. {
  316. Vector const & N = normals[ x + y * NumCols() ];
  317. ret->Pixel( x, y, 0, 0 ) = 0.5 + 0.5 * N.x;
  318. ret->Pixel( x, y, 0, 1 ) = 0.5 + 0.5 * N.y;
  319. ret->Pixel( x, y, 0, 2 ) = 0.5 + 0.5 * N.z;
  320. ret->Pixel( x, y, 0, 3 ) = Pixel( x, y, 0, 3 );
  321. }
  322. return ret;
  323. }