]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/renderer/ModelOverlay.cpp
Use the same OpenAL headers on all platforms.
[icculus/iodoom3.git] / neo / renderer / ModelOverlay.cpp
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 */
41 idRenderModelOverlay::idRenderModelOverlay() {
42 }
43
44 /*
45 ====================
46 idRenderModelOverlay::~idRenderModelOverlay
47 ====================
48 */
49 idRenderModelOverlay::~idRenderModelOverlay() {
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 */
67 idRenderModelOverlay *idRenderModelOverlay::Alloc( void ) {
68         return new idRenderModelOverlay;
69 }
70
71 /*
72 ====================
73 idRenderModelOverlay::Free
74 ====================
75 */
76 void idRenderModelOverlay::Free( idRenderModelOverlay *overlay ) {
77         delete overlay;
78 }
79
80 /*
81 ====================
82 idRenderModelOverlay::FreeSurface
83 ====================
84 */
85 void idRenderModelOverlay::FreeSurface( overlaySurface_t *surface ) {
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
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;
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 {
215                         overlayMaterial_t *mat = new overlayMaterial_t;
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 */
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;
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 {
291                         R_FreeStaticTriSurfVertexCaches( newSurf->geometry );
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 */
360 void idRenderModelOverlay::RemoveOverlaySurfacesFromModel( idRenderModel *baseModel ) {
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 */
375 void idRenderModelOverlay::ReadFromDemoFile( idDemoFile *f ) {
376         // FIXME: implement
377 }
378
379 /*
380 ====================
381 idRenderModelOverlay::WriteToDemoFile
382 ====================
383 */
384 void idRenderModelOverlay::WriteToDemoFile( idDemoFile *f ) const {
385         // FIXME: implement
386 }