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 "sys/platform.h"
30 #include "renderer/VertexCache.h"
31 #include "renderer/tr_local.h"
32
33 #include "renderer/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 */
idRenderModelDecal(void)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 */
~idRenderModelDecal(void)62 idRenderModelDecal::~idRenderModelDecal( void ) {
63 }
64
65 /*
66 ==================
67 idRenderModelDecal::idRenderModelDecal
68 ==================
69 */
Alloc(void)70 idRenderModelDecal *idRenderModelDecal::Alloc( void ) {
71 return new idRenderModelDecal;
72 }
73
74 /*
75 ==================
76 idRenderModelDecal::idRenderModelDecal
77 ==================
78 */
Free(idRenderModelDecal * decal)79 void idRenderModelDecal::Free( idRenderModelDecal *decal ) {
80 delete decal;
81 }
82
83 /*
84 =================
85 idRenderModelDecal::CreateProjectionInfo
86 =================
87 */
CreateProjectionInfo(decalProjectionInfo_t & info,const idFixedWinding & winding,const idVec3 & projectionOrigin,const bool parallel,const float fadeDepth,const idMaterial * material,const int startTime)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 */
GlobalProjectionInfoToLocal(decalProjectionInfo_t & localInfo,const decalProjectionInfo_t & info,const idVec3 & origin,const idMat3 & axis)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 */
AddWinding(const idWinding & w,const idMaterial * decalMaterial,const idPlane fadePlanes[2],float fadeDepth,int startTime)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 */
AddDepthFadedWinding(const idWinding & w,const idMaterial * decalMaterial,const idPlane fadePlanes[2],float fadeDepth,int startTime)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 */
CreateDecal(const idRenderModel * model,const decalProjectionInfo_t & localInfo)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 if (!localInfo.boundingPlanes[NUM_DECAL_BOUNDING_PLANES - 1].RayIntersection( fw[j].ToVec3(), dir, scale ))
358 scale = 0.0f;
359 dir = fw[j].ToVec3() + scale * dir;
360 fw[j].s = localInfo.textureAxis[0].Distance( dir );
361 fw[j].t = localInfo.textureAxis[1].Distance( dir );
362 }
363 }
364
365 int orBits = cullBits[v1] | cullBits[v2] | cullBits[v3];
366
367 // clip the exact surface triangle to the projection volume
368 for ( int j = 0; j < NUM_DECAL_BOUNDING_PLANES; j++ ) {
369 if ( orBits & ( 1 << j ) ) {
370 if ( !fw.ClipInPlace( -localInfo.boundingPlanes[j] ) ) {
371 break;
372 }
373 }
374 }
375
376 if ( fw.GetNumPoints() == 0 ) {
377 continue;
378 }
379
380 AddDepthFadedWinding( fw, localInfo.material, localInfo.fadePlanes, localInfo.fadeDepth, localInfo.startTime );
381 }
382 }
383 }
384
385 /*
386 =====================
387 idRenderModelDecal::RemoveFadedDecals
388 =====================
389 */
RemoveFadedDecals(idRenderModelDecal * decals,int time)390 idRenderModelDecal *idRenderModelDecal::RemoveFadedDecals( idRenderModelDecal *decals, int time ) {
391 int i, j, minTime, newNumIndexes, newNumVerts;
392 int inUse[MAX_DECAL_VERTS];
393 decalInfo_t decalInfo;
394 idRenderModelDecal *nextDecal;
395
396 if ( decals == NULL ) {
397 return NULL;
398 }
399
400 // recursively free any next decals
401 decals->nextDecal = RemoveFadedDecals( decals->nextDecal, time );
402
403 // free the decals if no material set
404 if ( decals->material == NULL ) {
405 nextDecal = decals->nextDecal;
406 Free( decals );
407 return nextDecal;
408 }
409
410 decalInfo = decals->material->GetDecalInfo();
411 minTime = time - ( decalInfo.stayTime + decalInfo.fadeTime );
412
413 newNumIndexes = 0;
414 for ( i = 0; i < decals->tri.numIndexes; i += 3 ) {
415 if ( decals->indexStartTime[i] > minTime ) {
416 // keep this triangle
417 if ( newNumIndexes != i ) {
418 for ( j = 0; j < 3; j++ ) {
419 decals->tri.indexes[newNumIndexes+j] = decals->tri.indexes[i+j];
420 decals->indexStartTime[newNumIndexes+j] = decals->indexStartTime[i+j];
421 }
422 }
423 newNumIndexes += 3;
424 }
425 }
426
427 // free the decals if all trianges faded away
428 if ( newNumIndexes == 0 ) {
429 nextDecal = decals->nextDecal;
430 Free( decals );
431 return nextDecal;
432 }
433
434 decals->tri.numIndexes = newNumIndexes;
435
436 memset( inUse, 0, sizeof( inUse ) );
437 for ( i = 0; i < decals->tri.numIndexes; i++ ) {
438 inUse[decals->tri.indexes[i]] = 1;
439 }
440
441 newNumVerts = 0;
442 for ( i = 0; i < decals->tri.numVerts; i++ ) {
443 if ( !inUse[i] ) {
444 continue;
445 }
446 decals->tri.verts[newNumVerts] = decals->tri.verts[i];
447 decals->vertDepthFade[newNumVerts] = decals->vertDepthFade[i];
448 inUse[i] = newNumVerts;
449 newNumVerts++;
450 }
451 decals->tri.numVerts = newNumVerts;
452
453 for ( i = 0; i < decals->tri.numIndexes; i++ ) {
454 decals->tri.indexes[i] = inUse[decals->tri.indexes[i]];
455 }
456
457 return decals;
458 }
459
460 /*
461 =====================
462 idRenderModelDecal::AddDecalDrawSurf
463 =====================
464 */
AddDecalDrawSurf(viewEntity_t * space)465 void idRenderModelDecal::AddDecalDrawSurf( viewEntity_t *space ) {
466 int i, j, maxTime;
467 float f;
468 decalInfo_t decalInfo;
469
470 if ( tri.numIndexes == 0 ) {
471 return;
472 }
473
474 // fade down all the verts with time
475 decalInfo = material->GetDecalInfo();
476 maxTime = decalInfo.stayTime + decalInfo.fadeTime;
477
478 // set vertex colors and remove faded triangles
479 for ( i = 0 ; i < tri.numIndexes ; i += 3 ) {
480 int deltaTime = tr.viewDef->renderView.time - indexStartTime[i];
481
482 if ( deltaTime > maxTime ) {
483 continue;
484 }
485
486 if ( deltaTime <= decalInfo.stayTime ) {
487 continue;
488 }
489
490 deltaTime -= decalInfo.stayTime;
491 f = (float)deltaTime / decalInfo.fadeTime;
492
493 for ( j = 0; j < 3; j++ ) {
494 int ind = tri.indexes[i+j];
495
496 for ( int k = 0; k < 4; k++ ) {
497 float fcolor = decalInfo.start[k] + ( decalInfo.end[k] - decalInfo.start[k] ) * f;
498 int icolor = idMath::FtoiFast( fcolor * vertDepthFade[ind] * 255.0f );
499 if ( icolor < 0 ) {
500 icolor = 0;
501 } else if ( icolor > 255 ) {
502 icolor = 255;
503 }
504 tri.verts[ind].color[k] = icolor;
505 }
506 }
507 }
508
509 // copy the tri and indexes to temp heap memory,
510 // because if we are running multi-threaded, we wouldn't
511 // be able to reorganize the index list
512 srfTriangles_t *newTri = (srfTriangles_t *)R_FrameAlloc( sizeof( *newTri ) );
513 *newTri = tri;
514
515 // copy the current vertexes to temp vertex cache
516 newTri->ambientCache = vertexCache.AllocFrameTemp( tri.verts, tri.numVerts * sizeof( idDrawVert ) );
517
518 // create the drawsurf
519 R_AddDrawSurf( newTri, space, &space->entityDef->parms, material, space->scissorRect );
520 }
521
522 /*
523 ====================
524 idRenderModelDecal::ReadFromDemoFile
525 ====================
526 */
ReadFromDemoFile(idDemoFile * f)527 void idRenderModelDecal::ReadFromDemoFile( idDemoFile *f ) {
528 // FIXME: implement
529 }
530
531 /*
532 ====================
533 idRenderModelDecal::WriteToDemoFile
534 ====================
535 */
WriteToDemoFile(idDemoFile * f) const536 void idRenderModelDecal::WriteToDemoFile( idDemoFile *f ) const {
537 // FIXME: implement
538 }
539