tr_frontend_deform.cpp 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #pragma hdrstop
  21. #include "../idlib/precompiled.h"
  22. #include "tr_local.h"
  23. #include "Model_local.h"
  24. /*
  25. ==========================================================================================
  26. DEFORM SURFACES
  27. ==========================================================================================
  28. */
  29. /*
  30. =================
  31. R_FinishDeform
  32. =================
  33. */
  34. static drawSurf_t * R_FinishDeform( drawSurf_t * surf, srfTriangles_t * newTri, const idDrawVert * newVerts, const triIndex_t * newIndexes ) {
  35. newTri->ambientCache = vertexCache.AllocVertex( newVerts, ALIGN( newTri->numVerts * sizeof( idDrawVert ), VERTEX_CACHE_ALIGN ) );
  36. newTri->indexCache = vertexCache.AllocIndex( newIndexes, ALIGN( newTri->numIndexes * sizeof( triIndex_t ), INDEX_CACHE_ALIGN ) );
  37. surf->frontEndGeo = newTri;
  38. surf->numIndexes = newTri->numIndexes;
  39. surf->ambientCache = newTri->ambientCache;
  40. surf->indexCache = newTri->indexCache;
  41. surf->shadowCache = 0;
  42. surf->jointCache = 0;
  43. surf->nextOnLight = NULL;
  44. return surf;
  45. }
  46. /*
  47. =====================
  48. R_AutospriteDeform
  49. Assuming all the triangles for this shader are independant
  50. quads, rebuild them as forward facing sprites.
  51. =====================
  52. */
  53. static drawSurf_t * R_AutospriteDeform( drawSurf_t *surf ) {
  54. const srfTriangles_t * srcTri = surf->frontEndGeo;
  55. if ( srcTri->numVerts & 3 ) {
  56. common->Warning( "R_AutospriteDeform: shader had odd vertex count" );
  57. return NULL;
  58. }
  59. if ( srcTri->numIndexes != ( srcTri->numVerts >> 2 ) * 6 ) {
  60. common->Warning( "R_AutospriteDeform: autosprite had odd index count" );
  61. return NULL;
  62. }
  63. const idJointMat * joints = ( srcTri->staticModelWithJoints != NULL && r_useGPUSkinning.GetBool() ) ? srcTri->staticModelWithJoints->jointsInverted : NULL;
  64. idVec3 leftDir;
  65. idVec3 upDir;
  66. R_GlobalVectorToLocal( surf->space->modelMatrix, tr.viewDef->renderView.viewaxis[1], leftDir );
  67. R_GlobalVectorToLocal( surf->space->modelMatrix, tr.viewDef->renderView.viewaxis[2], upDir );
  68. if ( tr.viewDef->isMirror ) {
  69. leftDir = vec3_origin - leftDir;
  70. }
  71. // the srfTriangles_t are in frame memory and will be automatically disposed of
  72. srfTriangles_t * newTri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *newTri ), FRAME_ALLOC_SURFACE_TRIANGLES );
  73. newTri->numVerts = srcTri->numVerts;
  74. newTri->numIndexes = srcTri->numIndexes;
  75. idDrawVert * newVerts = (idDrawVert *)_alloca16( ALIGN( srcTri->numVerts * sizeof( idDrawVert ), 16 ) );
  76. triIndex_t * newIndexes = (triIndex_t *)_alloca16( ALIGN( srcTri->numIndexes * sizeof( triIndex_t ), 16 ) );
  77. for ( int i = 0; i < srcTri->numVerts; i += 4 ) {
  78. // find the midpoint
  79. newVerts[i+0] = idDrawVert::GetSkinnedDrawVert( srcTri->verts[i + 0], joints );
  80. newVerts[i+1] = idDrawVert::GetSkinnedDrawVert( srcTri->verts[i + 1], joints );
  81. newVerts[i+2] = idDrawVert::GetSkinnedDrawVert( srcTri->verts[i + 2], joints );
  82. newVerts[i+3] = idDrawVert::GetSkinnedDrawVert( srcTri->verts[i + 3], joints );
  83. idVec3 mid;
  84. mid[0] = 0.25f * ( newVerts[i+0].xyz[0] + newVerts[i+1].xyz[0] + newVerts[i+2].xyz[0] + newVerts[i+3].xyz[0] );
  85. mid[1] = 0.25f * ( newVerts[i+0].xyz[1] + newVerts[i+1].xyz[1] + newVerts[i+2].xyz[1] + newVerts[i+3].xyz[1] );
  86. mid[2] = 0.25f * ( newVerts[i+0].xyz[2] + newVerts[i+1].xyz[2] + newVerts[i+2].xyz[2] + newVerts[i+3].xyz[2] );
  87. const idVec3 delta = newVerts[i+0].xyz - mid;
  88. const float radius = delta.Length() * idMath::SQRT_1OVER2;
  89. const idVec3 left = leftDir * radius;
  90. const idVec3 up = upDir * radius;
  91. newVerts[i+0].xyz = mid + left + up;
  92. newVerts[i+0].SetTexCoord( 0, 0 );
  93. newVerts[i+1].xyz = mid - left + up;
  94. newVerts[i+1].SetTexCoord( 1, 0 );
  95. newVerts[i+2].xyz = mid - left - up;
  96. newVerts[i+2].SetTexCoord( 1, 1 );
  97. newVerts[i+3].xyz = mid + left - up;
  98. newVerts[i+3].SetTexCoord( 0, 1 );
  99. newIndexes[6*(i>>2)+0] = i+0;
  100. newIndexes[6*(i>>2)+1] = i+1;
  101. newIndexes[6*(i>>2)+2] = i+2;
  102. newIndexes[6*(i>>2)+3] = i+0;
  103. newIndexes[6*(i>>2)+4] = i+2;
  104. newIndexes[6*(i>>2)+5] = i+3;
  105. }
  106. return R_FinishDeform( surf, newTri, newVerts, newIndexes );
  107. }
  108. /*
  109. =====================
  110. R_TubeDeform
  111. Will pivot a rectangular quad along the center of its long axis.
  112. Note that a geometric tube with even quite a few sides will almost certainly render
  113. much faster than this, so this should only be for faked volumetric tubes.
  114. Make sure this is used with twosided translucent shaders, because the exact side
  115. order may not be correct.
  116. =====================
  117. */
  118. static drawSurf_t * R_TubeDeform( drawSurf_t * surf ) {
  119. static int edgeVerts[6][2] = {
  120. { 0, 1 },
  121. { 1, 2 },
  122. { 2, 0 },
  123. { 3, 4 },
  124. { 4, 5 },
  125. { 5, 3 }
  126. };
  127. const srfTriangles_t * srcTri = surf->frontEndGeo;
  128. if ( srcTri->numVerts & 3 ) {
  129. common->Error( "R_TubeDeform: shader had odd vertex count" );
  130. }
  131. if ( srcTri->numIndexes != ( srcTri->numVerts >> 2 ) * 6 ) {
  132. common->Error( "R_TubeDeform: autosprite had odd index count" );
  133. }
  134. const idJointMat * joints = ( srcTri->staticModelWithJoints != NULL && r_useGPUSkinning.GetBool() ) ? srcTri->staticModelWithJoints->jointsInverted : NULL;
  135. // we need the view direction to project the minor axis of the tube
  136. // as the view changes
  137. idVec3 localView;
  138. R_GlobalPointToLocal( surf->space->modelMatrix, tr.viewDef->renderView.vieworg, localView );
  139. // the srfTriangles_t are in frame memory and will be automatically disposed of
  140. srfTriangles_t * newTri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *newTri ), FRAME_ALLOC_SURFACE_TRIANGLES );
  141. newTri->numVerts = srcTri->numVerts;
  142. newTri->numIndexes = srcTri->numIndexes;
  143. idDrawVert * newVerts = (idDrawVert *)_alloca16( ALIGN( srcTri->numVerts * sizeof( idDrawVert ), 16 ) );
  144. for ( int i = 0; i < srcTri->numVerts; i++ ) {
  145. newVerts[i].Clear();
  146. }
  147. // this is a lot of work for two triangles...
  148. // we could precalculate a lot if it is an issue, but it would mess up the shader abstraction
  149. for ( int i = 0, indexes = 0; i < srcTri->numVerts; i += 4, indexes += 6 ) {
  150. // identify the two shortest edges out of the six defined by the indexes
  151. int nums[2] = { 0, 0 };
  152. float lengths[2] = { 999999.0f, 999999.0f };
  153. for ( int j = 0; j < 6; j++ ) {
  154. const idVec3 v1 = idDrawVert::GetSkinnedDrawVertPosition( srcTri->verts[srcTri->indexes[i + edgeVerts[j][0]]], joints );
  155. const idVec3 v2 = idDrawVert::GetSkinnedDrawVertPosition( srcTri->verts[srcTri->indexes[i + edgeVerts[j][1]]], joints );
  156. const float l = ( v1 - v2 ).Length();
  157. if ( l < lengths[0] ) {
  158. nums[1] = nums[0];
  159. lengths[1] = lengths[0];
  160. nums[0] = j;
  161. lengths[0] = l;
  162. } else if ( l < lengths[1] ) {
  163. nums[1] = j;
  164. lengths[1] = l;
  165. }
  166. }
  167. // find the midpoints of the two short edges, which
  168. // will give us the major axis in object coordinates
  169. idVec3 mid[2];
  170. for ( int j = 0; j < 2; j++ ) {
  171. const idVec3 v1 = idDrawVert::GetSkinnedDrawVertPosition( srcTri->verts[srcTri->indexes[i+edgeVerts[nums[j]][0]]], joints );
  172. const idVec3 v2 = idDrawVert::GetSkinnedDrawVertPosition( srcTri->verts[srcTri->indexes[i+edgeVerts[nums[j]][1]]], joints );
  173. mid[j][0] = 0.5f * ( v1[0] + v2[0] );
  174. mid[j][1] = 0.5f * ( v1[1] + v2[1] );
  175. mid[j][2] = 0.5f * ( v1[2] + v2[2] );
  176. }
  177. // find the vector of the major axis
  178. const idVec3 major = mid[1] - mid[0];
  179. // re-project the points
  180. for ( int j = 0; j < 2; j++ ) {
  181. const int i1 = srcTri->indexes[i+edgeVerts[nums[j]][0]];
  182. const int i2 = srcTri->indexes[i+edgeVerts[nums[j]][1]];
  183. newVerts[i1] = idDrawVert::GetSkinnedDrawVert( srcTri->verts[i1], joints );
  184. newVerts[i2] = idDrawVert::GetSkinnedDrawVert( srcTri->verts[i2], joints );
  185. const float l = 0.5f * lengths[j];
  186. // cross this with the view direction to get minor axis
  187. idVec3 dir = mid[j] - localView;
  188. idVec3 minor;
  189. minor.Cross( major, dir );
  190. minor.Normalize();
  191. if ( j ) {
  192. newVerts[i1].xyz = mid[j] - l * minor;
  193. newVerts[i2].xyz = mid[j] + l * minor;
  194. } else {
  195. newVerts[i1].xyz = mid[j] + l * minor;
  196. newVerts[i2].xyz = mid[j] - l * minor;
  197. }
  198. }
  199. }
  200. return R_FinishDeform( surf, newTri, newVerts, srcTri->indexes );
  201. }
  202. /*
  203. =====================
  204. R_WindingFromTriangles
  205. =====================
  206. */
  207. #define MAX_TRI_WINDING_INDEXES 16
  208. int R_WindingFromTriangles( const srfTriangles_t *tri, triIndex_t indexes[MAX_TRI_WINDING_INDEXES] ) {
  209. int i, j, k, l;
  210. indexes[0] = tri->indexes[0];
  211. int numIndexes = 1;
  212. int numTris = tri->numIndexes / 3;
  213. do {
  214. // find an edge that goes from the current index to another
  215. // index that isn't already used, and isn't an internal edge
  216. for ( i = 0; i < numTris; i++ ) {
  217. for ( j = 0; j < 3; j++ ) {
  218. if ( tri->indexes[i*3+j] != indexes[numIndexes-1] ) {
  219. continue;
  220. }
  221. int next = tri->indexes[i*3+(j+1)%3];
  222. // make sure it isn't already used
  223. if ( numIndexes == 1 ) {
  224. if ( next == indexes[0] ) {
  225. continue;
  226. }
  227. } else {
  228. for ( k = 1; k < numIndexes; k++ ) {
  229. if ( indexes[k] == next ) {
  230. break;
  231. }
  232. }
  233. if ( k != numIndexes ) {
  234. continue;
  235. }
  236. }
  237. // make sure it isn't an interior edge
  238. for ( k = 0; k < numTris; k++ ) {
  239. if ( k == i ) {
  240. continue;
  241. }
  242. for ( l = 0; l < 3; l++ ) {
  243. int a, b;
  244. a = tri->indexes[k*3+l];
  245. if ( a != next ) {
  246. continue;
  247. }
  248. b = tri->indexes[k*3+(l+1)%3];
  249. if ( b != indexes[numIndexes-1] ) {
  250. continue;
  251. }
  252. // this is an interior edge
  253. break;
  254. }
  255. if ( l != 3 ) {
  256. break;
  257. }
  258. }
  259. if ( k != numTris ) {
  260. continue;
  261. }
  262. // add this to the list
  263. indexes[numIndexes] = next;
  264. numIndexes++;
  265. break;
  266. }
  267. if ( j != 3 ) {
  268. break;
  269. }
  270. }
  271. if ( numIndexes == tri->numVerts ) {
  272. break;
  273. }
  274. } while ( i != numTris );
  275. return numIndexes;
  276. }
  277. /*
  278. =====================
  279. R_FlareDeform
  280. =====================
  281. */
  282. static drawSurf_t * R_FlareDeform( drawSurf_t * surf ) {
  283. const srfTriangles_t * srcTri = surf->frontEndGeo;
  284. assert( srcTri->staticModelWithJoints == NULL );
  285. if ( srcTri->numVerts != 4 || srcTri->numIndexes != 6 ) {
  286. // FIXME: temp hack for flares on tripleted models
  287. common->Warning( "R_FlareDeform: not a single quad" );
  288. return NULL;
  289. }
  290. // find the plane
  291. idPlane plane;
  292. plane.FromPoints( srcTri->verts[srcTri->indexes[0]].xyz, srcTri->verts[srcTri->indexes[1]].xyz, srcTri->verts[srcTri->indexes[2]].xyz );
  293. // if viewer is behind the plane, draw nothing
  294. idVec3 localViewer;
  295. R_GlobalPointToLocal( surf->space->modelMatrix, tr.viewDef->renderView.vieworg, localViewer );
  296. float distFromPlane = localViewer * plane.Normal() + plane[3];
  297. if ( distFromPlane <= 0 ) {
  298. return NULL;
  299. }
  300. idVec3 center = srcTri->verts[0].xyz;
  301. for ( int i = 1; i < srcTri->numVerts; i++ ) {
  302. center += srcTri->verts[i].xyz;
  303. }
  304. center *= 1.0f / srcTri->numVerts;
  305. idVec3 dir = localViewer - center;
  306. dir.Normalize();
  307. const float dot = dir * plane.Normal();
  308. // set vertex colors based on plane angle
  309. int color = idMath::Ftoi( dot * 8 * 256 );
  310. if ( color > 255 ) {
  311. color = 255;
  312. }
  313. triIndex_t indexes[MAX_TRI_WINDING_INDEXES];
  314. int numIndexes = R_WindingFromTriangles( srcTri, indexes );
  315. // only deal with quads
  316. if ( numIndexes != 4 ) {
  317. return NULL;
  318. }
  319. const int maxVerts = 16;
  320. const int maxIndexes = 18 * 3;
  321. // the srfTriangles_t are in frame memory and will be automatically disposed of
  322. srfTriangles_t * newTri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *newTri ), FRAME_ALLOC_SURFACE_TRIANGLES );
  323. newTri->numVerts = maxVerts;
  324. newTri->numIndexes = maxIndexes;
  325. idDrawVert *newVerts = (idDrawVert *)_alloca16( ALIGN( maxVerts * sizeof( idDrawVert ), 16 ) );
  326. idVec3 edgeDir[4][3];
  327. // calculate vector directions
  328. for ( int i = 0; i < 4; i++ ) {
  329. newVerts[i].Clear();
  330. newVerts[i].xyz = srcTri->verts[ indexes[i] ].xyz;
  331. newVerts[i].SetTexCoord( 0.5f, 0.5f );
  332. newVerts[i].color[0] = color;
  333. newVerts[i].color[1] = color;
  334. newVerts[i].color[2] = color;
  335. newVerts[i].color[3] = 255;
  336. idVec3 toEye = srcTri->verts[ indexes[i] ].xyz - localViewer;
  337. toEye.Normalize();
  338. idVec3 d1 = srcTri->verts[ indexes[(i+1)%4] ].xyz - localViewer;
  339. d1.Normalize();
  340. edgeDir[i][2].Cross( toEye, d1 );
  341. edgeDir[i][2].Normalize();
  342. edgeDir[i][2] = vec3_origin - edgeDir[i][2];
  343. idVec3 d2 = srcTri->verts[ indexes[(i+3)%4] ].xyz - localViewer;
  344. d2.Normalize();
  345. edgeDir[i][0].Cross( toEye, d2 );
  346. edgeDir[i][0].Normalize();
  347. edgeDir[i][1] = edgeDir[i][0] + edgeDir[i][2];
  348. edgeDir[i][1].Normalize();
  349. }
  350. const float spread = surf->shaderRegisters[ surf->material->GetDeformRegister(0) ] * r_flareSize.GetFloat();
  351. for ( int i = 4; i < 16; i++ ) {
  352. const int index = ( i - 4 ) / 3;
  353. idVec3 v = srcTri->verts[indexes[index]].xyz + spread * edgeDir[index][( i - 4 ) % 3];
  354. idVec3 dir = v - localViewer;
  355. const float len = dir.Normalize();
  356. const float ang = dir * plane.Normal();
  357. const float newLen = -( distFromPlane / ang );
  358. if ( newLen > 0.0f && newLen < len ) {
  359. v = localViewer + dir * newLen;
  360. }
  361. newVerts[i].Clear();
  362. newVerts[i].xyz = v;
  363. newVerts[i].SetTexCoord( 0.0f, 0.5f );
  364. newVerts[i].color[0] = color;
  365. newVerts[i].color[1] = color;
  366. newVerts[i].color[2] = color;
  367. newVerts[i].color[3] = 255;
  368. }
  369. ALIGNTYPE16 static triIndex_t triIndexes[18*3 + 10] = {
  370. 0, 4,5, 0,5, 6, 0,6,7, 0,7, 1, 1,7, 8, 1,8, 9,
  371. 15, 4,0, 15,0, 3, 3,0,1, 3,1, 2, 2,1, 9, 2,9,10,
  372. 14,15,3, 14,3,13, 13,3,2, 13,2,12, 12,2,11, 11,2,10,
  373. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // to make this a multiple of 16 bytes
  374. };
  375. return R_FinishDeform( surf, newTri, newVerts, triIndexes );
  376. }
  377. /*
  378. =====================
  379. R_ExpandDeform
  380. Expands the surface along it's normals by a shader amount
  381. =====================
  382. */
  383. static drawSurf_t * R_ExpandDeform( drawSurf_t * surf ) {
  384. const srfTriangles_t * srcTri = surf->frontEndGeo;
  385. assert( srcTri->staticModelWithJoints == NULL );
  386. // the srfTriangles_t are in frame memory and will be automatically disposed of
  387. srfTriangles_t * newTri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *newTri ), FRAME_ALLOC_SURFACE_TRIANGLES );
  388. newTri->numVerts = srcTri->numVerts;
  389. newTri->numIndexes = srcTri->numIndexes;
  390. idDrawVert *newVerts = (idDrawVert *)_alloca16( ALIGN( newTri->numVerts * sizeof( idDrawVert ), 16 ) );
  391. const float dist = surf->shaderRegisters[ surf->material->GetDeformRegister(0) ];
  392. for ( int i = 0; i < srcTri->numVerts; i++ ) {
  393. newVerts[i] = srcTri->verts[i];
  394. newVerts[i].xyz = srcTri->verts[i].xyz + srcTri->verts[i].GetNormal() * dist;
  395. }
  396. return R_FinishDeform( surf, newTri, newVerts, srcTri->indexes );
  397. }
  398. /*
  399. =====================
  400. R_MoveDeform
  401. Moves the surface along the X axis, mostly just for demoing the deforms
  402. =====================
  403. */
  404. static drawSurf_t * R_MoveDeform( drawSurf_t * surf ) {
  405. const srfTriangles_t * srcTri = surf->frontEndGeo;
  406. assert( srcTri->staticModelWithJoints == NULL );
  407. // the srfTriangles_t are in frame memory and will be automatically disposed of
  408. srfTriangles_t * newTri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *newTri ), FRAME_ALLOC_SURFACE_TRIANGLES );
  409. newTri->numVerts = srcTri->numVerts;
  410. newTri->numIndexes = srcTri->numIndexes;
  411. idDrawVert *newVerts = (idDrawVert *)_alloca16( ALIGN( newTri->numVerts * sizeof( idDrawVert ), 16 ) );
  412. const float dist = surf->shaderRegisters[ surf->material->GetDeformRegister(0) ];
  413. for ( int i = 0; i < srcTri->numVerts; i++ ) {
  414. newVerts[i] = srcTri->verts[i];
  415. newVerts[i].xyz[0] += dist;
  416. }
  417. return R_FinishDeform( surf, newTri, newVerts, srcTri->indexes );
  418. }
  419. /*
  420. =====================
  421. R_TurbulentDeform
  422. Turbulently deforms the texture coordinates.
  423. =====================
  424. */
  425. static drawSurf_t * R_TurbulentDeform( drawSurf_t * surf ) {
  426. const srfTriangles_t * srcTri = surf->frontEndGeo;
  427. assert( srcTri->staticModelWithJoints == NULL );
  428. // the srfTriangles_t are in frame memory and will be automatically disposed of
  429. srfTriangles_t * newTri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *newTri ), FRAME_ALLOC_SURFACE_TRIANGLES );
  430. newTri->numVerts = srcTri->numVerts;
  431. newTri->numIndexes = srcTri->numIndexes;
  432. idDrawVert *newVerts = (idDrawVert *)_alloca16( ALIGN( newTri->numVerts * sizeof( idDrawVert ), 16 ) );
  433. const idDeclTable * table = (const idDeclTable *)surf->material->GetDeformDecl();
  434. const float range = surf->shaderRegisters[ surf->material->GetDeformRegister(0) ];
  435. const float timeOfs = surf->shaderRegisters[ surf->material->GetDeformRegister(1) ];
  436. const float domain = surf->shaderRegisters[ surf->material->GetDeformRegister(2) ];
  437. const float tOfs = 0.5f;
  438. for ( int i = 0; i < srcTri->numVerts; i++ ) {
  439. float f = srcTri->verts[i].xyz[0] * 0.003f + srcTri->verts[i].xyz[1] * 0.007f + srcTri->verts[i].xyz[2] * 0.011f;
  440. f = timeOfs + domain * f;
  441. f += timeOfs;
  442. idVec2 tempST = srcTri->verts[i].GetTexCoord();
  443. tempST[0] += range * table->TableLookup( f );
  444. tempST[1] += range * table->TableLookup( f + tOfs );
  445. newVerts[i] = srcTri->verts[i];
  446. newVerts[i].SetTexCoord( tempST );
  447. }
  448. return R_FinishDeform( surf, newTri, newVerts, srcTri->indexes );
  449. }
  450. /*
  451. =====================
  452. AddTriangleToIsland_r
  453. =====================
  454. */
  455. #define MAX_EYEBALL_TRIS 10
  456. #define MAX_EYEBALL_ISLANDS 6
  457. typedef struct {
  458. int tris[MAX_EYEBALL_TRIS];
  459. int numTris;
  460. idBounds bounds;
  461. idVec3 mid;
  462. } eyeIsland_t;
  463. static void AddTriangleToIsland_r( const srfTriangles_t *tri, int triangleNum, bool *usedList, eyeIsland_t *island ) {
  464. usedList[triangleNum] = true;
  465. // add to the current island
  466. if ( island->numTris >= MAX_EYEBALL_TRIS ) {
  467. common->Error( "MAX_EYEBALL_TRIS" );
  468. return;
  469. }
  470. island->tris[island->numTris] = triangleNum;
  471. island->numTris++;
  472. const idJointMat * joints = ( tri->staticModelWithJoints != NULL && r_useGPUSkinning.GetBool() ) ? tri->staticModelWithJoints->jointsInverted : NULL;
  473. // recurse into all neighbors
  474. const int a = tri->indexes[triangleNum*3+0];
  475. const int b = tri->indexes[triangleNum*3+1];
  476. const int c = tri->indexes[triangleNum*3+2];
  477. const idVec3 va = idDrawVert::GetSkinnedDrawVertPosition( tri->verts[a], joints );
  478. const idVec3 vb = idDrawVert::GetSkinnedDrawVertPosition( tri->verts[b], joints );
  479. const idVec3 vc = idDrawVert::GetSkinnedDrawVertPosition( tri->verts[c], joints );
  480. island->bounds.AddPoint( va );
  481. island->bounds.AddPoint( vb );
  482. island->bounds.AddPoint( vc );
  483. int numTri = tri->numIndexes / 3;
  484. for ( int i = 0; i < numTri; i++ ) {
  485. if ( usedList[i] ) {
  486. continue;
  487. }
  488. if ( tri->indexes[i*3+0] == a
  489. || tri->indexes[i*3+1] == a
  490. || tri->indexes[i*3+2] == a
  491. || tri->indexes[i*3+0] == b
  492. || tri->indexes[i*3+1] == b
  493. || tri->indexes[i*3+2] == b
  494. || tri->indexes[i*3+0] == c
  495. || tri->indexes[i*3+1] == c
  496. || tri->indexes[i*3+2] == c ) {
  497. AddTriangleToIsland_r( tri, i, usedList, island );
  498. }
  499. }
  500. }
  501. /*
  502. =====================
  503. R_EyeballDeform
  504. Each eyeball surface should have an separate upright triangle behind it, long end
  505. pointing out the eye, and another single triangle in front of the eye for the focus point.
  506. =====================
  507. */
  508. static drawSurf_t * R_EyeballDeform( drawSurf_t * surf ) {
  509. const srfTriangles_t * srcTri = surf->frontEndGeo;
  510. // separate all the triangles into islands
  511. const int numTri = srcTri->numIndexes / 3;
  512. if ( numTri > MAX_EYEBALL_ISLANDS * MAX_EYEBALL_TRIS ) {
  513. common->Printf( "R_EyeballDeform: too many triangles in surface" );
  514. return NULL;
  515. }
  516. eyeIsland_t islands[MAX_EYEBALL_ISLANDS];
  517. bool triUsed[MAX_EYEBALL_ISLANDS*MAX_EYEBALL_TRIS];
  518. memset( triUsed, 0, sizeof( triUsed ) );
  519. int numIslands = 0;
  520. for ( ; numIslands < MAX_EYEBALL_ISLANDS; numIslands++ ) {
  521. islands[numIslands].numTris = 0;
  522. islands[numIslands].bounds.Clear();
  523. int i;
  524. for ( i = 0; i < numTri; i++ ) {
  525. if ( !triUsed[i] ) {
  526. AddTriangleToIsland_r( srcTri, i, triUsed, &islands[numIslands] );
  527. break;
  528. }
  529. }
  530. if ( i == numTri ) {
  531. break;
  532. }
  533. }
  534. // assume we always have two eyes, two origins, and two targets
  535. if ( numIslands != 3 ) {
  536. common->Printf( "R_EyeballDeform: %i triangle islands\n", numIslands );
  537. return NULL;
  538. }
  539. const idJointMat * joints = ( srcTri->staticModelWithJoints != NULL && r_useGPUSkinning.GetBool() ) ? srcTri->staticModelWithJoints->jointsInverted : NULL;
  540. // the srfTriangles_t are in frame memory and will be automatically disposed of
  541. srfTriangles_t * newTri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *newTri ), FRAME_ALLOC_SURFACE_TRIANGLES );
  542. newTri->numVerts = srcTri->numVerts;
  543. newTri->numIndexes = srcTri->numIndexes;
  544. idDrawVert *newVerts = (idDrawVert *)_alloca16( ALIGN( srcTri->numVerts * sizeof( idDrawVert ), 16 ) );
  545. triIndex_t *newIndexes = (triIndex_t *)_alloca16( ALIGN( srcTri->numIndexes * sizeof( triIndex_t ), 16 ) );
  546. // decide which islands are the eyes and points
  547. for ( int i = 0; i < numIslands; i++ ) {
  548. islands[i].mid = islands[i].bounds.GetCenter();
  549. }
  550. int numIndexes = 0;
  551. for ( int i = 0; i < numIslands; i++ ) {
  552. eyeIsland_t * island = &islands[i];
  553. if ( island->numTris == 1 ) {
  554. continue;
  555. }
  556. // the closest single triangle point will be the eye origin
  557. // and the next-to-farthest will be the focal point
  558. idVec3 origin;
  559. idVec3 focus;
  560. int originIsland = 0;
  561. float dist[MAX_EYEBALL_ISLANDS];
  562. int sortOrder[MAX_EYEBALL_ISLANDS];
  563. for ( int j = 0; j < numIslands; j++ ) {
  564. idVec3 dir = islands[j].mid - island->mid;
  565. dist[j] = dir.Length();
  566. sortOrder[j] = j;
  567. for ( int k = j - 1; k >= 0; k-- ) {
  568. if ( dist[k] > dist[k+1] ) {
  569. int temp = sortOrder[k];
  570. sortOrder[k] = sortOrder[k+1];
  571. sortOrder[k+1] = temp;
  572. float ftemp = dist[k];
  573. dist[k] = dist[k+1];
  574. dist[k+1] = ftemp;
  575. }
  576. }
  577. }
  578. originIsland = sortOrder[1];
  579. origin = islands[originIsland].mid;
  580. focus = islands[sortOrder[2]].mid;
  581. // determine the projection directions based on the origin island triangle
  582. idVec3 dir = focus - origin;
  583. dir.Normalize();
  584. const idVec3 p1 = idDrawVert::GetSkinnedDrawVertPosition( srcTri->verts[srcTri->indexes[islands[originIsland].tris[0] + 0]], joints );
  585. const idVec3 p2 = idDrawVert::GetSkinnedDrawVertPosition( srcTri->verts[srcTri->indexes[islands[originIsland].tris[0] + 1]], joints );
  586. const idVec3 p3 = idDrawVert::GetSkinnedDrawVertPosition( srcTri->verts[srcTri->indexes[islands[originIsland].tris[0] + 2]], joints );
  587. idVec3 v1 = p2 - p1;
  588. v1.Normalize();
  589. idVec3 v2 = p3 - p1;
  590. v2.Normalize();
  591. // texVec[0] will be the normal to the origin triangle
  592. idVec3 texVec[2];
  593. texVec[0].Cross( v1, v2 );
  594. texVec[1].Cross( texVec[0], dir );
  595. for ( int j = 0; j < 2; j++ ) {
  596. texVec[j] -= dir * ( texVec[j] * dir );
  597. texVec[j].Normalize();
  598. }
  599. // emit these triangles, generating the projected texcoords
  600. for ( int j = 0; j < islands[i].numTris; j++ ) {
  601. for ( int k = 0; k < 3; k++ ) {
  602. int index = islands[i].tris[j] * 3;
  603. index = srcTri->indexes[index + k];
  604. newIndexes[numIndexes++] = index;
  605. newVerts[index] = idDrawVert::GetSkinnedDrawVert( srcTri->verts[index], joints );
  606. const idVec3 local = newVerts[index].xyz - origin;
  607. newVerts[index].SetTexCoord( 0.5f + local * texVec[0], 0.5f + local * texVec[1] );
  608. }
  609. }
  610. }
  611. newTri->numIndexes = numIndexes;
  612. return R_FinishDeform( surf, newTri, newVerts, newIndexes );
  613. }
  614. /*
  615. =====================
  616. R_ParticleDeform
  617. Emit particles from the surface.
  618. =====================
  619. */
  620. static drawSurf_t * R_ParticleDeform( drawSurf_t *surf, bool useArea ) {
  621. const renderEntity_t * renderEntity = &surf->space->entityDef->parms;
  622. const viewDef_t * viewDef = tr.viewDef;
  623. const idDeclParticle * particleSystem = (const idDeclParticle *)surf->material->GetDeformDecl();
  624. const srfTriangles_t * srcTri = surf->frontEndGeo;
  625. if ( r_skipParticles.GetBool() ) {
  626. return NULL;
  627. }
  628. //
  629. // calculate the area of all the triangles
  630. //
  631. int numSourceTris = surf->frontEndGeo->numIndexes / 3;
  632. float totalArea = 0.0f;
  633. float * sourceTriAreas = NULL;
  634. const idJointMat * joints = ( ( srcTri->staticModelWithJoints != NULL ) && r_useGPUSkinning.GetBool() ) ? srcTri->staticModelWithJoints->jointsInverted : NULL;
  635. if ( useArea ) {
  636. sourceTriAreas = (float *)_alloca( sizeof( *sourceTriAreas ) * numSourceTris );
  637. int triNum = 0;
  638. for ( int i = 0; i < srcTri->numIndexes; i += 3, triNum++ ) {
  639. float area = idWinding::TriangleArea( idDrawVert::GetSkinnedDrawVertPosition( srcTri->verts[ srcTri->indexes[ i+0 ] ], joints ),
  640. idDrawVert::GetSkinnedDrawVertPosition( srcTri->verts[ srcTri->indexes[ i+1 ] ], joints ),
  641. idDrawVert::GetSkinnedDrawVertPosition( srcTri->verts[ srcTri->indexes[ i+2 ] ], joints ) );
  642. sourceTriAreas[triNum] = totalArea;
  643. totalArea += area;
  644. }
  645. }
  646. //
  647. // create the particles almost exactly the way idRenderModelPrt does
  648. //
  649. particleGen_t g;
  650. g.renderEnt = renderEntity;
  651. g.renderView = &viewDef->renderView;
  652. g.origin.Zero();
  653. g.axis = mat3_identity;
  654. int maxStageParticles[MAX_PARTICLE_STAGES] = { 0 };
  655. int maxStageQuads[MAX_PARTICLE_STAGES] = { 0 };
  656. int maxQuads = 0;
  657. for ( int stageNum = 0; stageNum < particleSystem->stages.Num(); stageNum++ ) {
  658. idParticleStage *stage = particleSystem->stages[stageNum];
  659. if ( stage->material == NULL ) {
  660. continue;
  661. }
  662. if ( stage->cycleMsec == 0 ) {
  663. continue;
  664. }
  665. if ( stage->hidden ) { // just for gui particle editor use
  666. continue;
  667. }
  668. // we interpret stage->totalParticles as "particles per map square area"
  669. // so the systems look the same on different size surfaces
  670. const int totalParticles = ( useArea ) ? idMath::Ftoi( stage->totalParticles * totalArea * ( 1.0f / 4096.0f ) ) : ( stage->totalParticles );
  671. const int numQuads = totalParticles * stage->NumQuadsPerParticle() * ( ( useArea ) ? 1 : numSourceTris );
  672. maxStageParticles[stageNum] = totalParticles;
  673. maxStageQuads[stageNum] = numQuads;
  674. maxQuads = Max( maxQuads, numQuads );
  675. }
  676. if ( maxQuads == 0 ) {
  677. return NULL;
  678. }
  679. idTempArray<byte> tempVerts( ALIGN( maxQuads * 4 * sizeof( idDrawVert ), 16 ) );
  680. idDrawVert *newVerts = (idDrawVert *) tempVerts.Ptr();
  681. idTempArray<byte> tempIndex( ALIGN( maxQuads * 6 * sizeof( triIndex_t ), 16 ) );
  682. triIndex_t *newIndexes = (triIndex_t *) tempIndex.Ptr();
  683. drawSurf_t * drawSurfList = NULL;
  684. for ( int stageNum = 0; stageNum < particleSystem->stages.Num(); stageNum++ ) {
  685. if ( maxStageQuads[stageNum] == 0 ) {
  686. continue;
  687. }
  688. idParticleStage *stage = particleSystem->stages[stageNum];
  689. int numVerts = 0;
  690. for ( int currentTri = 0; currentTri < ( ( useArea ) ? 1 : numSourceTris ); currentTri++ ) {
  691. idRandom steppingRandom;
  692. idRandom steppingRandom2;
  693. int stageAge = g.renderView->time[renderEntity->timeGroup] + idMath::Ftoi( renderEntity->shaderParms[SHADERPARM_TIMEOFFSET] * 1000.0f - stage->timeOffset * 1000.0f );
  694. int stageCycle = stageAge / stage->cycleMsec;
  695. // some particles will be in this cycle, some will be in the previous cycle
  696. steppingRandom.SetSeed( ( ( stageCycle << 10 ) & idRandom::MAX_RAND ) ^ idMath::Ftoi( renderEntity->shaderParms[SHADERPARM_DIVERSITY] * idRandom::MAX_RAND ) );
  697. steppingRandom2.SetSeed( ( ( ( stageCycle - 1 ) << 10 ) & idRandom::MAX_RAND ) ^ idMath::Ftoi( renderEntity->shaderParms[SHADERPARM_DIVERSITY] * idRandom::MAX_RAND ) );
  698. for ( int index = 0; index < maxStageParticles[stageNum]; index++ ) {
  699. g.index = index;
  700. // bump the random
  701. steppingRandom.RandomInt();
  702. steppingRandom2.RandomInt();
  703. // calculate local age for this index
  704. int bunchOffset = idMath::Ftoi( stage->particleLife * 1000 * stage->spawnBunching * index / maxStageParticles[stageNum] );
  705. int particleAge = stageAge - bunchOffset;
  706. int particleCycle = particleAge / stage->cycleMsec;
  707. if ( particleCycle < 0 ) {
  708. // before the particleSystem spawned
  709. continue;
  710. }
  711. if ( stage->cycles != 0.0f && particleCycle >= stage->cycles ) {
  712. // cycled systems will only run cycle times
  713. continue;
  714. }
  715. int inCycleTime = particleAge - particleCycle * stage->cycleMsec;
  716. if ( renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME] != 0.0f &&
  717. g.renderView->time[renderEntity->timeGroup] - inCycleTime >= renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME] * 1000.0f ) {
  718. // don't fire any more particles
  719. continue;
  720. }
  721. // supress particles before or after the age clamp
  722. g.frac = (float)inCycleTime / ( stage->particleLife * 1000.0f );
  723. if ( g.frac < 0.0f ) {
  724. // yet to be spawned
  725. continue;
  726. }
  727. if ( g.frac > 1.0f ) {
  728. // this particle is in the deadTime band
  729. continue;
  730. }
  731. if ( particleCycle == stageCycle ) {
  732. g.random = steppingRandom;
  733. } else {
  734. g.random = steppingRandom2;
  735. }
  736. //---------------
  737. // locate the particle origin and axis somewhere on the surface
  738. //---------------
  739. int pointTri = currentTri;
  740. if ( useArea ) {
  741. // select a triangle based on an even area distribution
  742. pointTri = idBinSearch_LessEqual<float>( sourceTriAreas, numSourceTris, g.random.RandomFloat() * totalArea );
  743. }
  744. // now pick a random point inside pointTri
  745. const idDrawVert v1 = idDrawVert::GetSkinnedDrawVert( srcTri->verts[ srcTri->indexes[ pointTri * 3 + 0 ] ], joints );
  746. const idDrawVert v2 = idDrawVert::GetSkinnedDrawVert( srcTri->verts[ srcTri->indexes[ pointTri * 3 + 1 ] ], joints );
  747. const idDrawVert v3 = idDrawVert::GetSkinnedDrawVert( srcTri->verts[ srcTri->indexes[ pointTri * 3 + 2 ] ], joints );
  748. float f1 = g.random.RandomFloat();
  749. float f2 = g.random.RandomFloat();
  750. float f3 = g.random.RandomFloat();
  751. float ft = 1.0f / ( f1 + f2 + f3 + 0.0001f );
  752. f1 *= ft;
  753. f2 *= ft;
  754. f3 *= ft;
  755. g.origin = v1.xyz * f1 + v2.xyz * f2 + v3.xyz * f3;
  756. g.axis[0] = v1.GetTangent() * f1 + v2.GetTangent() * f2 + v3.GetTangent() * f3;
  757. g.axis[1] = v1.GetBiTangent() * f1 + v2.GetBiTangent() * f2 + v3.GetBiTangent() * f3;
  758. g.axis[2] = v1.GetNormal() * f1 + v2.GetNormal() * f2 + v3.GetNormal() * f3;
  759. // this is needed so aimed particles can calculate origins at different times
  760. g.originalRandom = g.random;
  761. g.age = g.frac * stage->particleLife;
  762. // if the particle doesn't get drawn because it is faded out or beyond a kill region,
  763. // don't increment the verts
  764. numVerts += stage->CreateParticle( &g, newVerts + numVerts );
  765. }
  766. }
  767. if ( numVerts == 0 ) {
  768. continue;
  769. }
  770. // build the index list
  771. int numIndexes = 0;
  772. for ( int i = 0; i < numVerts; i += 4 ) {
  773. newIndexes[numIndexes + 0] = i + 0;
  774. newIndexes[numIndexes + 1] = i + 2;
  775. newIndexes[numIndexes + 2] = i + 3;
  776. newIndexes[numIndexes + 3] = i + 0;
  777. newIndexes[numIndexes + 4] = i + 3;
  778. newIndexes[numIndexes + 5] = i + 1;
  779. numIndexes += 6;
  780. }
  781. // allocate a srfTriangles in temp memory that can hold all the particles
  782. srfTriangles_t * newTri = (srfTriangles_t *)R_ClearedFrameAlloc( sizeof( *newTri ), FRAME_ALLOC_SURFACE_TRIANGLES );
  783. newTri->bounds = stage->bounds; // just always draw the particles
  784. newTri->numVerts = numVerts;
  785. newTri->numIndexes = numIndexes;
  786. newTri->ambientCache = vertexCache.AllocVertex( newVerts, ALIGN( numVerts * sizeof( idDrawVert ), VERTEX_CACHE_ALIGN ) );
  787. newTri->indexCache = vertexCache.AllocIndex( newIndexes, ALIGN( numIndexes * sizeof( triIndex_t ), INDEX_CACHE_ALIGN ) );
  788. drawSurf_t * drawSurf = (drawSurf_t *)R_FrameAlloc( sizeof( *drawSurf ), FRAME_ALLOC_DRAW_SURFACE );
  789. drawSurf->frontEndGeo = newTri;
  790. drawSurf->numIndexes = newTri->numIndexes;
  791. drawSurf->ambientCache = newTri->ambientCache;
  792. drawSurf->indexCache = newTri->indexCache;
  793. drawSurf->shadowCache = 0;
  794. drawSurf->jointCache = 0;
  795. drawSurf->space = surf->space;
  796. drawSurf->scissorRect = surf->scissorRect;
  797. drawSurf->extraGLState = 0;
  798. drawSurf->renderZFail = 0;
  799. R_SetupDrawSurfShader( drawSurf, stage->material, renderEntity );
  800. drawSurf->linkChain = NULL;
  801. drawSurf->nextOnLight = drawSurfList;
  802. drawSurfList = drawSurf;
  803. }
  804. return drawSurfList;
  805. }
  806. /*
  807. =================
  808. R_DeformDrawSurf
  809. =================
  810. */
  811. drawSurf_t * R_DeformDrawSurf( drawSurf_t * drawSurf ) {
  812. if ( drawSurf->material == NULL ) {
  813. return NULL;
  814. }
  815. if ( r_skipDeforms.GetBool() ) {
  816. return drawSurf;
  817. }
  818. switch ( drawSurf->material->Deform() ) {
  819. case DFRM_SPRITE: return R_AutospriteDeform( drawSurf );
  820. case DFRM_TUBE: return R_TubeDeform( drawSurf );
  821. case DFRM_FLARE: return R_FlareDeform( drawSurf );
  822. case DFRM_EXPAND: return R_ExpandDeform( drawSurf );
  823. case DFRM_MOVE: return R_MoveDeform( drawSurf );
  824. case DFRM_TURB: return R_TurbulentDeform( drawSurf );
  825. case DFRM_EYEBALL: return R_EyeballDeform( drawSurf );
  826. case DFRM_PARTICLE: return R_ParticleDeform( drawSurf, true );
  827. case DFRM_PARTICLE2: return R_ParticleDeform( drawSurf, false );
  828. default: return NULL;
  829. }
  830. }