2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
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.
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.
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/>.
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.
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.
26 ===========================================================================
29 #include "../idlib/precompiled.h"
32 #include "Model_local.h"
38 idRenderModelOverlay::idRenderModelOverlay
41 idRenderModelOverlay::idRenderModelOverlay() {
46 idRenderModelOverlay::~idRenderModelOverlay
49 idRenderModelOverlay::~idRenderModelOverlay() {
52 for ( k = 0; k < materials.Num(); k++ ) {
53 for ( i = 0; i < materials[k]->surfaces.Num(); i++ ) {
54 FreeSurface( materials[k]->surfaces[i] );
56 materials[k]->surfaces.Clear();
64 idRenderModelOverlay::Alloc
67 idRenderModelOverlay *idRenderModelOverlay::Alloc( void ) {
68 return new idRenderModelOverlay;
73 idRenderModelOverlay::Free
76 void idRenderModelOverlay::Free( idRenderModelOverlay *overlay ) {
82 idRenderModelOverlay::FreeSurface
85 void idRenderModelOverlay::FreeSurface( overlaySurface_t *surface ) {
86 if ( surface->verts ) {
87 Mem_Free( surface->verts );
89 if ( surface->indexes ) {
90 Mem_Free( surface->indexes );
97 idRenderModelOverlay::CreateOverlay
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 =====================
104 void idRenderModelOverlay::CreateOverlay( const idRenderModel *model, const idPlane localTextureAxis[2], const idMaterial *mtr ) {
105 int i, maxVerts, maxIndexes, surfNum;
106 idRenderModelOverlay *overlay = NULL;
108 // count up the maximum possible vertices and indexes per surface
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;
116 if ( surf->geometry->numIndexes > maxIndexes ) {
117 maxIndexes = surf->geometry->numIndexes;
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 ) );
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 );
130 if ( !surf->geometry || !surf->shader ) {
134 // some surfaces can explicitly disallow overlays
135 if ( !surf->shader->AllowOverlays() ) {
139 const srfTriangles_t *stri = surf->geometry;
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 ) {
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 ) {
153 byte *cullBits = (byte *)_alloca16( stri->numVerts * sizeof( cullBits[0] ) );
154 idVec2 *texCoords = (idVec2 *)_alloca16( stri->numVerts * sizeof( texCoords[0] ) );
156 SIMDProcessor->OverlayPointCull( cullBits, texCoords, localTextureAxis, stri->verts, stri->numVerts );
158 glIndex_t *vertexRemap = (glIndex_t *)_alloca16( sizeof( vertexRemap[0] ) * stri->numVerts );
159 SIMDProcessor->Memset( vertexRemap, -1, sizeof( vertexRemap[0] ) * stri->numVerts );
161 // find triangles that need the overlay
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];
170 // skip triangles completely off one side
171 if ( cullBits[v1] & cullBits[v2] & cullBits[v3] ) {
175 // we could do more precise triangle culling, like the light interaction does, if desired
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;
183 overlayVerts[numVerts].vertexNum = ind;
184 overlayVerts[numVerts].st[0] = texCoords[ind][0];
185 overlayVerts[numVerts].st[1] = texCoords[ind][1];
189 overlayIndexes[numIndexes++] = vertexRemap[ind];
197 overlaySurface_t *s = (overlaySurface_t *) Mem_Alloc( sizeof( overlaySurface_t ) );
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;
207 for ( i = 0; i < materials.Num(); i++ ) {
208 if ( materials[i]->material == mtr ) {
212 if ( i < materials.Num() ) {
213 materials[i]->surfaces.Append( s );
215 overlayMaterial_t *mat = new overlayMaterial_t;
217 mat->surfaces.Append( s );
218 materials.Append( mat );
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 );
233 idRenderModelOverlay::AddOverlaySurfacesToModel
236 void idRenderModelOverlay::AddOverlaySurfacesToModel( idRenderModel *baseModel ) {
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;
244 if ( baseModel == NULL || baseModel->IsDefaultModel() ) {
248 // md5 models won't have any surfaces when r_showSkel is set
249 if ( !baseModel->NumSurfaces() ) {
253 if ( baseModel->IsDynamicModel() != DM_STATIC ) {
254 common->Error( "idRenderModelOverlay::AddOverlaySurfacesToModel: baseModel is not a static model" );
257 assert( dynamic_cast<idRenderModelStatic *>(baseModel) != NULL );
258 staticModel = static_cast<idRenderModelStatic *>(baseModel);
260 staticModel->overlaysAdded = 0;
262 if ( !materials.Num() ) {
263 staticModel->DeleteSurfacesWithNegativeId();
267 for ( k = 0; k < materials.Num(); k++ ) {
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;
275 if ( staticModel->FindSurfaceWithId( -1 - k, surfaceNum ) ) {
276 newSurf = &staticModel->surfaces[surfaceNum];
278 newSurf = &staticModel->surfaces.Alloc();
279 newSurf->geometry = NULL;
280 newSurf->shader = materials[k]->material;
281 newSurf->id = -1 - k;
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] ) );
291 R_FreeStaticTriSurfVertexCaches( newSurf->geometry );
294 newTri = newSurf->geometry;
295 numVerts = numIndexes = 0;
297 for ( i = 0; i < materials[k]->surfaces.Num(); i++ ) {
298 surf = materials[k]->surfaces[i];
300 // get the model surface for this overlay surface
301 if ( surf->surfaceNum < staticModel->NumSurfaces() ) {
302 baseSurf = staticModel->Surface( surf->surfaceNum );
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 );
313 // the surface with this id no longer exists
315 materials[k]->surfaces.RemoveIndex( i );
322 for ( j = 0; j < surf->numIndexes; j++ ) {
323 newTri->indexes[numIndexes + j] = numVerts + surf->indexes[j];
325 numIndexes += surf->numIndexes;
328 for ( j = 0; j < surf->numVerts; j++ ) {
329 overlayVertex_t *overlayVert = &surf->verts[j];
331 newTri->verts[numVerts].st[0] = overlayVert->st[0];
332 newTri->verts[numVerts].st[1] = overlayVert->st[1];
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." );
338 materials[k]->surfaces.RemoveIndex( i );
339 staticModel->DeleteSurfaceWithId( newSurf->id );
342 newTri->verts[numVerts].xyz = baseSurf->geometry->verts[overlayVert->vertexNum].xyz;
347 newTri->numVerts = numVerts;
348 newTri->numIndexes = numIndexes;
349 R_BoundTriSurf( newTri );
351 staticModel->overlaysAdded++; // so we don't create an overlay on an overlay surface
357 idRenderModelOverlay::RemoveOverlaySurfacesFromModel
360 void idRenderModelOverlay::RemoveOverlaySurfacesFromModel( idRenderModel *baseModel ) {
361 idRenderModelStatic *staticModel;
363 assert( dynamic_cast<idRenderModelStatic *>(baseModel) != NULL );
364 staticModel = static_cast<idRenderModelStatic *>(baseModel);
366 staticModel->DeleteSurfacesWithNegativeId();
367 staticModel->overlaysAdded = 0;
372 idRenderModelOverlay::ReadFromDemoFile
375 void idRenderModelOverlay::ReadFromDemoFile( idDemoFile *f ) {
381 idRenderModelOverlay::WriteToDemoFile
384 void idRenderModelOverlay::WriteToDemoFile( idDemoFile *f ) const {