ModelDecal.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 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 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 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 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 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. #include "../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "tr_local.h"
  23. #include "Model_local.h"
  24. // decalFade filter 5 0.1
  25. // polygonOffset
  26. // {
  27. // map invertColor( textures/splat )
  28. // blend GL_ZERO GL_ONE_MINUS_SRC
  29. // vertexColor
  30. // clamp
  31. // }
  32. /*
  33. ==================
  34. idRenderModelDecal::idRenderModelDecal
  35. ==================
  36. */
  37. idRenderModelDecal::idRenderModelDecal( void ) {
  38. memset( &tri, 0, sizeof( tri ) );
  39. tri.verts = verts;
  40. tri.indexes = indexes;
  41. material = NULL;
  42. nextDecal = NULL;
  43. }
  44. /*
  45. ==================
  46. idRenderModelDecal::~idRenderModelDecal
  47. ==================
  48. */
  49. idRenderModelDecal::~idRenderModelDecal( void ) {
  50. }
  51. /*
  52. ==================
  53. idRenderModelDecal::idRenderModelDecal
  54. ==================
  55. */
  56. idRenderModelDecal *idRenderModelDecal::Alloc( void ) {
  57. return new idRenderModelDecal;
  58. }
  59. /*
  60. ==================
  61. idRenderModelDecal::idRenderModelDecal
  62. ==================
  63. */
  64. void idRenderModelDecal::Free( idRenderModelDecal *decal ) {
  65. delete decal;
  66. }
  67. /*
  68. =================
  69. idRenderModelDecal::CreateProjectionInfo
  70. =================
  71. */
  72. bool idRenderModelDecal::CreateProjectionInfo( decalProjectionInfo_t &info, const idFixedWinding &winding, const idVec3 &projectionOrigin, const bool parallel, const float fadeDepth, const idMaterial *material, const int startTime ) {
  73. if ( winding.GetNumPoints() != NUM_DECAL_BOUNDING_PLANES - 2 ) {
  74. common->Printf( "idRenderModelDecal::CreateProjectionInfo: winding must have %d points\n", NUM_DECAL_BOUNDING_PLANES - 2 );
  75. return false;
  76. }
  77. assert( material != NULL );
  78. info.projectionOrigin = projectionOrigin;
  79. info.material = material;
  80. info.parallel = parallel;
  81. info.fadeDepth = fadeDepth;
  82. info.startTime = startTime;
  83. info.force = false;
  84. // get the winding plane and the depth of the projection volume
  85. idPlane windingPlane;
  86. winding.GetPlane( windingPlane );
  87. float depth = windingPlane.Distance( projectionOrigin );
  88. // find the bounds for the projection
  89. winding.GetBounds( info.projectionBounds );
  90. if ( parallel ) {
  91. info.projectionBounds.ExpandSelf( depth );
  92. } else {
  93. info.projectionBounds.AddPoint( projectionOrigin );
  94. }
  95. // calculate the world space projection volume bounding planes, positive sides face outside the decal
  96. if ( parallel ) {
  97. for ( int i = 0; i < winding.GetNumPoints(); i++ ) {
  98. idVec3 edge = winding[(i+1)%winding.GetNumPoints()].ToVec3() - winding[i].ToVec3();
  99. info.boundingPlanes[i].Normal().Cross( windingPlane.Normal(), edge );
  100. info.boundingPlanes[i].Normalize();
  101. info.boundingPlanes[i].FitThroughPoint( winding[i].ToVec3() );
  102. }
  103. } else {
  104. for ( int i = 0; i < winding.GetNumPoints(); i++ ) {
  105. info.boundingPlanes[i].FromPoints( projectionOrigin, winding[i].ToVec3(), winding[(i+1)%winding.GetNumPoints()].ToVec3() );
  106. }
  107. }
  108. info.boundingPlanes[NUM_DECAL_BOUNDING_PLANES - 2] = windingPlane;
  109. info.boundingPlanes[NUM_DECAL_BOUNDING_PLANES - 2][3] -= depth;
  110. info.boundingPlanes[NUM_DECAL_BOUNDING_PLANES - 1] = -windingPlane;
  111. // fades will be from these plane
  112. info.fadePlanes[0] = windingPlane;
  113. info.fadePlanes[0][3] -= fadeDepth;
  114. info.fadePlanes[1] = -windingPlane;
  115. info.fadePlanes[1][3] += depth - fadeDepth;
  116. // calculate the texture vectors for the winding
  117. float len, texArea, inva;
  118. idVec3 temp;
  119. idVec5 d0, d1;
  120. const idVec5 &a = winding[0];
  121. const idVec5 &b = winding[1];
  122. const idVec5 &c = winding[2];
  123. d0 = b.ToVec3() - a.ToVec3();
  124. d0.s = b.s - a.s;
  125. d0.t = b.t - a.t;
  126. d1 = c.ToVec3() - a.ToVec3();
  127. d1.s = c.s - a.s;
  128. d1.t = c.t - a.t;
  129. texArea = ( d0[3] * d1[4] ) - ( d0[4] * d1[3] );
  130. inva = 1.0f / texArea;
  131. temp[0] = ( d0[0] * d1[4] - d0[4] * d1[0] ) * inva;
  132. temp[1] = ( d0[1] * d1[4] - d0[4] * d1[1] ) * inva;
  133. temp[2] = ( d0[2] * d1[4] - d0[4] * d1[2] ) * inva;
  134. len = temp.Normalize();
  135. info.textureAxis[0].Normal() = temp * ( 1.0f / len );
  136. info.textureAxis[0][3] = winding[0].s - ( winding[0].ToVec3() * info.textureAxis[0].Normal() );
  137. temp[0] = ( d0[3] * d1[0] - d0[0] * d1[3] ) * inva;
  138. temp[1] = ( d0[3] * d1[1] - d0[1] * d1[3] ) * inva;
  139. temp[2] = ( d0[3] * d1[2] - d0[2] * d1[3] ) * inva;
  140. len = temp.Normalize();
  141. info.textureAxis[1].Normal() = temp * ( 1.0f / len );
  142. info.textureAxis[1][3] = winding[0].t - ( winding[0].ToVec3() * info.textureAxis[1].Normal() );
  143. return true;
  144. }
  145. /*
  146. =================
  147. idRenderModelDecal::CreateProjectionInfo
  148. =================
  149. */
  150. void idRenderModelDecal::GlobalProjectionInfoToLocal( decalProjectionInfo_t &localInfo, const decalProjectionInfo_t &info, const idVec3 &origin, const idMat3 &axis ) {
  151. float modelMatrix[16];
  152. R_AxisToModelMatrix( axis, origin, modelMatrix );
  153. for ( int j = 0; j < NUM_DECAL_BOUNDING_PLANES; j++ ) {
  154. R_GlobalPlaneToLocal( modelMatrix, info.boundingPlanes[j], localInfo.boundingPlanes[j] );
  155. }
  156. R_GlobalPlaneToLocal( modelMatrix, info.fadePlanes[0], localInfo.fadePlanes[0] );
  157. R_GlobalPlaneToLocal( modelMatrix, info.fadePlanes[1], localInfo.fadePlanes[1] );
  158. R_GlobalPlaneToLocal( modelMatrix, info.textureAxis[0], localInfo.textureAxis[0] );
  159. R_GlobalPlaneToLocal( modelMatrix, info.textureAxis[1], localInfo.textureAxis[1] );
  160. R_GlobalPointToLocal( modelMatrix, info.projectionOrigin, localInfo.projectionOrigin );
  161. localInfo.projectionBounds = info.projectionBounds;
  162. localInfo.projectionBounds.TranslateSelf( -origin );
  163. localInfo.projectionBounds.RotateSelf( axis.Transpose() );
  164. localInfo.material = info.material;
  165. localInfo.parallel = info.parallel;
  166. localInfo.fadeDepth = info.fadeDepth;
  167. localInfo.startTime = info.startTime;
  168. localInfo.force = info.force;
  169. }
  170. /*
  171. =================
  172. idRenderModelDecal::AddWinding
  173. =================
  174. */
  175. void idRenderModelDecal::AddWinding( const idWinding &w, const idMaterial *decalMaterial, const idPlane fadePlanes[2], float fadeDepth, int startTime ) {
  176. int i;
  177. float invFadeDepth, fade;
  178. decalInfo_t decalInfo;
  179. if ( ( material == NULL || material == decalMaterial ) &&
  180. tri.numVerts + w.GetNumPoints() < MAX_DECAL_VERTS &&
  181. tri.numIndexes + ( w.GetNumPoints() - 2 ) * 3 < MAX_DECAL_INDEXES ) {
  182. material = decalMaterial;
  183. // add to this decal
  184. decalInfo = material->GetDecalInfo();
  185. invFadeDepth = -1.0f / fadeDepth;
  186. for ( i = 0; i < w.GetNumPoints(); i++ ) {
  187. fade = fadePlanes[0].Distance( w[i].ToVec3() ) * invFadeDepth;
  188. if ( fade < 0.0f ) {
  189. fade = fadePlanes[1].Distance( w[i].ToVec3() ) * invFadeDepth;
  190. }
  191. if ( fade < 0.0f ) {
  192. fade = 0.0f;
  193. } else if ( fade > 0.99f ) {
  194. fade = 1.0f;
  195. }
  196. fade = 1.0f - fade;
  197. vertDepthFade[tri.numVerts + i] = fade;
  198. tri.verts[tri.numVerts + i].xyz = w[i].ToVec3();
  199. tri.verts[tri.numVerts + i].st[0] = w[i].s;
  200. tri.verts[tri.numVerts + i].st[1] = w[i].t;
  201. for ( int k = 0 ; k < 4 ; k++ ) {
  202. int icolor = idMath::FtoiFast( decalInfo.start[k] * fade * 255.0f );
  203. if ( icolor < 0 ) {
  204. icolor = 0;
  205. } else if ( icolor > 255 ) {
  206. icolor = 255;
  207. }
  208. tri.verts[tri.numVerts + i].color[k] = icolor;
  209. }
  210. }
  211. for ( i = 2; i < w.GetNumPoints(); i++ ) {
  212. tri.indexes[tri.numIndexes + 0] = tri.numVerts;
  213. tri.indexes[tri.numIndexes + 1] = tri.numVerts + i - 1;
  214. tri.indexes[tri.numIndexes + 2] = tri.numVerts + i;
  215. indexStartTime[tri.numIndexes] =
  216. indexStartTime[tri.numIndexes + 1] =
  217. indexStartTime[tri.numIndexes + 2] = startTime;
  218. tri.numIndexes += 3;
  219. }
  220. tri.numVerts += w.GetNumPoints();
  221. return;
  222. }
  223. // if we are at the end of the list, create a new decal
  224. if ( !nextDecal ) {
  225. nextDecal = idRenderModelDecal::Alloc();
  226. }
  227. // let the next decal on the chain take a look
  228. nextDecal->AddWinding( w, decalMaterial, fadePlanes, fadeDepth, startTime );
  229. }
  230. /*
  231. =================
  232. idRenderModelDecal::AddDepthFadedWinding
  233. =================
  234. */
  235. void idRenderModelDecal::AddDepthFadedWinding( const idWinding &w, const idMaterial *decalMaterial, const idPlane fadePlanes[2], float fadeDepth, int startTime ) {
  236. idFixedWinding front, back;
  237. front = w;
  238. if ( front.Split( &back, fadePlanes[0], 0.1f ) == SIDE_CROSS ) {
  239. AddWinding( back, decalMaterial, fadePlanes, fadeDepth, startTime );
  240. }
  241. if ( front.Split( &back, fadePlanes[1], 0.1f ) == SIDE_CROSS ) {
  242. AddWinding( back, decalMaterial, fadePlanes, fadeDepth, startTime );
  243. }
  244. AddWinding( front, decalMaterial, fadePlanes, fadeDepth, startTime );
  245. }
  246. /*
  247. =================
  248. idRenderModelDecal::CreateDecal
  249. =================
  250. */
  251. void idRenderModelDecal::CreateDecal( const idRenderModel *model, const decalProjectionInfo_t &localInfo ) {
  252. // check all model surfaces
  253. for ( int surfNum = 0; surfNum < model->NumSurfaces(); surfNum++ ) {
  254. const modelSurface_t *surf = model->Surface( surfNum );
  255. // if no geometry or no shader
  256. if ( !surf->geometry || !surf->shader ) {
  257. continue;
  258. }
  259. // decals and overlays use the same rules
  260. if ( !localInfo.force && !surf->shader->AllowOverlays() ) {
  261. continue;
  262. }
  263. srfTriangles_t *stri = surf->geometry;
  264. // if the triangle bounds do not overlap with projection bounds
  265. if ( !localInfo.projectionBounds.IntersectsBounds( stri->bounds ) ) {
  266. continue;
  267. }
  268. // allocate memory for the cull bits
  269. byte *cullBits = (byte *)_alloca16( stri->numVerts * sizeof( cullBits[0] ) );
  270. // catagorize all points by the planes
  271. SIMDProcessor->DecalPointCull( cullBits, localInfo.boundingPlanes, stri->verts, stri->numVerts );
  272. // find triangles inside the projection volume
  273. for ( int triNum = 0, index = 0; index < stri->numIndexes; index += 3, triNum++ ) {
  274. int v1 = stri->indexes[index+0];
  275. int v2 = stri->indexes[index+1];
  276. int v3 = stri->indexes[index+2];
  277. // skip triangles completely off one side
  278. if ( cullBits[v1] & cullBits[v2] & cullBits[v3] ) {
  279. continue;
  280. }
  281. // skip back facing triangles
  282. if ( stri->facePlanes && stri->facePlanesCalculated &&
  283. stri->facePlanes[triNum].Normal() * localInfo.boundingPlanes[NUM_DECAL_BOUNDING_PLANES - 2].Normal() < -0.1f ) {
  284. continue;
  285. }
  286. // create a winding with texture coordinates for the triangle
  287. idFixedWinding fw;
  288. fw.SetNumPoints( 3 );
  289. if ( localInfo.parallel ) {
  290. for ( int j = 0; j < 3; j++ ) {
  291. fw[j] = stri->verts[stri->indexes[index+j]].xyz;
  292. fw[j].s = localInfo.textureAxis[0].Distance( fw[j].ToVec3() );
  293. fw[j].t = localInfo.textureAxis[1].Distance( fw[j].ToVec3() );
  294. }
  295. } else {
  296. for ( int j = 0; j < 3; j++ ) {
  297. idVec3 dir;
  298. float scale;
  299. fw[j] = stri->verts[stri->indexes[index+j]].xyz;
  300. dir = fw[j].ToVec3() - localInfo.projectionOrigin;
  301. localInfo.boundingPlanes[NUM_DECAL_BOUNDING_PLANES - 1].RayIntersection( fw[j].ToVec3(), dir, scale );
  302. dir = fw[j].ToVec3() + scale * dir;
  303. fw[j].s = localInfo.textureAxis[0].Distance( dir );
  304. fw[j].t = localInfo.textureAxis[1].Distance( dir );
  305. }
  306. }
  307. int orBits = cullBits[v1] | cullBits[v2] | cullBits[v3];
  308. // clip the exact surface triangle to the projection volume
  309. for ( int j = 0; j < NUM_DECAL_BOUNDING_PLANES; j++ ) {
  310. if ( orBits & ( 1 << j ) ) {
  311. if ( !fw.ClipInPlace( -localInfo.boundingPlanes[j] ) ) {
  312. break;
  313. }
  314. }
  315. }
  316. if ( fw.GetNumPoints() == 0 ) {
  317. continue;
  318. }
  319. AddDepthFadedWinding( fw, localInfo.material, localInfo.fadePlanes, localInfo.fadeDepth, localInfo.startTime );
  320. }
  321. }
  322. }
  323. /*
  324. =====================
  325. idRenderModelDecal::RemoveFadedDecals
  326. =====================
  327. */
  328. idRenderModelDecal *idRenderModelDecal::RemoveFadedDecals( idRenderModelDecal *decals, int time ) {
  329. int i, j, minTime, newNumIndexes, newNumVerts;
  330. int inUse[MAX_DECAL_VERTS];
  331. decalInfo_t decalInfo;
  332. idRenderModelDecal *nextDecal;
  333. if ( decals == NULL ) {
  334. return NULL;
  335. }
  336. // recursively free any next decals
  337. decals->nextDecal = RemoveFadedDecals( decals->nextDecal, time );
  338. // free the decals if no material set
  339. if ( decals->material == NULL ) {
  340. nextDecal = decals->nextDecal;
  341. Free( decals );
  342. return nextDecal;
  343. }
  344. decalInfo = decals->material->GetDecalInfo();
  345. minTime = time - ( decalInfo.stayTime + decalInfo.fadeTime );
  346. newNumIndexes = 0;
  347. for ( i = 0; i < decals->tri.numIndexes; i += 3 ) {
  348. if ( decals->indexStartTime[i] > minTime ) {
  349. // keep this triangle
  350. if ( newNumIndexes != i ) {
  351. for ( j = 0; j < 3; j++ ) {
  352. decals->tri.indexes[newNumIndexes+j] = decals->tri.indexes[i+j];
  353. decals->indexStartTime[newNumIndexes+j] = decals->indexStartTime[i+j];
  354. }
  355. }
  356. newNumIndexes += 3;
  357. }
  358. }
  359. // free the decals if all trianges faded away
  360. if ( newNumIndexes == 0 ) {
  361. nextDecal = decals->nextDecal;
  362. Free( decals );
  363. return nextDecal;
  364. }
  365. decals->tri.numIndexes = newNumIndexes;
  366. memset( inUse, 0, sizeof( inUse ) );
  367. for ( i = 0; i < decals->tri.numIndexes; i++ ) {
  368. inUse[decals->tri.indexes[i]] = 1;
  369. }
  370. newNumVerts = 0;
  371. for ( i = 0; i < decals->tri.numVerts; i++ ) {
  372. if ( !inUse[i] ) {
  373. continue;
  374. }
  375. decals->tri.verts[newNumVerts] = decals->tri.verts[i];
  376. decals->vertDepthFade[newNumVerts] = decals->vertDepthFade[i];
  377. inUse[i] = newNumVerts;
  378. newNumVerts++;
  379. }
  380. decals->tri.numVerts = newNumVerts;
  381. for ( i = 0; i < decals->tri.numIndexes; i++ ) {
  382. decals->tri.indexes[i] = inUse[decals->tri.indexes[i]];
  383. }
  384. return decals;
  385. }
  386. /*
  387. =====================
  388. idRenderModelDecal::AddDecalDrawSurf
  389. =====================
  390. */
  391. void idRenderModelDecal::AddDecalDrawSurf( viewEntity_t *space ) {
  392. int i, j, maxTime;
  393. float f;
  394. decalInfo_t decalInfo;
  395. if ( tri.numIndexes == 0 ) {
  396. return;
  397. }
  398. // fade down all the verts with time
  399. decalInfo = material->GetDecalInfo();
  400. maxTime = decalInfo.stayTime + decalInfo.fadeTime;
  401. // set vertex colors and remove faded triangles
  402. for ( i = 0 ; i < tri.numIndexes ; i += 3 ) {
  403. int deltaTime = tr.viewDef->renderView.time - indexStartTime[i];
  404. if ( deltaTime > maxTime ) {
  405. continue;
  406. }
  407. if ( deltaTime <= decalInfo.stayTime ) {
  408. continue;
  409. }
  410. deltaTime -= decalInfo.stayTime;
  411. f = (float)deltaTime / decalInfo.fadeTime;
  412. for ( j = 0; j < 3; j++ ) {
  413. int ind = tri.indexes[i+j];
  414. for ( int k = 0; k < 4; k++ ) {
  415. float fcolor = decalInfo.start[k] + ( decalInfo.end[k] - decalInfo.start[k] ) * f;
  416. int icolor = idMath::FtoiFast( fcolor * vertDepthFade[ind] * 255.0f );
  417. if ( icolor < 0 ) {
  418. icolor = 0;
  419. } else if ( icolor > 255 ) {
  420. icolor = 255;
  421. }
  422. tri.verts[ind].color[k] = icolor;
  423. }
  424. }
  425. }
  426. // copy the tri and indexes to temp heap memory,
  427. // because if we are running multi-threaded, we wouldn't
  428. // be able to reorganize the index list
  429. srfTriangles_t *newTri = (srfTriangles_t *)R_FrameAlloc( sizeof( *newTri ) );
  430. *newTri = tri;
  431. // copy the current vertexes to temp vertex cache
  432. newTri->ambientCache = vertexCache.AllocFrameTemp( tri.verts, tri.numVerts * sizeof( idDrawVert ) );
  433. // create the drawsurf
  434. R_AddDrawSurf( newTri, space, &space->entityDef->parms, material, space->scissorRect );
  435. }
  436. /*
  437. ====================
  438. idRenderModelDecal::ReadFromDemoFile
  439. ====================
  440. */
  441. void idRenderModelDecal::ReadFromDemoFile( idDemoFile *f ) {
  442. // FIXME: implement
  443. }
  444. /*
  445. ====================
  446. idRenderModelDecal::WriteToDemoFile
  447. ====================
  448. */
  449. void idRenderModelDecal::WriteToDemoFile( idDemoFile *f ) const {
  450. // FIXME: implement
  451. }