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.

348 lines
9.1 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "stdafx.h"
  8. #include "IEditorTexture.h"
  9. #include "MapFace.h"
  10. #include "clipcode.h"
  11. // memdbgon must be the last include file in a .cpp file!!!
  12. #include "tier0/memdbgon.h"
  13. static float g_vert[MAX_CLIPVERT][VERTEXSIZE];
  14. static int g_outCount;
  15. // Quick and dirty sutherland Hodgman clipper
  16. // Clip polygon to decal in texture space
  17. // JAY: This code is lame, change it later. It does way too much work per frame
  18. // It can be made to recursively call the clipping code and only copy the vertex list once
  19. int Inside( float *vert, int edge )
  20. {
  21. switch( edge ) {
  22. case 0: // left
  23. if ( vert[3] > 0.0 )
  24. return 1;
  25. return 0;
  26. case 1: // right
  27. if ( vert[3] < 1.0 )
  28. return 1;
  29. return 0;
  30. case 2: // top
  31. if ( vert[4] > 0.0 )
  32. return 1;
  33. return 0;
  34. case 3:
  35. if ( vert[4] < 1.0 )
  36. return 1;
  37. return 0;
  38. }
  39. return 0;
  40. }
  41. void Intersect( float *one, float *two, int edge, float *out )
  42. {
  43. float t;
  44. // t is the parameter of the line between one and two clipped to the edge
  45. // or the fraction of the clipped point between one & two
  46. // vert[3] is u
  47. // vert[4] is v
  48. // vert[0], vert[1], vert[2] is X, Y, Z
  49. if ( edge < 2 ) {
  50. if ( edge == 0 ) { // left
  51. t = ( (one[3] - 0) / (one[3] - two[3]) );
  52. out[3] = 0;
  53. }
  54. else { // right
  55. t = ( (one[3] - 1) / (one[3] - two[3]) );
  56. out[3] = 1;
  57. }
  58. out[4] = one[4] + (two[4] - one[4]) * t;
  59. }
  60. else {
  61. if ( edge == 2 ) { // top
  62. t = ( (one[4] - 0) / (one[4] - two[4]) );
  63. out[4] = 0;
  64. }
  65. else { // bottom
  66. t = ( (one[4] - 1) / (one[4] - two[4]) );
  67. out[4] = 1;
  68. }
  69. out[3] = one[3] + (two[3] - one[3]) * t;
  70. }
  71. out[0] = one[0] + (two[0] - one[0]) * t;
  72. out[1] = one[1] + (two[1] - one[1]) * t;
  73. out[2] = one[2] + (two[2] - one[2]) * t;
  74. }
  75. //-----------------------------------------------------------------------------
  76. // Purpose:
  77. // Input : *vert -
  78. // vertCount -
  79. // *out -
  80. // outSize -
  81. // edge -
  82. // Output : int
  83. //-----------------------------------------------------------------------------
  84. int SHClip( float *vert, int vertCount, float *out, int outSize, int edge )
  85. {
  86. int j, outCount;
  87. float *s, *p;
  88. outCount = 0;
  89. s = &vert[ (vertCount-1) * VERTEXSIZE ];
  90. for ( j = 0; j < vertCount; j++ ) {
  91. p = &vert[ j * VERTEXSIZE ];
  92. if ( Inside( p, edge ) ) {
  93. if ( Inside( s, edge ) ) {
  94. // Add a vertex and advance out to next vertex
  95. memcpy( out, p, sizeof(float)*VERTEXSIZE );
  96. outCount++;
  97. out += VERTEXSIZE;
  98. }
  99. else {
  100. Intersect( s, p, edge, out );
  101. out += VERTEXSIZE;
  102. outCount++;
  103. memcpy( out, p, sizeof(float)*VERTEXSIZE );
  104. outCount++;
  105. out += VERTEXSIZE;
  106. }
  107. }
  108. else {
  109. if ( Inside( s, edge ) ) {
  110. Intersect( p, s, edge, out );
  111. out += VERTEXSIZE;
  112. outCount++;
  113. }
  114. }
  115. if (outCount >= outSize)
  116. {
  117. Assert(FALSE);
  118. break;
  119. }
  120. s = p;
  121. }
  122. return outCount;
  123. }
  124. #define SIN_45_DEGREES ( 0.70710678118654752440084436210485f )
  125. // The world coordinate system is right handed with Z up.
  126. //
  127. // ^ Z
  128. // |
  129. // |
  130. // |
  131. //X<----|
  132. // \
  133. // \
  134. // \ Y
  135. //-----------------------------------------------------------------------------
  136. // compute the decal basis based on surface normal, and preferred saxis
  137. //-----------------------------------------------------------------------------
  138. static void R_DecalComputeBasis( Vector const& surfaceNormal, Vector const* pSAxis,
  139. bool flipNormal, Vector* textureSpaceBasis )
  140. {
  141. // s, t, textureSpaceNormal (T cross S = textureSpaceNormal(N))
  142. // N
  143. // \
  144. // \
  145. // \
  146. // |---->S
  147. // |
  148. // |
  149. // |T
  150. // S = textureSpaceBasis[0]
  151. // T = textureSpaceBasis[1]
  152. // N = textureSpaceBasis[2]
  153. // Get the surface normal.
  154. textureSpaceBasis[2] = surfaceNormal;
  155. if (flipNormal)
  156. VectorNegate( textureSpaceBasis[2] );
  157. if (pSAxis)
  158. {
  159. // T = S cross N
  160. CrossProduct( *pSAxis, textureSpaceBasis[2], textureSpaceBasis[1] );
  161. // Name sure they aren't parallel or antiparallel
  162. // In that case, fall back to the normal algorithm.
  163. if ( DotProduct( textureSpaceBasis[1], textureSpaceBasis[1] ) > 1e-6 )
  164. {
  165. // S = N cross T
  166. CrossProduct( textureSpaceBasis[2], textureSpaceBasis[1], textureSpaceBasis[0] );
  167. VectorNormalize( textureSpaceBasis[0] );
  168. VectorNormalize( textureSpaceBasis[1] );
  169. return;
  170. }
  171. // Fall through to the standard algorithm for parallel or antiparallel
  172. }
  173. // floor/ceiling?
  174. if( fabs( surfaceNormal[2] ) > SIN_45_DEGREES )
  175. {
  176. textureSpaceBasis[0][0] = 1.0f;
  177. textureSpaceBasis[0][1] = 0.0f;
  178. textureSpaceBasis[0][2] = 0.0f;
  179. // T = S cross N
  180. CrossProduct( textureSpaceBasis[0], textureSpaceBasis[2], textureSpaceBasis[1] );
  181. // S = N cross T
  182. CrossProduct( textureSpaceBasis[2], textureSpaceBasis[1], textureSpaceBasis[0] );
  183. }
  184. // wall
  185. else
  186. {
  187. textureSpaceBasis[1][0] = 0.0f;
  188. textureSpaceBasis[1][1] = 0.0f;
  189. textureSpaceBasis[1][2] = -1.0f;
  190. // S = N cross T
  191. CrossProduct( textureSpaceBasis[2], textureSpaceBasis[1], textureSpaceBasis[0] );
  192. // T = S cross N
  193. CrossProduct( textureSpaceBasis[0], textureSpaceBasis[2], textureSpaceBasis[1] );
  194. }
  195. VectorNormalize( textureSpaceBasis[0] );
  196. VectorNormalize( textureSpaceBasis[1] );
  197. }
  198. //-----------------------------------------------------------------------------
  199. // Purpose: Clips a texture to a face. Used for decal application.
  200. // NOTE : HL and HL2 generate texcoords for decals differently!!!
  201. // Input : pFace -
  202. // pDecalTex -
  203. // org -
  204. // pOutPoints -
  205. // Output : Returns the number of points places in the pOutPoints array.
  206. //-----------------------------------------------------------------------------
  207. int CreateClippedPoly(CMapFace *pFace, IEditorTexture *pDecalTex, Vector& org, vec5_t *pOutPoints, int nOutSize)
  208. {
  209. float outvert[MAX_CLIPVERT][VERTEXSIZE];
  210. Assert(nOutSize <= MAX_CLIPVERT); // This code uses temp buffers of this size.
  211. /*#ifdef SDK_BUILD
  212. BUG: THIS IS THE HL1 VERSION! SWITCH BETWEEN THESE ALGORITHMS AT RUNTIME
  213. Vector vecOrg, vecSAxis, vecTAxis;
  214. // Copy the origin.
  215. vecOrg = org;
  216. // Get the U/V axes for this face.
  217. vecSAxis = pFace->texture.UAxis;
  218. vecTAxis = pFace->texture.VAxis;
  219. float decalwidth = pDecalTex->GetWidth();
  220. float decalheight = pDecalTex->GetHeight();
  221. float scale = 1.0f;
  222. IEditorTexture *pFaceTex = pFace->GetTexture();
  223. float scalex = scale * (float)pFaceTex->GetWidth() / decalwidth;
  224. float scaley = scale * (float)pFaceTex->GetHeight() / decalheight;
  225. float u = DotProduct(vecSAxis, vecOrg);
  226. float v = DotProduct(vecTAxis, vecOrg);
  227. u -= decalwidth / 2;
  228. v -= decalheight / 2;
  229. u /= pFaceTex->GetWidth();
  230. v /= pFaceTex->GetHeight();
  231. // Generate texture coordinates for each vertex in decal s,t space
  232. Vector *pVertex = pFace->Points;
  233. float curU, curV;
  234. for (int j = 0; j < pFace->nPoints; j++, pVertex++)
  235. {
  236. // Copy X, Y, & Z
  237. g_vert[j][0] = pVertex[0][0];
  238. g_vert[j][1] = pVertex[0][1];
  239. g_vert[j][2] = pVertex[0][2];
  240. // Get u, v coordinates of vertex in DECAL SPACE
  241. curU = DotProduct(vecSAxis, *pVertex) / pFaceTex->GetWidth();
  242. curV = DotProduct(vecTAxis, *pVertex) / pFaceTex->GetHeight();
  243. // Generate U & V
  244. g_vert[j][3] = (curU - u) * scalex; // Decal relative texture coordinates
  245. g_vert[j][4] = (curV - v) * scaley;
  246. }
  247. #else */
  248. // THIS IS THE HL2 VERSION!
  249. float decalScale = pDecalTex->GetDecalScale();
  250. float decalWidth = pDecalTex->GetWidth();
  251. float decalHeight = pDecalTex->GetHeight();
  252. Vector textureSpaceBasis[3];
  253. R_DecalComputeBasis( pFace->plane.normal, NULL,
  254. false, textureSpaceBasis );
  255. float u = DotProduct(textureSpaceBasis[0], org);
  256. float v = DotProduct(textureSpaceBasis[1], org);
  257. // subtract the world space dist from the center of the
  258. // decal to the origin of the decal
  259. u -= decalWidth * decalScale / 2.0f;
  260. v -= decalHeight * decalScale / 2.0f;
  261. float scalex = 1.0f / ( decalScale * decalWidth );
  262. float scaley = 1.0f / ( decalScale * decalHeight );
  263. // Generate texture coordinates for each vertex in decal s,t space
  264. Vector *pVertex = pFace->Points;
  265. float curU, curV;
  266. for (int j = 0; j < pFace->nPoints; j++, pVertex++)
  267. {
  268. // Copy X, Y, & Z
  269. g_vert[j][0] = pVertex[0][0];
  270. g_vert[j][1] = pVertex[0][1];
  271. g_vert[j][2] = pVertex[0][2];
  272. // Get u, v coordinates of vertex in DECAL SPACE
  273. curU = DotProduct(textureSpaceBasis[0], *pVertex);
  274. curV = DotProduct(textureSpaceBasis[1], *pVertex);
  275. // Generate U & V
  276. g_vert[j][3] = (curU - u) * scalex; // Decal relative texture coordinates
  277. g_vert[j][4] = (curV - v) * scaley;
  278. }
  279. // #endif
  280. // Clip the polygon to the decal texture space
  281. // FIXME: Yes this realy copies the vertex list 4 times !!
  282. int nMaxVerts = min(nOutSize, MAX_CLIPVERT);
  283. g_outCount = SHClip( g_vert[0], pFace->nPoints, outvert[0], nMaxVerts, 0 ); // clip left
  284. g_outCount = SHClip( outvert[0], g_outCount, g_vert[0], nMaxVerts, 1 ); // clip right
  285. g_outCount = SHClip( g_vert[0], g_outCount, outvert[0], nMaxVerts, 2 ); // clip top
  286. g_outCount = SHClip( outvert[0], g_outCount, g_vert[0], nMaxVerts, 3 ); // clip bottom
  287. memcpy(pOutPoints, g_vert, sizeof(vec5_t) * g_outCount);
  288. return(g_outCount);
  289. }