ModelOverlay.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  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 "Model_local.h"
  23. #include "tr_local.h"
  24. /*
  25. ====================
  26. idRenderModelOverlay::idRenderModelOverlay
  27. ====================
  28. */
  29. idRenderModelOverlay::idRenderModelOverlay() {
  30. }
  31. /*
  32. ====================
  33. idRenderModelOverlay::~idRenderModelOverlay
  34. ====================
  35. */
  36. idRenderModelOverlay::~idRenderModelOverlay() {
  37. int i, k;
  38. for ( k = 0; k < materials.Num(); k++ ) {
  39. for ( i = 0; i < materials[k]->surfaces.Num(); i++ ) {
  40. FreeSurface( materials[k]->surfaces[i] );
  41. }
  42. materials[k]->surfaces.Clear();
  43. delete materials[k];
  44. }
  45. materials.Clear();
  46. }
  47. /*
  48. ====================
  49. idRenderModelOverlay::Alloc
  50. ====================
  51. */
  52. idRenderModelOverlay *idRenderModelOverlay::Alloc( void ) {
  53. return new idRenderModelOverlay;
  54. }
  55. /*
  56. ====================
  57. idRenderModelOverlay::Free
  58. ====================
  59. */
  60. void idRenderModelOverlay::Free( idRenderModelOverlay *overlay ) {
  61. delete overlay;
  62. }
  63. /*
  64. ====================
  65. idRenderModelOverlay::FreeSurface
  66. ====================
  67. */
  68. void idRenderModelOverlay::FreeSurface( overlaySurface_t *surface ) {
  69. if ( surface->verts ) {
  70. Mem_Free( surface->verts );
  71. }
  72. if ( surface->indexes ) {
  73. Mem_Free( surface->indexes );
  74. }
  75. Mem_Free( surface );
  76. }
  77. /*
  78. =====================
  79. idRenderModelOverlay::CreateOverlay
  80. This projects on both front and back sides to avoid seams
  81. The material should be clamped, because entire triangles are added, some of which
  82. may extend well past the 0.0 to 1.0 texture range
  83. =====================
  84. */
  85. void idRenderModelOverlay::CreateOverlay( const idRenderModel *model, const idPlane localTextureAxis[2], const idMaterial *mtr ) {
  86. int i, maxVerts, maxIndexes, surfNum;
  87. idRenderModelOverlay *overlay = NULL;
  88. // count up the maximum possible vertices and indexes per surface
  89. maxVerts = 0;
  90. maxIndexes = 0;
  91. for ( surfNum = 0; surfNum < model->NumSurfaces(); surfNum++ ) {
  92. const modelSurface_t *surf = model->Surface( surfNum );
  93. if ( surf->geometry->numVerts > maxVerts ) {
  94. maxVerts = surf->geometry->numVerts;
  95. }
  96. if ( surf->geometry->numIndexes > maxIndexes ) {
  97. maxIndexes = surf->geometry->numIndexes;
  98. }
  99. }
  100. // make temporary buffers for the building process
  101. overlayVertex_t *overlayVerts = (overlayVertex_t *)_alloca( maxVerts * sizeof( *overlayVerts ) );
  102. glIndex_t *overlayIndexes = (glIndex_t *)_alloca16( maxIndexes * sizeof( *overlayIndexes ) );
  103. // pull out the triangles we need from the base surfaces
  104. for ( surfNum = 0; surfNum < model->NumBaseSurfaces(); surfNum++ ) {
  105. const modelSurface_t *surf = model->Surface( surfNum );
  106. float d;
  107. if ( !surf->geometry || !surf->shader ) {
  108. continue;
  109. }
  110. // some surfaces can explicitly disallow overlays
  111. if ( !surf->shader->AllowOverlays() ) {
  112. continue;
  113. }
  114. const srfTriangles_t *stri = surf->geometry;
  115. // try to cull the whole surface along the first texture axis
  116. d = stri->bounds.PlaneDistance( localTextureAxis[0] );
  117. if ( d < 0.0f || d > 1.0f ) {
  118. continue;
  119. }
  120. // try to cull the whole surface along the second texture axis
  121. d = stri->bounds.PlaneDistance( localTextureAxis[1] );
  122. if ( d < 0.0f || d > 1.0f ) {
  123. continue;
  124. }
  125. byte *cullBits = (byte *)_alloca16( stri->numVerts * sizeof( cullBits[0] ) );
  126. idVec2 *texCoords = (idVec2 *)_alloca16( stri->numVerts * sizeof( texCoords[0] ) );
  127. SIMDProcessor->OverlayPointCull( cullBits, texCoords, localTextureAxis, stri->verts, stri->numVerts );
  128. glIndex_t *vertexRemap = (glIndex_t *)_alloca16( sizeof( vertexRemap[0] ) * stri->numVerts );
  129. SIMDProcessor->Memset( vertexRemap, -1, sizeof( vertexRemap[0] ) * stri->numVerts );
  130. // find triangles that need the overlay
  131. int numVerts = 0;
  132. int numIndexes = 0;
  133. int triNum = 0;
  134. for ( int index = 0; index < stri->numIndexes; index += 3, triNum++ ) {
  135. int v1 = stri->indexes[index+0];
  136. int v2 = stri->indexes[index+1];
  137. int v3 = stri->indexes[index+2];
  138. // skip triangles completely off one side
  139. if ( cullBits[v1] & cullBits[v2] & cullBits[v3] ) {
  140. continue;
  141. }
  142. // we could do more precise triangle culling, like the light interaction does, if desired
  143. // keep this triangle
  144. for ( int vnum = 0; vnum < 3; vnum++ ) {
  145. int ind = stri->indexes[index+vnum];
  146. if ( vertexRemap[ind] == (glIndex_t)-1 ) {
  147. vertexRemap[ind] = numVerts;
  148. overlayVerts[numVerts].vertexNum = ind;
  149. overlayVerts[numVerts].st[0] = texCoords[ind][0];
  150. overlayVerts[numVerts].st[1] = texCoords[ind][1];
  151. numVerts++;
  152. }
  153. overlayIndexes[numIndexes++] = vertexRemap[ind];
  154. }
  155. }
  156. if ( !numIndexes ) {
  157. continue;
  158. }
  159. overlaySurface_t *s = (overlaySurface_t *) Mem_Alloc( sizeof( overlaySurface_t ) );
  160. s->surfaceNum = surfNum;
  161. s->surfaceId = surf->id;
  162. s->verts = (overlayVertex_t *)Mem_Alloc( numVerts * sizeof( s->verts[0] ) );
  163. memcpy( s->verts, overlayVerts, numVerts * sizeof( s->verts[0] ) );
  164. s->numVerts = numVerts;
  165. s->indexes = (glIndex_t *)Mem_Alloc( numIndexes * sizeof( s->indexes[0] ) );
  166. memcpy( s->indexes, overlayIndexes, numIndexes * sizeof( s->indexes[0] ) );
  167. s->numIndexes = numIndexes;
  168. for ( i = 0; i < materials.Num(); i++ ) {
  169. if ( materials[i]->material == mtr ) {
  170. break;
  171. }
  172. }
  173. if ( i < materials.Num() ) {
  174. materials[i]->surfaces.Append( s );
  175. } else {
  176. overlayMaterial_t *mat = new overlayMaterial_t;
  177. mat->material = mtr;
  178. mat->surfaces.Append( s );
  179. materials.Append( mat );
  180. }
  181. }
  182. // remove the oldest overlay surfaces if there are too many per material
  183. for ( i = 0; i < materials.Num(); i++ ) {
  184. while( materials[i]->surfaces.Num() > MAX_OVERLAY_SURFACES ) {
  185. FreeSurface( materials[i]->surfaces[0] );
  186. materials[i]->surfaces.RemoveIndex( 0 );
  187. }
  188. }
  189. }
  190. /*
  191. ====================
  192. idRenderModelOverlay::AddOverlaySurfacesToModel
  193. ====================
  194. */
  195. void idRenderModelOverlay::AddOverlaySurfacesToModel( idRenderModel *baseModel ) {
  196. int i, j, k, numVerts, numIndexes, surfaceNum;
  197. const modelSurface_t *baseSurf;
  198. idRenderModelStatic *staticModel;
  199. overlaySurface_t *surf;
  200. srfTriangles_t *newTri;
  201. modelSurface_t *newSurf;
  202. if ( baseModel == NULL || baseModel->IsDefaultModel() ) {
  203. return;
  204. }
  205. // md5 models won't have any surfaces when r_showSkel is set
  206. if ( !baseModel->NumSurfaces() ) {
  207. return;
  208. }
  209. if ( baseModel->IsDynamicModel() != DM_STATIC ) {
  210. common->Error( "idRenderModelOverlay::AddOverlaySurfacesToModel: baseModel is not a static model" );
  211. }
  212. assert( dynamic_cast<idRenderModelStatic *>(baseModel) != NULL );
  213. staticModel = static_cast<idRenderModelStatic *>(baseModel);
  214. staticModel->overlaysAdded = 0;
  215. if ( !materials.Num() ) {
  216. staticModel->DeleteSurfacesWithNegativeId();
  217. return;
  218. }
  219. for ( k = 0; k < materials.Num(); k++ ) {
  220. numVerts = numIndexes = 0;
  221. for ( i = 0; i < materials[k]->surfaces.Num(); i++ ) {
  222. numVerts += materials[k]->surfaces[i]->numVerts;
  223. numIndexes += materials[k]->surfaces[i]->numIndexes;
  224. }
  225. if ( staticModel->FindSurfaceWithId( -1 - k, surfaceNum ) ) {
  226. newSurf = &staticModel->surfaces[surfaceNum];
  227. } else {
  228. newSurf = &staticModel->surfaces.Alloc();
  229. newSurf->geometry = NULL;
  230. newSurf->shader = materials[k]->material;
  231. newSurf->id = -1 - k;
  232. }
  233. if ( newSurf->geometry == NULL || newSurf->geometry->numVerts < numVerts || newSurf->geometry->numIndexes < numIndexes ) {
  234. R_FreeStaticTriSurf( newSurf->geometry );
  235. newSurf->geometry = R_AllocStaticTriSurf();
  236. R_AllocStaticTriSurfVerts( newSurf->geometry, numVerts );
  237. R_AllocStaticTriSurfIndexes( newSurf->geometry, numIndexes );
  238. SIMDProcessor->Memset( newSurf->geometry->verts, 0, numVerts * sizeof( newTri->verts[0] ) );
  239. } else {
  240. R_FreeStaticTriSurfVertexCaches( newSurf->geometry );
  241. }
  242. newTri = newSurf->geometry;
  243. numVerts = numIndexes = 0;
  244. for ( i = 0; i < materials[k]->surfaces.Num(); i++ ) {
  245. surf = materials[k]->surfaces[i];
  246. // get the model surface for this overlay surface
  247. if ( surf->surfaceNum < staticModel->NumSurfaces() ) {
  248. baseSurf = staticModel->Surface( surf->surfaceNum );
  249. } else {
  250. baseSurf = NULL;
  251. }
  252. // if the surface ids no longer match
  253. if ( !baseSurf || baseSurf->id != surf->surfaceId ) {
  254. // find the surface with the correct id
  255. if ( staticModel->FindSurfaceWithId( surf->surfaceId, surf->surfaceNum ) ) {
  256. baseSurf = staticModel->Surface( surf->surfaceNum );
  257. } else {
  258. // the surface with this id no longer exists
  259. FreeSurface( surf );
  260. materials[k]->surfaces.RemoveIndex( i );
  261. i--;
  262. continue;
  263. }
  264. }
  265. // copy indexes;
  266. for ( j = 0; j < surf->numIndexes; j++ ) {
  267. newTri->indexes[numIndexes + j] = numVerts + surf->indexes[j];
  268. }
  269. numIndexes += surf->numIndexes;
  270. // copy vertices
  271. for ( j = 0; j < surf->numVerts; j++ ) {
  272. overlayVertex_t *overlayVert = &surf->verts[j];
  273. newTri->verts[numVerts].st[0] = overlayVert->st[0];
  274. newTri->verts[numVerts].st[1] = overlayVert->st[1];
  275. if ( overlayVert->vertexNum >= baseSurf->geometry->numVerts ) {
  276. // This can happen when playing a demofile and a model has been changed since it was recorded, so just issue a warning and go on.
  277. common->Warning( "idRenderModelOverlay::AddOverlaySurfacesToModel: overlay vertex out of range. Model has probably changed since generating the overlay." );
  278. FreeSurface( surf );
  279. materials[k]->surfaces.RemoveIndex( i );
  280. staticModel->DeleteSurfaceWithId( newSurf->id );
  281. return;
  282. }
  283. newTri->verts[numVerts].xyz = baseSurf->geometry->verts[overlayVert->vertexNum].xyz;
  284. numVerts++;
  285. }
  286. }
  287. newTri->numVerts = numVerts;
  288. newTri->numIndexes = numIndexes;
  289. R_BoundTriSurf( newTri );
  290. staticModel->overlaysAdded++; // so we don't create an overlay on an overlay surface
  291. }
  292. }
  293. /*
  294. ====================
  295. idRenderModelOverlay::RemoveOverlaySurfacesFromModel
  296. ====================
  297. */
  298. void idRenderModelOverlay::RemoveOverlaySurfacesFromModel( idRenderModel *baseModel ) {
  299. idRenderModelStatic *staticModel;
  300. assert( dynamic_cast<idRenderModelStatic *>(baseModel) != NULL );
  301. staticModel = static_cast<idRenderModelStatic *>(baseModel);
  302. staticModel->DeleteSurfacesWithNegativeId();
  303. staticModel->overlaysAdded = 0;
  304. }
  305. /*
  306. ====================
  307. idRenderModelOverlay::ReadFromDemoFile
  308. ====================
  309. */
  310. void idRenderModelOverlay::ReadFromDemoFile( idDemoFile *f ) {
  311. // FIXME: implement
  312. }
  313. /*
  314. ====================
  315. idRenderModelOverlay::WriteToDemoFile
  316. ====================
  317. */
  318. void idRenderModelOverlay::WriteToDemoFile( idDemoFile *f ) const {
  319. // FIXME: implement
  320. }