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