doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ModelOverlay.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21 
22 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.
23 
24 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.
25 
26 ===========================================================================
27 */
28 
29 #include "../idlib/precompiled.h"
30 #pragma hdrstop
31 
32 #include "Model_local.h"
33 #include "tr_local.h"
34 
35 
36 /*
37 ====================
38 idRenderModelOverlay::idRenderModelOverlay
39 ====================
40 */
42 }
43 
44 /*
45 ====================
46 idRenderModelOverlay::~idRenderModelOverlay
47 ====================
48 */
50  int i, k;
51 
52  for ( k = 0; k < materials.Num(); k++ ) {
53  for ( i = 0; i < materials[k]->surfaces.Num(); i++ ) {
54  FreeSurface( materials[k]->surfaces[i] );
55  }
56  materials[k]->surfaces.Clear();
57  delete materials[k];
58  }
59  materials.Clear();
60 }
61 
62 /*
63 ====================
64 idRenderModelOverlay::Alloc
65 ====================
66 */
68  return new idRenderModelOverlay;
69 }
70 
71 /*
72 ====================
73 idRenderModelOverlay::Free
74 ====================
75 */
77  delete overlay;
78 }
79 
80 /*
81 ====================
82 idRenderModelOverlay::FreeSurface
83 ====================
84 */
86  if ( surface->verts ) {
87  Mem_Free( surface->verts );
88  }
89  if ( surface->indexes ) {
90  Mem_Free( surface->indexes );
91  }
92  Mem_Free( surface );
93 }
94 
95 /*
96 =====================
97 idRenderModelOverlay::CreateOverlay
98 
99 This projects on both front and back sides to avoid seams
100 The material should be clamped, because entire triangles are added, some of which
101 may extend well past the 0.0 to 1.0 texture range
102 =====================
103 */
104 void idRenderModelOverlay::CreateOverlay( const idRenderModel *model, const idPlane localTextureAxis[2], const idMaterial *mtr ) {
105  int i, maxVerts, maxIndexes, surfNum;
106  idRenderModelOverlay *overlay = NULL;
107 
108  // count up the maximum possible vertices and indexes per surface
109  maxVerts = 0;
110  maxIndexes = 0;
111  for ( surfNum = 0; surfNum < model->NumSurfaces(); surfNum++ ) {
112  const modelSurface_t *surf = model->Surface( surfNum );
113  if ( surf->geometry->numVerts > maxVerts ) {
114  maxVerts = surf->geometry->numVerts;
115  }
116  if ( surf->geometry->numIndexes > maxIndexes ) {
117  maxIndexes = surf->geometry->numIndexes;
118  }
119  }
120 
121  // make temporary buffers for the building process
122  overlayVertex_t *overlayVerts = (overlayVertex_t *)_alloca( maxVerts * sizeof( *overlayVerts ) );
123  glIndex_t *overlayIndexes = (glIndex_t *)_alloca16( maxIndexes * sizeof( *overlayIndexes ) );
124 
125  // pull out the triangles we need from the base surfaces
126  for ( surfNum = 0; surfNum < model->NumBaseSurfaces(); surfNum++ ) {
127  const modelSurface_t *surf = model->Surface( surfNum );
128  float d;
129 
130  if ( !surf->geometry || !surf->shader ) {
131  continue;
132  }
133 
134  // some surfaces can explicitly disallow overlays
135  if ( !surf->shader->AllowOverlays() ) {
136  continue;
137  }
138 
139  const srfTriangles_t *stri = surf->geometry;
140 
141  // try to cull the whole surface along the first texture axis
142  d = stri->bounds.PlaneDistance( localTextureAxis[0] );
143  if ( d < 0.0f || d > 1.0f ) {
144  continue;
145  }
146 
147  // try to cull the whole surface along the second texture axis
148  d = stri->bounds.PlaneDistance( localTextureAxis[1] );
149  if ( d < 0.0f || d > 1.0f ) {
150  continue;
151  }
152 
153  byte *cullBits = (byte *)_alloca16( stri->numVerts * sizeof( cullBits[0] ) );
154  idVec2 *texCoords = (idVec2 *)_alloca16( stri->numVerts * sizeof( texCoords[0] ) );
155 
156  SIMDProcessor->OverlayPointCull( cullBits, texCoords, localTextureAxis, stri->verts, stri->numVerts );
157 
158  glIndex_t *vertexRemap = (glIndex_t *)_alloca16( sizeof( vertexRemap[0] ) * stri->numVerts );
159  SIMDProcessor->Memset( vertexRemap, -1, sizeof( vertexRemap[0] ) * stri->numVerts );
160 
161  // find triangles that need the overlay
162  int numVerts = 0;
163  int numIndexes = 0;
164  int triNum = 0;
165  for ( int index = 0; index < stri->numIndexes; index += 3, triNum++ ) {
166  int v1 = stri->indexes[index+0];
167  int v2 = stri->indexes[index+1];
168  int v3 = stri->indexes[index+2];
169 
170  // skip triangles completely off one side
171  if ( cullBits[v1] & cullBits[v2] & cullBits[v3] ) {
172  continue;
173  }
174 
175  // we could do more precise triangle culling, like the light interaction does, if desired
176 
177  // keep this triangle
178  for ( int vnum = 0; vnum < 3; vnum++ ) {
179  int ind = stri->indexes[index+vnum];
180  if ( vertexRemap[ind] == (glIndex_t)-1 ) {
181  vertexRemap[ind] = numVerts;
182 
183  overlayVerts[numVerts].vertexNum = ind;
184  overlayVerts[numVerts].st[0] = texCoords[ind][0];
185  overlayVerts[numVerts].st[1] = texCoords[ind][1];
186 
187  numVerts++;
188  }
189  overlayIndexes[numIndexes++] = vertexRemap[ind];
190  }
191  }
192 
193  if ( !numIndexes ) {
194  continue;
195  }
196 
198  s->surfaceNum = surfNum;
199  s->surfaceId = surf->id;
200  s->verts = (overlayVertex_t *)Mem_Alloc( numVerts * sizeof( s->verts[0] ) );
201  memcpy( s->verts, overlayVerts, numVerts * sizeof( s->verts[0] ) );
202  s->numVerts = numVerts;
203  s->indexes = (glIndex_t *)Mem_Alloc( numIndexes * sizeof( s->indexes[0] ) );
204  memcpy( s->indexes, overlayIndexes, numIndexes * sizeof( s->indexes[0] ) );
205  s->numIndexes = numIndexes;
206 
207  for ( i = 0; i < materials.Num(); i++ ) {
208  if ( materials[i]->material == mtr ) {
209  break;
210  }
211  }
212  if ( i < materials.Num() ) {
213  materials[i]->surfaces.Append( s );
214  } else {
216  mat->material = mtr;
217  mat->surfaces.Append( s );
218  materials.Append( mat );
219  }
220  }
221 
222  // remove the oldest overlay surfaces if there are too many per material
223  for ( i = 0; i < materials.Num(); i++ ) {
224  while( materials[i]->surfaces.Num() > MAX_OVERLAY_SURFACES ) {
225  FreeSurface( materials[i]->surfaces[0] );
226  materials[i]->surfaces.RemoveIndex( 0 );
227  }
228  }
229 }
230 
231 /*
232 ====================
233 idRenderModelOverlay::AddOverlaySurfacesToModel
234 ====================
235 */
237  int i, j, k, numVerts, numIndexes, surfaceNum;
238  const modelSurface_t *baseSurf;
239  idRenderModelStatic *staticModel;
240  overlaySurface_t *surf;
241  srfTriangles_t *newTri;
242  modelSurface_t *newSurf;
243 
244  if ( baseModel == NULL || baseModel->IsDefaultModel() ) {
245  return;
246  }
247 
248  // md5 models won't have any surfaces when r_showSkel is set
249  if ( !baseModel->NumSurfaces() ) {
250  return;
251  }
252 
253  if ( baseModel->IsDynamicModel() != DM_STATIC ) {
254  common->Error( "idRenderModelOverlay::AddOverlaySurfacesToModel: baseModel is not a static model" );
255  }
256 
257  assert( dynamic_cast<idRenderModelStatic *>(baseModel) != NULL );
258  staticModel = static_cast<idRenderModelStatic *>(baseModel);
259 
260  staticModel->overlaysAdded = 0;
261 
262  if ( !materials.Num() ) {
263  staticModel->DeleteSurfacesWithNegativeId();
264  return;
265  }
266 
267  for ( k = 0; k < materials.Num(); k++ ) {
268 
269  numVerts = numIndexes = 0;
270  for ( i = 0; i < materials[k]->surfaces.Num(); i++ ) {
271  numVerts += materials[k]->surfaces[i]->numVerts;
272  numIndexes += materials[k]->surfaces[i]->numIndexes;
273  }
274 
275  if ( staticModel->FindSurfaceWithId( -1 - k, surfaceNum ) ) {
276  newSurf = &staticModel->surfaces[surfaceNum];
277  } else {
278  newSurf = &staticModel->surfaces.Alloc();
279  newSurf->geometry = NULL;
280  newSurf->shader = materials[k]->material;
281  newSurf->id = -1 - k;
282  }
283 
284  if ( newSurf->geometry == NULL || newSurf->geometry->numVerts < numVerts || newSurf->geometry->numIndexes < numIndexes ) {
285  R_FreeStaticTriSurf( newSurf->geometry );
286  newSurf->geometry = R_AllocStaticTriSurf();
287  R_AllocStaticTriSurfVerts( newSurf->geometry, numVerts );
288  R_AllocStaticTriSurfIndexes( newSurf->geometry, numIndexes );
289  SIMDProcessor->Memset( newSurf->geometry->verts, 0, numVerts * sizeof( newTri->verts[0] ) );
290  } else {
292  }
293 
294  newTri = newSurf->geometry;
295  numVerts = numIndexes = 0;
296 
297  for ( i = 0; i < materials[k]->surfaces.Num(); i++ ) {
298  surf = materials[k]->surfaces[i];
299 
300  // get the model surface for this overlay surface
301  if ( surf->surfaceNum < staticModel->NumSurfaces() ) {
302  baseSurf = staticModel->Surface( surf->surfaceNum );
303  } else {
304  baseSurf = NULL;
305  }
306 
307  // if the surface ids no longer match
308  if ( !baseSurf || baseSurf->id != surf->surfaceId ) {
309  // find the surface with the correct id
310  if ( staticModel->FindSurfaceWithId( surf->surfaceId, surf->surfaceNum ) ) {
311  baseSurf = staticModel->Surface( surf->surfaceNum );
312  } else {
313  // the surface with this id no longer exists
314  FreeSurface( surf );
315  materials[k]->surfaces.RemoveIndex( i );
316  i--;
317  continue;
318  }
319  }
320 
321  // copy indexes;
322  for ( j = 0; j < surf->numIndexes; j++ ) {
323  newTri->indexes[numIndexes + j] = numVerts + surf->indexes[j];
324  }
325  numIndexes += surf->numIndexes;
326 
327  // copy vertices
328  for ( j = 0; j < surf->numVerts; j++ ) {
329  overlayVertex_t *overlayVert = &surf->verts[j];
330 
331  newTri->verts[numVerts].st[0] = overlayVert->st[0];
332  newTri->verts[numVerts].st[1] = overlayVert->st[1];
333 
334  if ( overlayVert->vertexNum >= baseSurf->geometry->numVerts ) {
335  // 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.
336  common->Warning( "idRenderModelOverlay::AddOverlaySurfacesToModel: overlay vertex out of range. Model has probably changed since generating the overlay." );
337  FreeSurface( surf );
338  materials[k]->surfaces.RemoveIndex( i );
339  staticModel->DeleteSurfaceWithId( newSurf->id );
340  return;
341  }
342  newTri->verts[numVerts].xyz = baseSurf->geometry->verts[overlayVert->vertexNum].xyz;
343  numVerts++;
344  }
345  }
346 
347  newTri->numVerts = numVerts;
348  newTri->numIndexes = numIndexes;
349  R_BoundTriSurf( newTri );
350 
351  staticModel->overlaysAdded++; // so we don't create an overlay on an overlay surface
352  }
353 }
354 
355 /*
356 ====================
357 idRenderModelOverlay::RemoveOverlaySurfacesFromModel
358 ====================
359 */
361  idRenderModelStatic *staticModel;
362 
363  assert( dynamic_cast<idRenderModelStatic *>(baseModel) != NULL );
364  staticModel = static_cast<idRenderModelStatic *>(baseModel);
365 
366  staticModel->DeleteSurfacesWithNegativeId();
367  staticModel->overlaysAdded = 0;
368 }
369 
370 /*
371 ====================
372 idRenderModelOverlay::ReadFromDemoFile
373 ====================
374 */
376  // FIXME: implement
377 }
378 
379 /*
380 ====================
381 idRenderModelOverlay::WriteToDemoFile
382 ====================
383 */
385  // FIXME: implement
386 }
static void RemoveOverlaySurfacesFromModel(idRenderModel *baseModel)
bool FindSurfaceWithId(int id, int &surfaceNum)
Definition: Model.cpp:2318
idList< modelSurface_t > surfaces
Definition: Model_local.h:106
assert(prefInfo.fullscreenBtn)
glIndex_t * indexes
Definition: ModelOverlay.h:51
int numVerts
Definition: Model.h:98
struct overlayMaterial_s overlayMaterial_t
idVec3 xyz
Definition: DrawVert.h:42
virtual const modelSurface_t * Surface(int surfaceNum) const
Definition: Model.cpp:403
const idMaterial * shader
Definition: Model.h:146
virtual void VPCALL OverlayPointCull(byte *cullBits, idVec2 *texCoords, const idPlane *planes, const idDrawVert *verts, const int numVerts)=0
srfTriangles_t * R_AllocStaticTriSurf(void)
Definition: tr_trisurf.cpp:523
GLdouble s
Definition: glext.h:2935
virtual void VPCALL Memset(void *dst, const int val, const int count)=0
bool DeleteSurfaceWithId(int id)
Definition: Model.cpp:2283
int i
Definition: process.py:33
void FreeSurface(overlaySurface_t *surface)
static void Free(idRenderModelOverlay *overlay)
virtual dynamicModel_t IsDynamicModel() const =0
static idRenderModelOverlay * Alloc(void)
bool AllowOverlays(void) const
Definition: Material.h:422
const idMaterial * material
Definition: ModelOverlay.h:57
idVec2 st
Definition: DrawVert.h:43
GLfloat GLfloat GLfloat v2
Definition: glext.h:3608
Definition: Vector.h:52
GLuint index
Definition: glext.h:3476
void CreateOverlay(const idRenderModel *model, const idPlane localTextureAxis[2], const idMaterial *material)
void DeleteSurfacesWithNegativeId(void)
Definition: Model.cpp:2301
idBounds bounds
Definition: Model.h:87
idCommon * common
Definition: Common.cpp:206
float PlaneDistance(const idPlane &plane) const
Definition: Bounds.cpp:83
#define NULL
Definition: Lib.h:88
srfTriangles_t * geometry
Definition: Model.h:147
int glIndex_t
Definition: Model.h:52
virtual const modelSurface_t * Surface(int surfaceNum) const =0
Definition: Plane.h:71
void R_FreeStaticTriSurf(srfTriangles_t *tri)
Definition: tr_trisurf.cpp:489
void Mem_Free(void *ptr)
Definition: Heap.cpp:1087
void R_BoundTriSurf(srfTriangles_t *tri)
Definition: tr_trisurf.cpp:704
GLfloat GLfloat v1
Definition: glext.h:3607
overlayVertex_t * verts
Definition: ModelOverlay.h:53
GLfloat GLfloat GLfloat GLfloat v3
Definition: glext.h:3609
virtual bool IsDefaultModel() const =0
tuple f
Definition: idal.py:89
unsigned char byte
Definition: Lib.h:75
virtual int NumBaseSurfaces() const =0
const int MAX_OVERLAY_SURFACES
Definition: ModelOverlay.h:40
glIndex_t * indexes
Definition: Model.h:102
idList< overlaySurface_t * > surfaces
Definition: ModelOverlay.h:58
virtual int NumSurfaces() const
Definition: Model.cpp:385
void AddOverlaySurfacesToModel(idRenderModel *baseModel)
idList< overlayMaterial_t * > materials
Definition: ModelOverlay.h:88
void R_AllocStaticTriSurfIndexes(srfTriangles_t *tri, int numIndexes)
Definition: tr_trisurf.cpp:565
void * Mem_Alloc(const int size)
Definition: Heap.cpp:1067
GLint j
Definition: qgl.h:264
int numIndexes
Definition: Model.h:101
virtual void Error(const char *fmt,...) id_attribute((format(printf
void R_AllocStaticTriSurfVerts(srfTriangles_t *tri, int numVerts)
Definition: tr_trisurf.cpp:555
virtual void virtual void Warning(const char *fmt,...) id_attribute((format(printf
void WriteToDemoFile(class idDemoFile *f) const
void R_FreeStaticTriSurfVertexCaches(srfTriangles_t *tri)
Definition: tr_trisurf.cpp:343
idDrawVert * verts
Definition: Model.h:99
void ReadFromDemoFile(class idDemoFile *f)
idSIMDProcessor * SIMDProcessor
Definition: Simd.cpp:43
virtual int NumSurfaces() const =0