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.

420 lines
14 KiB

  1. // $Id:$
  2. #ifndef RAYTRACE_H
  3. #define RAYTRACE_H
  4. #include <tier0/platform.h>
  5. #include <mathlib/vector.h>
  6. #include <mathlib/ssemath.h>
  7. #include <mathlib/lightdesc.h>
  8. #include <assert.h>
  9. #include <tier1/utlvector.h>
  10. #include <tier1/utlbuffer.h>
  11. #include <mathlib/mathlib.h>
  12. #include <bspfile.h>
  13. // fast SSE-ONLY ray tracing module. Based upon various "real time ray tracing" research.
  14. //#define DEBUG_RAYTRACE 1
  15. class FourRays
  16. {
  17. public:
  18. FourVectors origin;
  19. FourVectors direction;
  20. inline void Check(void) const
  21. {
  22. // in order to be valid to trace as a group, all four rays must have the same signs in all
  23. // of their direction components
  24. #ifndef NDEBUG
  25. for(int c=1;c<4;c++)
  26. {
  27. Assert(direction.X(0)*direction.X(c)>=0);
  28. Assert(direction.Y(0)*direction.Y(c)>=0);
  29. Assert(direction.Z(0)*direction.Z(c)>=0);
  30. }
  31. #endif
  32. }
  33. // returns direction sign mask for 4 rays. returns -1 if the rays can not be traced as a
  34. // bundle.
  35. int CalculateDirectionSignMask(void) const;
  36. };
  37. /// The format a triangle is stored in for intersections. size of this structure is important.
  38. /// This structure can be in one of two forms. Before the ray tracing environment is set up, the
  39. /// ProjectedEdgeEquations hold the coordinates of the 3 vertices, for facilitating bounding box
  40. /// checks needed while building the tree. afterwards, they are changed into the projected ege
  41. /// equations for intersection purposes.
  42. enum triangleflags
  43. {
  44. FCACHETRI_TRANSPARENT = 0x01,
  45. FCACHETRI_NEGATIVE_NORMAL = 0x02,
  46. };
  47. struct TriIntersectData_t
  48. {
  49. // this structure is 16longs=64 bytes for cache line packing.
  50. float m_flNx, m_flNy, m_flNz; // plane equation
  51. float m_flD;
  52. int32 m_nTriangleID; // id of the triangle.
  53. float m_ProjectedEdgeEquations[6]; // A,B,C for each edge equation. a
  54. // point is inside the triangle if
  55. // a*c1+b*c2+c is negative for all 3
  56. // edges.
  57. uint8 m_nCoordSelect0,m_nCoordSelect1; // the triangle is projected onto a 2d
  58. // plane for edge testing. These are
  59. // the indices (0..2) of the
  60. // coordinates preserved in the
  61. // projection
  62. uint8 m_nFlags; // triangle flags
  63. uint8 m_unused0; // no longer used
  64. };
  65. struct TriGeometryData_t
  66. {
  67. int32 m_nTriangleID; // id of the triangle.
  68. float m_VertexCoordData[9]; // can't use a vector in a union
  69. uint8 m_nFlags; // triangle flags
  70. signed char m_nTmpData0; // used by kd-tree builder
  71. signed char m_nTmpData1; // used by kd-tree builder
  72. // accessors to get around union annoyance
  73. FORCEINLINE Vector &Vertex(int idx)
  74. {
  75. return * ( reinterpret_cast<Vector *> ( m_VertexCoordData+3*idx ) );
  76. }
  77. };
  78. struct CacheOptimizedTriangle
  79. {
  80. union
  81. {
  82. TriIntersectData_t m_IntersectData;
  83. TriGeometryData_t m_GeometryData;
  84. } m_Data;
  85. // accessors to get around union annoyance
  86. FORCEINLINE Vector &Vertex(int idx)
  87. {
  88. return * ( reinterpret_cast<Vector *> (m_Data.m_GeometryData.m_VertexCoordData+3*idx ) );
  89. }
  90. FORCEINLINE const Vector &Vertex(int idx) const
  91. {
  92. return * ( reinterpret_cast<const Vector *> (m_Data.m_GeometryData.m_VertexCoordData+3*idx ) );
  93. }
  94. void ChangeIntoIntersectionFormat(void); // change information storage format for
  95. // computing intersections.
  96. int ClassifyAgainstAxisSplit(int split_plane, float split_value); // PLANECHECK_xxx below
  97. // Debug - take a triangle that has been converted to intersection format and extract the vertices
  98. // from by intersecting the planes
  99. void ExtractVerticesFromIntersectionFormat( Vector &v0, Vector &v1, Vector &v2 ) const;
  100. };
  101. #define PLANECHECK_POSITIVE 1
  102. #define PLANECHECK_NEGATIVE -1
  103. #define PLANECHECK_STRADDLING 0
  104. #define KDNODE_STATE_XSPLIT 0 // this node is an x split
  105. #define KDNODE_STATE_YSPLIT 1 // this node is a ysplit
  106. #define KDNODE_STATE_ZSPLIT 2 // this node is a zsplit
  107. #define KDNODE_STATE_LEAF 3 // this node is a leaf
  108. struct CacheOptimizedKDNode
  109. {
  110. // this is the cache intensive data structure. "Tricks" are used to fit it into 8 bytes:
  111. //
  112. // A) the right child is always stored after the left child, which means we only need one
  113. // pointer
  114. // B) The type of node (KDNODE_xx) is stored in the lower 2 bits of the pointer.
  115. // C) for leaf nodes, we store the number of triangles in the leaf in the same place as the floating
  116. // point splitting parameter is stored in a non-leaf node
  117. int32 Children; // child idx, or'ed with flags above
  118. float SplittingPlaneValue; // for non-leaf nodes, the nodes on the
  119. // "high" side of the splitting plane
  120. // are on the right
  121. #ifdef DEBUG_RAYTRACE
  122. Vector vecMins;
  123. Vector vecMaxs;
  124. #endif
  125. inline int NodeType(void) const
  126. {
  127. return Children & 3;
  128. }
  129. inline int32 TriangleIndexStart(void) const
  130. {
  131. assert(NodeType()==KDNODE_STATE_LEAF);
  132. return Children>>2;
  133. }
  134. inline int LeftChild(void) const
  135. {
  136. assert(NodeType()!=KDNODE_STATE_LEAF);
  137. return Children>>2;
  138. }
  139. inline int RightChild(void) const
  140. {
  141. return LeftChild()+1;
  142. }
  143. inline int NumberOfTrianglesInLeaf(void) const
  144. {
  145. assert(NodeType()==KDNODE_STATE_LEAF);
  146. return *((int32 *) &SplittingPlaneValue);
  147. }
  148. inline void SetNumberOfTrianglesInLeafNode(int n)
  149. {
  150. *((int32 *) &SplittingPlaneValue)=n;
  151. }
  152. protected:
  153. };
  154. struct RayTracingSingleResult
  155. {
  156. Vector surface_normal; // surface normal at intersection
  157. int32 HitID; // -1=no hit. otherwise, triangle index
  158. float HitDistance; // distance to intersection
  159. float ray_length; // leng of initial ray
  160. };
  161. struct RayTracingResult
  162. {
  163. FourVectors surface_normal; // surface normal at intersection
  164. ALIGN16 int32 HitIds[4] ALIGN16_POST; // -1=no hit. otherwise, triangle index
  165. fltx4 HitDistance; // distance to intersection
  166. };
  167. class RayTraceLight
  168. {
  169. public:
  170. FourVectors Position;
  171. FourVectors Intensity;
  172. };
  173. #define RTE_FLAGS_FAST_TREE_GENERATION 1
  174. #define RTE_FLAGS_DONT_STORE_TRIANGLE_COLORS 2 // saves memory if not needed
  175. #define RTE_FLAGS_DONT_STORE_TRIANGLE_MATERIALS 4
  176. enum RayTraceLightingMode_t {
  177. DIRECT_LIGHTING, // just dot product lighting
  178. DIRECT_LIGHTING_WITH_SHADOWS, // with shadows
  179. GLOBAL_LIGHTING // global light w/ shadows
  180. };
  181. class RayStream
  182. {
  183. friend class RayTracingEnvironment;
  184. RayTracingSingleResult *PendingStreamOutputs[8][4];
  185. int n_in_stream[8];
  186. FourRays PendingRays[8];
  187. public:
  188. RayStream(void)
  189. {
  190. memset(n_in_stream,0,sizeof(n_in_stream));
  191. }
  192. };
  193. // When transparent triangles are in the list, the caller can provide a callback that will get called at each triangle
  194. // allowing the callback to stop processing if desired.
  195. // UNDONE: This is not currently SIMD - it really only supports single rays
  196. // Also for efficiency FourRays really needs some kind of active mask for the cases where rays get unbundled
  197. class ITransparentTriangleCallback
  198. {
  199. public:
  200. virtual bool VisitTriangle_ShouldContinue( const TriIntersectData_t &triangle, const FourRays &rays, bi32x4 *hitMask, fltx4 *b0, fltx4 *b1, fltx4 *b2, int32 hitID ) = 0;
  201. };
  202. enum RTECullMode_t
  203. {
  204. RTE_CULL_NONE = 0,
  205. RTE_CULL_FRONT,
  206. RTE_CULL_BACK
  207. };
  208. // serialization flag bits and defines
  209. #define RT_ENV_SERIALIZE_COLORS 1
  210. class RayTracingEnvironment
  211. {
  212. public:
  213. uint32 Flags; // RTE_FLAGS_xxx above
  214. Vector m_MinBound;
  215. Vector m_MaxBound;
  216. FourVectors BackgroundColor; //< color where no intersection
  217. CUtlVector<CacheOptimizedKDNode> OptimizedKDTree; //< the packed kdtree. root is 0
  218. CUtlBlockVector<CacheOptimizedTriangle> OptimizedTriangleList; //< the packed triangles
  219. CUtlVector<int32> TriangleIndexList; //< the list of triangle indices.
  220. CUtlVector<LightDesc_t> LightList; //< the list of lights
  221. CUtlVector<Vector> TriangleColors; //< color of tries
  222. CUtlVector<int32> TriangleMaterials; //< material index of tries
  223. public:
  224. RayTracingEnvironment() : OptimizedTriangleList( 1024 )
  225. {
  226. BackgroundColor.DuplicateVector(Vector(1,0,0)); // red
  227. Flags=0;
  228. }
  229. #if !( defined ( _DEBUG ) && defined ( HAMMER_RAYTRACE ) )
  230. inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_( "RayTracingEnvironment" ); return MemAlloc_AllocAligned( size, 16 ); }
  231. inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_( "RayTracingEnvironment" ); return MemAlloc_AllocAligned( size, 16 ); }
  232. inline void operator delete( void* p ) { MemAlloc_FreeAligned( p ); }
  233. inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { MemAlloc_FreeAligned( p ); }
  234. #endif
  235. // call AddTriangle to set up the world
  236. void AddTriangle(int32 id, const Vector &v1, const Vector &v2, const Vector &v3,
  237. const Vector &color);
  238. // Adds a triangle with flags & material
  239. void AddTriangle(int32 id, const Vector &v1, const Vector &v2, const Vector &v3,
  240. const Vector &color, uint16 flags, int32 materialIndex);
  241. void AddQuad(int32 id, const Vector &v1, const Vector &v2, const Vector &v3,
  242. const Vector &v4, // specify vertices in cw or ccw order
  243. const Vector &color);
  244. // for ease of testing.
  245. void AddAxisAlignedRectangularSolid(int id,Vector mincoord, Vector Maxcoord,
  246. const Vector &color);
  247. // SetupAccelerationStructure to prepare for tracing
  248. void SetupAccelerationStructure(void);
  249. // lowest level intersection routine - fire 4 rays through the scene. all 4 rays must pass the
  250. // Check() function, and t extents must be initialized. skipid can be set to exclude a
  251. // particular id (such as the origin surface). This function finds the closest intersection.
  252. template <RTECullMode_t cullMode>
  253. void Trace4Rays(const FourRays &rays, fltx4 TMin, fltx4 TMax,int DirectionSignMask,
  254. RayTracingResult *rslt_out,
  255. int32 skip_id=-1, ITransparentTriangleCallback *pCallback = NULL );
  256. // wrapper for the low level trace4 rays routine
  257. void Trace4Rays(const FourRays &rays, fltx4 TMin, fltx4 TMax,int DirectionSignMask,
  258. RayTracingResult *rslt_out,
  259. int32 skip_id=-1, ITransparentTriangleCallback *pCallback = NULL, RTECullMode_t cullMode = RTE_CULL_NONE );
  260. // higher level intersection routine that handles computing the mask and handling rays which do not match in direciton sign
  261. void Trace4Rays(const FourRays &rays, fltx4 TMin, fltx4 TMax,
  262. RayTracingResult *rslt_out,
  263. int32 skip_id=-1, ITransparentTriangleCallback *pCallback = NULL, RTECullMode_t cullMode = RTE_CULL_NONE );
  264. // compute virtual light sources to model inter-reflection
  265. void ComputeVirtualLightSources(void);
  266. // high level interface - pass viewing parameters, rendering flags, and a destination frame
  267. // buffer, and get a ray traced scene in 32-bit rgba format
  268. void RenderScene(int width, int height, // width and height of desired rendering
  269. int stride, // actual width in pixels of target buffer
  270. uint32 *output_buffer, // pointer to destination
  271. Vector CameraOrigin, // eye position
  272. Vector ULCorner, // word space coordinates of upper left
  273. // monitor corner
  274. Vector URCorner, // top right corner
  275. Vector LLCorner, // lower left
  276. Vector LRCorner, // lower right
  277. RayTraceLightingMode_t lightmode=DIRECT_LIGHTING);
  278. /// raytracing stream - lets you trace an array of rays by feeding them to this function.
  279. /// results will not be returned until FinishStream is called. This function handles sorting
  280. /// the rays by direction, tracing them 4 at a time, and de-interleaving the results.
  281. void AddToRayStream(RayStream &s,
  282. Vector const &start,Vector const &end,RayTracingSingleResult *rslt_out,
  283. RTECullMode_t cullMode = RTE_CULL_NONE);
  284. inline void FlushStreamEntry(RayStream &s, int msk, RTECullMode_t cullMode = RTE_CULL_NONE);
  285. /// call this when you are done. handles all cleanup. After this is called, all rslt ptrs
  286. /// previously passed to AddToRaySteam will have been filled in.
  287. void FinishRayStream(RayStream &s, RTECullMode_t cullMode = RTE_CULL_NONE);
  288. int MakeLeafNode(int first_tri, int last_tri);
  289. float CalculateCostsOfSplit(
  290. int split_plane,int32 const *tri_list,int ntris,
  291. Vector MinBound,Vector MaxBound, float &split_value,
  292. int &nleft, int &nright, int &nboth);
  293. void RefineNode(int node_number,int32 const *tri_list,int ntris,
  294. Vector MinBound,Vector MaxBound, int depth);
  295. void CalculateTriangleListBounds(int32 const *tris,int ntris,
  296. Vector &minout, Vector &maxout);
  297. void AddInfinitePointLight(Vector position, // light center
  298. Vector intensity); // rgb amount
  299. // use the global variables set by LoadBSPFile to populated the RayTracingEnvironment with
  300. // faces.
  301. void InitializeFromLoadedBSP(void);
  302. void AddBSPFace(int id,dface_t const &face);
  303. // MakeRoomForTriangles - a hint telling it how many triangles we are going to add so that
  304. // the utl vectors used can be pre-allocated
  305. void MakeRoomForTriangles( int ntriangles );
  306. const CacheOptimizedTriangle &GetTriangle( int32 triID )
  307. {
  308. return OptimizedTriangleList[triID];
  309. }
  310. int32 GetTriangleMaterial( int32 triID )
  311. {
  312. return TriangleMaterials[triID];
  313. }
  314. const Vector &GetTriangleColor( int triID )
  315. {
  316. return TriangleColors[triID];
  317. }
  318. // (un)serialization
  319. size_t GetSerializationNumBytes( uint32 nSerializationFlags = 0 ) const;
  320. void Serialize( CUtlBuffer &outbuf, uint32 nSerializationFlags = 0 ) const;
  321. void UnSerialize( CUtlBuffer &inbuf );
  322. };
  323. #endif