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"
33 #include "Model_local.h"
35 // decalFade filter 5 0.1
38 // map invertColor( textures/splat )
39 // blend GL_ZERO GL_ONE_MINUS_SRC
46 idRenderModelDecal::idRenderModelDecal
49 idRenderModelDecal::idRenderModelDecal( void ) {
50 memset( &tri, 0, sizeof( tri ) );
52 tri.indexes = indexes;
59 idRenderModelDecal::~idRenderModelDecal
62 idRenderModelDecal::~idRenderModelDecal( void ) {
67 idRenderModelDecal::idRenderModelDecal
70 idRenderModelDecal *idRenderModelDecal::Alloc( void ) {
71 return new idRenderModelDecal;
76 idRenderModelDecal::idRenderModelDecal
79 void idRenderModelDecal::Free( idRenderModelDecal *decal ) {
85 idRenderModelDecal::CreateProjectionInfo
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 ) {
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 );
95 assert( material != NULL );
97 info.projectionOrigin = projectionOrigin;
98 info.material = material;
99 info.parallel = parallel;
100 info.fadeDepth = fadeDepth;
101 info.startTime = startTime;
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 );
109 // find the bounds for the projection
110 winding.GetBounds( info.projectionBounds );
112 info.projectionBounds.ExpandSelf( depth );
114 info.projectionBounds.AddPoint( projectionOrigin );
117 // calculate the world space projection volume bounding planes, positive sides face outside the decal
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() );
126 for ( int i = 0; i < winding.GetNumPoints(); i++ ) {
127 info.boundingPlanes[i].FromPoints( projectionOrigin, winding[i].ToVec3(), winding[(i+1)%winding.GetNumPoints()].ToVec3() );
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;
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;
140 // calculate the texture vectors for the winding
141 float len, texArea, inva;
145 const idVec5 &a = winding[0];
146 const idVec5 &b = winding[1];
147 const idVec5 &c = winding[2];
149 d0 = b.ToVec3() - a.ToVec3();
152 d1 = c.ToVec3() - a.ToVec3();
156 texArea = ( d0[3] * d1[4] ) - ( d0[4] * d1[3] );
157 inva = 1.0f / texArea;
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() );
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() );
178 idRenderModelDecal::CreateProjectionInfo
181 void idRenderModelDecal::GlobalProjectionInfoToLocal( decalProjectionInfo_t &localInfo, const decalProjectionInfo_t &info, const idVec3 &origin, const idMat3 &axis ) {
182 float modelMatrix[16];
184 R_AxisToModelMatrix( axis, origin, modelMatrix );
186 for ( int j = 0; j < NUM_DECAL_BOUNDING_PLANES; j++ ) {
187 R_GlobalPlaneToLocal( modelMatrix, info.boundingPlanes[j], localInfo.boundingPlanes[j] );
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;
206 idRenderModelDecal::AddWinding
209 void idRenderModelDecal::AddWinding( const idWinding &w, const idMaterial *decalMaterial, const idPlane fadePlanes[2], float fadeDepth, int startTime ) {
211 float invFadeDepth, fade;
212 decalInfo_t decalInfo;
214 if ( ( material == NULL || material == decalMaterial ) &&
215 tri.numVerts + w.GetNumPoints() < MAX_DECAL_VERTS &&
216 tri.numIndexes + ( w.GetNumPoints() - 2 ) * 3 < MAX_DECAL_INDEXES ) {
218 material = decalMaterial;
221 decalInfo = material->GetDecalInfo();
222 invFadeDepth = -1.0f / fadeDepth;
224 for ( i = 0; i < w.GetNumPoints(); i++ ) {
225 fade = fadePlanes[0].Distance( w[i].ToVec3() ) * invFadeDepth;
227 fade = fadePlanes[1].Distance( w[i].ToVec3() ) * invFadeDepth;
231 } else if ( fade > 0.99f ) {
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 );
243 } else if ( icolor > 255 ) {
246 tri.verts[tri.numVerts + i].color[k] = icolor;
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;
258 tri.numVerts += w.GetNumPoints();
262 // if we are at the end of the list, create a new decal
264 nextDecal = idRenderModelDecal::Alloc();
266 // let the next decal on the chain take a look
267 nextDecal->AddWinding( w, decalMaterial, fadePlanes, fadeDepth, startTime );
272 idRenderModelDecal::AddDepthFadedWinding
275 void idRenderModelDecal::AddDepthFadedWinding( const idWinding &w, const idMaterial *decalMaterial, const idPlane fadePlanes[2], float fadeDepth, int startTime ) {
276 idFixedWinding front, back;
279 if ( front.Split( &back, fadePlanes[0], 0.1f ) == SIDE_CROSS ) {
280 AddWinding( back, decalMaterial, fadePlanes, fadeDepth, startTime );
283 if ( front.Split( &back, fadePlanes[1], 0.1f ) == SIDE_CROSS ) {
284 AddWinding( back, decalMaterial, fadePlanes, fadeDepth, startTime );
287 AddWinding( front, decalMaterial, fadePlanes, fadeDepth, startTime );
292 idRenderModelDecal::CreateDecal
295 void idRenderModelDecal::CreateDecal( const idRenderModel *model, const decalProjectionInfo_t &localInfo ) {
297 // check all model surfaces
298 for ( int surfNum = 0; surfNum < model->NumSurfaces(); surfNum++ ) {
299 const modelSurface_t *surf = model->Surface( surfNum );
301 // if no geometry or no shader
302 if ( !surf->geometry || !surf->shader ) {
306 // decals and overlays use the same rules
307 if ( !localInfo.force && !surf->shader->AllowOverlays() ) {
311 srfTriangles_t *stri = surf->geometry;
313 // if the triangle bounds do not overlap with projection bounds
314 if ( !localInfo.projectionBounds.IntersectsBounds( stri->bounds ) ) {
318 // allocate memory for the cull bits
319 byte *cullBits = (byte *)_alloca16( stri->numVerts * sizeof( cullBits[0] ) );
321 // catagorize all points by the planes
322 SIMDProcessor->DecalPointCull( cullBits, localInfo.boundingPlanes, stri->verts, stri->numVerts );
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];
330 // skip triangles completely off one side
331 if ( cullBits[v1] & cullBits[v2] & cullBits[v3] ) {
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 ) {
341 // create a winding with texture coordinates for the triangle
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() );
351 for ( int j = 0; j < 3; j++ ) {
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 );
364 int orBits = cullBits[v1] | cullBits[v2] | cullBits[v3];
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] ) ) {
375 if ( fw.GetNumPoints() == 0 ) {
379 AddDepthFadedWinding( fw, localInfo.material, localInfo.fadePlanes, localInfo.fadeDepth, localInfo.startTime );
385 =====================
386 idRenderModelDecal::RemoveFadedDecals
387 =====================
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;
395 if ( decals == NULL ) {
399 // recursively free any next decals
400 decals->nextDecal = RemoveFadedDecals( decals->nextDecal, time );
402 // free the decals if no material set
403 if ( decals->material == NULL ) {
404 nextDecal = decals->nextDecal;
409 decalInfo = decals->material->GetDecalInfo();
410 minTime = time - ( decalInfo.stayTime + decalInfo.fadeTime );
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];
426 // free the decals if all trianges faded away
427 if ( newNumIndexes == 0 ) {
428 nextDecal = decals->nextDecal;
433 decals->tri.numIndexes = newNumIndexes;
435 memset( inUse, 0, sizeof( inUse ) );
436 for ( i = 0; i < decals->tri.numIndexes; i++ ) {
437 inUse[decals->tri.indexes[i]] = 1;
441 for ( i = 0; i < decals->tri.numVerts; i++ ) {
445 decals->tri.verts[newNumVerts] = decals->tri.verts[i];
446 decals->vertDepthFade[newNumVerts] = decals->vertDepthFade[i];
447 inUse[i] = newNumVerts;
450 decals->tri.numVerts = newNumVerts;
452 for ( i = 0; i < decals->tri.numIndexes; i++ ) {
453 decals->tri.indexes[i] = inUse[decals->tri.indexes[i]];
460 =====================
461 idRenderModelDecal::AddDecalDrawSurf
462 =====================
464 void idRenderModelDecal::AddDecalDrawSurf( viewEntity_t *space ) {
467 decalInfo_t decalInfo;
469 if ( tri.numIndexes == 0 ) {
473 // fade down all the verts with time
474 decalInfo = material->GetDecalInfo();
475 maxTime = decalInfo.stayTime + decalInfo.fadeTime;
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];
481 if ( deltaTime > maxTime ) {
485 if ( deltaTime <= decalInfo.stayTime ) {
489 deltaTime -= decalInfo.stayTime;
490 f = (float)deltaTime / decalInfo.fadeTime;
492 for ( j = 0; j < 3; j++ ) {
493 int ind = tri.indexes[i+j];
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 );
500 } else if ( icolor > 255 ) {
503 tri.verts[ind].color[k] = icolor;
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 ) );
514 // copy the current vertexes to temp vertex cache
515 newTri->ambientCache = vertexCache.AllocFrameTemp( tri.verts, tri.numVerts * sizeof( idDrawVert ) );
517 // create the drawsurf
518 R_AddDrawSurf( newTri, space, &space->entityDef->parms, material, space->scissorRect );
523 idRenderModelDecal::ReadFromDemoFile
526 void idRenderModelDecal::ReadFromDemoFile( idDemoFile *f ) {
532 idRenderModelDecal::WriteToDemoFile
535 void idRenderModelDecal::WriteToDemoFile( idDemoFile *f ) const {