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