DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

CollisionModel_debug.cpp (15677B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, the Doom 3 BFG Edition 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 BFG Edition 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 /*
     30 ===============================================================================
     31 
     32 	Trace model vs. polygonal model collision detection.
     33 
     34 ===============================================================================
     35 */
     36 
     37 #pragma hdrstop
     38 #include "../idlib/precompiled.h"
     39 
     40 
     41 #include "CollisionModel_local.h"
     42 
     43 
     44 /*
     45 ===============================================================================
     46 
     47 Visualisation code
     48 
     49 ===============================================================================
     50 */
     51 
     52 const char *cm_contentsNameByIndex[] = {
     53 	"none",							// 0
     54 	"solid",						// 1
     55 	"opaque",						// 2
     56 	"water",						// 3
     57 	"playerclip",					// 4
     58 	"monsterclip",					// 5
     59 	"moveableclip",					// 6
     60 	"ikclip",						// 7
     61 	"blood",						// 8
     62 	"body",							// 9
     63 	"corpse",						// 10
     64 	"trigger",						// 11
     65 	"aas_solid",					// 12
     66 	"aas_obstacle",					// 13
     67 	"flashlight_trigger",			// 14
     68 	NULL
     69 };
     70 
     71 int cm_contentsFlagByIndex[] = {
     72 	-1,								// 0
     73 	CONTENTS_SOLID,					// 1
     74 	CONTENTS_OPAQUE,				// 2
     75 	CONTENTS_WATER,					// 3
     76 	CONTENTS_PLAYERCLIP,			// 4
     77 	CONTENTS_MONSTERCLIP,			// 5
     78 	CONTENTS_MOVEABLECLIP,			// 6
     79 	CONTENTS_IKCLIP,				// 7
     80 	CONTENTS_BLOOD,					// 8
     81 	CONTENTS_BODY,					// 9
     82 	CONTENTS_CORPSE,				// 10
     83 	CONTENTS_TRIGGER,				// 11
     84 	CONTENTS_AAS_SOLID,				// 12
     85 	CONTENTS_AAS_OBSTACLE,			// 13
     86 	CONTENTS_FLASHLIGHT_TRIGGER,	// 14
     87 	0
     88 };
     89 
     90 idCVar cm_drawMask(			"cm_drawMask",			"none",		CVAR_GAME,				"collision mask", cm_contentsNameByIndex, idCmdSystem::ArgCompletion_String<cm_contentsNameByIndex> );
     91 idCVar cm_drawColor(		"cm_drawColor",			"1 0 0 .5",	CVAR_GAME,				"color used to draw the collision models" );
     92 idCVar cm_drawFilled(		"cm_drawFilled",		"0",		CVAR_GAME | CVAR_BOOL,	"draw filled polygons" );
     93 idCVar cm_drawInternal(		"cm_drawInternal",		"1",		CVAR_GAME | CVAR_BOOL,	"draw internal edges green" );
     94 idCVar cm_drawNormals(		"cm_drawNormals",		"0",		CVAR_GAME | CVAR_BOOL,	"draw polygon and edge normals" );
     95 idCVar cm_backFaceCull(		"cm_backFaceCull",		"0",		CVAR_GAME | CVAR_BOOL,	"cull back facing polygons" );
     96 idCVar cm_debugCollision(	"cm_debugCollision",	"0",		CVAR_GAME | CVAR_BOOL,	"debug the collision detection" );
     97 
     98 static idVec4 cm_color;
     99 
    100 /*
    101 ================
    102 idCollisionModelManagerLocal::ContentsFromString
    103 ================
    104 */
    105 int idCollisionModelManagerLocal::ContentsFromString( const char *string ) const {
    106 	int i, contents = 0;
    107 	idLexer src( string, idStr::Length( string ), "ContentsFromString" );
    108 	idToken token;
    109 
    110 	while( src.ReadToken( &token ) ) {
    111 		if ( token == "," ) {
    112 			continue;
    113 		}
    114 		for ( i = 1; cm_contentsNameByIndex[i] != NULL; i++ ) {
    115 			if ( token.Icmp( cm_contentsNameByIndex[i] ) == 0 ) {
    116 				contents |= cm_contentsFlagByIndex[i];
    117 				break;
    118 			}
    119 		}
    120 	}
    121 
    122 	return contents;
    123 }
    124 
    125 /*
    126 ================
    127 idCollisionModelManagerLocal::StringFromContents
    128 ================
    129 */
    130 const char *idCollisionModelManagerLocal::StringFromContents( const int contents ) const {
    131 	int i, length = 0;
    132 	static char contentsString[MAX_STRING_CHARS];
    133 
    134 	contentsString[0] = '\0';
    135 
    136 	for ( i = 1; cm_contentsFlagByIndex[i] != 0; i++ ) {
    137 		if ( contents & cm_contentsFlagByIndex[i] ) {
    138 			if ( length != 0 ) {
    139 				length += idStr::snPrintf( contentsString + length, sizeof( contentsString ) - length, "," );
    140 			}
    141 			length += idStr::snPrintf( contentsString + length, sizeof( contentsString ) - length, cm_contentsNameByIndex[i] );
    142 		}
    143 	}
    144 
    145 	return contentsString;
    146 }
    147 
    148 /*
    149 ================
    150 idCollisionModelManagerLocal::DrawEdge
    151 ================
    152 */
    153 void idCollisionModelManagerLocal::DrawEdge( cm_model_t *model, int edgeNum, const idVec3 &origin, const idMat3 &axis ) {
    154 	int side;
    155 	cm_edge_t *edge;
    156 	idVec3 start, end, mid;
    157 	bool isRotated;
    158 
    159 	isRotated = axis.IsRotated();
    160 
    161 	edge = model->edges + abs(edgeNum);
    162 	side = edgeNum < 0;
    163 
    164 	start = model->vertices[edge->vertexNum[side]].p;
    165 	end = model->vertices[edge->vertexNum[!side]].p;
    166 	if ( isRotated ) {
    167 		start *= axis;
    168 		end *= axis;
    169 	}
    170 	start += origin;
    171 	end += origin;
    172 
    173 	if ( edge->internal ) {
    174 		if ( cm_drawInternal.GetBool() ) {
    175 			common->RW()->DebugArrow( colorGreen, start, end, 1 );
    176 		}
    177 	} else {
    178 		if ( edge->numUsers > 2 ) {
    179 			common->RW()->DebugArrow( colorBlue, start, end, 1 );
    180 		} else {
    181 			common->RW()->DebugArrow( cm_color, start, end, 1 );
    182 		}
    183 	}
    184 
    185 	if ( cm_drawNormals.GetBool() ) {
    186 		mid = (start + end) * 0.5f;
    187 		if ( isRotated ) {
    188 			end = mid + 5 * (axis * edge->normal);
    189 		} else {
    190 			end = mid + 5 * edge->normal;
    191 		}
    192 		common->RW()->DebugArrow( colorCyan, mid, end, 1 );
    193 	}
    194 }
    195 
    196 /*
    197 ================
    198 idCollisionModelManagerLocal::DrawPolygon
    199 ================
    200 */
    201 void idCollisionModelManagerLocal::DrawPolygon( cm_model_t *model, cm_polygon_t *p, const idVec3 &origin, const idMat3 &axis, const idVec3 &viewOrigin ) {
    202 	int i, edgeNum;
    203 	cm_edge_t *edge;
    204 	idVec3 center, end, dir;
    205 
    206 	if ( cm_backFaceCull.GetBool() ) {
    207 		edgeNum = p->edges[0];
    208 		edge = model->edges + abs(edgeNum);
    209 		dir = model->vertices[edge->vertexNum[0]].p - viewOrigin;
    210 		if ( dir * p->plane.Normal() > 0.0f ) {
    211 			return;
    212 		}
    213 	}
    214 
    215 	if ( cm_drawNormals.GetBool() ) {
    216 		center = vec3_origin;
    217 		for ( i = 0; i < p->numEdges; i++ ) {
    218 			edgeNum = p->edges[i];
    219 			edge = model->edges + abs(edgeNum);
    220 			center += model->vertices[edge->vertexNum[edgeNum < 0]].p;
    221 		}
    222 		center *= (1.0f / p->numEdges);
    223 		if ( axis.IsRotated() ) {
    224 			center = center * axis + origin;
    225 			end = center + 5 * (axis * p->plane.Normal());
    226 		} else {
    227 			center += origin;
    228 			end = center + 5 * p->plane.Normal();
    229 		}
    230 		common->RW()->DebugArrow( colorMagenta, center, end, 1 );
    231 	}
    232 
    233 	if ( cm_drawFilled.GetBool() ) {
    234 		idFixedWinding winding;
    235 		for ( i = p->numEdges - 1; i >= 0; i-- ) {
    236 			edgeNum = p->edges[i];
    237 			edge = model->edges + abs(edgeNum);
    238 			winding += origin + model->vertices[edge->vertexNum[INT32_SIGNBITSET(edgeNum)]].p * axis;
    239 		}
    240 		common->RW()->DebugPolygon( cm_color, winding );
    241 	} else {
    242 		for ( i = 0; i < p->numEdges; i++ ) {
    243 			edgeNum = p->edges[i];
    244 			edge = model->edges + abs(edgeNum);
    245 			if ( edge->checkcount == checkCount ) {
    246 				continue;
    247 			}
    248 			edge->checkcount = checkCount;
    249 			DrawEdge( model, edgeNum, origin, axis );
    250 		}
    251 	}
    252 }
    253 
    254 /*
    255 ================
    256 idCollisionModelManagerLocal::DrawNodePolygons
    257 ================
    258 */
    259 void idCollisionModelManagerLocal::DrawNodePolygons( cm_model_t *model, cm_node_t *node,
    260 										   const idVec3 &origin, const idMat3 &axis,
    261 										   const idVec3 &viewOrigin, const float radius ) {
    262 	int i;
    263 	cm_polygon_t *p;
    264 	cm_polygonRef_t *pref;
    265 
    266 	while (1) {
    267 		for ( pref = node->polygons; pref; pref = pref->next ) {
    268 			p = pref->p;
    269 			if ( radius ) {
    270 				// polygon bounds should overlap with trace bounds
    271 				for ( i = 0; i < 3; i++ ) {
    272 					if ( p->bounds[0][i] > viewOrigin[i] + radius ) {
    273 						break;
    274 					}
    275 					if ( p->bounds[1][i] < viewOrigin[i] - radius ) {
    276 						break;
    277 					}
    278 				}
    279 				if ( i < 3 ) {
    280 					continue;
    281 				}
    282 			}
    283 			if ( p->checkcount == checkCount ) {
    284 				continue;
    285 			}
    286 			if ( !( p->contents & cm_contentsFlagByIndex[cm_drawMask.GetInteger()] ) ) {
    287 				continue;
    288 			}
    289 
    290 			DrawPolygon( model, p, origin, axis, viewOrigin );
    291 			p->checkcount = checkCount;
    292 		}
    293 		if ( node->planeType == -1 ) {
    294 			break;
    295 		}
    296 		if ( radius && viewOrigin[node->planeType] > node->planeDist + radius  ) {
    297 			node = node->children[0];
    298 		} else if ( radius && viewOrigin[node->planeType] < node->planeDist - radius  ) {
    299 			node = node->children[1];
    300 		} else {
    301 			DrawNodePolygons( model, node->children[1], origin, axis, viewOrigin, radius );
    302 			node = node->children[0];
    303 		}
    304 	}
    305 }
    306 
    307 /*
    308 ================
    309 idCollisionModelManagerLocal::DrawModel
    310 ================
    311 */
    312 void idCollisionModelManagerLocal::DrawModel( cmHandle_t handle, const idVec3 &modelOrigin, const idMat3 &modelAxis,
    313 					const idVec3 &viewOrigin, const float radius ) {
    314 
    315 	cm_model_t *model;
    316 	idVec3 viewPos;
    317 
    318 	if ( handle < 0 && handle >= numModels ) {
    319 		return;
    320 	}
    321 
    322 	if ( cm_drawColor.IsModified() ) {
    323 		sscanf( cm_drawColor.GetString(), "%f %f %f %f", &cm_color.x, &cm_color.y, &cm_color.z, &cm_color.w );
    324 		cm_drawColor.ClearModified();
    325 	}
    326 
    327 	model = models[ handle ];
    328 	viewPos = (viewOrigin - modelOrigin) * modelAxis.Transpose();
    329 	checkCount++;
    330 	DrawNodePolygons( model, model->node, modelOrigin, modelAxis, viewPos, radius );
    331 }
    332 
    333 /*
    334 ===============================================================================
    335 
    336 Speed test code
    337 
    338 ===============================================================================
    339 */
    340 
    341 static idCVar cm_testCollision(		"cm_testCollision",		"0",					CVAR_GAME | CVAR_BOOL,		"" );
    342 static idCVar cm_testRotation(		"cm_testRotation",		"1",					CVAR_GAME | CVAR_BOOL,		"" );
    343 static idCVar cm_testModel(			"cm_testModel",			"0",					CVAR_GAME | CVAR_INTEGER,	"" );
    344 static idCVar cm_testTimes(			"cm_testTimes",			"1000",					CVAR_GAME | CVAR_INTEGER,	"" );
    345 static idCVar cm_testRandomMany(	"cm_testRandomMany",	"0",					CVAR_GAME | CVAR_BOOL,		"" );
    346 static idCVar cm_testOrigin(		"cm_testOrigin",		"0 0 0",				CVAR_GAME,					"" );
    347 static idCVar cm_testReset(			"cm_testReset",			"0",					CVAR_GAME | CVAR_BOOL,		"" );
    348 static idCVar cm_testBox(			"cm_testBox",			"-16 -16 0 16 16 64",	CVAR_GAME,					"" );
    349 static idCVar cm_testBoxRotation(	"cm_testBoxRotation",	"0 0 0",				CVAR_GAME,					"" );
    350 static idCVar cm_testWalk(			"cm_testWalk",			"1",					CVAR_GAME | CVAR_BOOL,		"" );
    351 static idCVar cm_testLength(		"cm_testLength",		"1024",					CVAR_GAME | CVAR_FLOAT,		"" );
    352 static idCVar cm_testRadius(		"cm_testRadius",		"64",					CVAR_GAME | CVAR_FLOAT,		"" );
    353 static idCVar cm_testAngle(			"cm_testAngle",			"60",					CVAR_GAME | CVAR_FLOAT,		"" );
    354 
    355 static int total_translation;
    356 static int min_translation = 999999;
    357 static int max_translation = -999999;
    358 static int num_translation = 0;
    359 static int total_rotation;
    360 static int min_rotation = 999999;
    361 static int max_rotation = -999999;
    362 static int num_rotation = 0;
    363 static idVec3 start;
    364 static idVec3 *testend;
    365 
    366 #include "../sys/sys_public.h"
    367 
    368 void idCollisionModelManagerLocal::DebugOutput( const idVec3 &origin ) {
    369 	int i, k, t;
    370 	char buf[128];
    371 	idVec3 end;
    372 	idAngles boxAngles;
    373 	idMat3 modelAxis, boxAxis;
    374 	idBounds bounds;
    375 	trace_t trace;
    376 
    377 	if ( !cm_testCollision.GetBool() ) {
    378 		return;
    379 	}
    380 
    381 	testend = (idVec3 *) Mem_Alloc( cm_testTimes.GetInteger() * sizeof(idVec3), TAG_COLLISION );
    382 
    383 	if ( cm_testReset.GetBool() || ( cm_testWalk.GetBool() && !start.Compare( start ) ) ) {
    384 		total_translation = total_rotation = 0;
    385 		min_translation = min_rotation = 999999;
    386 		max_translation = max_rotation = -999999;
    387 		num_translation = num_rotation = 0;
    388 		cm_testReset.SetBool( false );
    389 	}
    390 
    391 	if ( cm_testWalk.GetBool() ) {
    392 		start = origin;
    393 		cm_testOrigin.SetString( va( "%1.2f %1.2f %1.2f", start[0], start[1], start[2] ) );
    394 	} else {
    395 		sscanf( cm_testOrigin.GetString(), "%f %f %f", &start[0], &start[1], &start[2] );
    396 	}
    397 
    398 	sscanf( cm_testBox.GetString(), "%f %f %f %f %f %f", &bounds[0][0], &bounds[0][1], &bounds[0][2],
    399 										&bounds[1][0], &bounds[1][1], &bounds[1][2] );
    400 	sscanf( cm_testBoxRotation.GetString(), "%f %f %f", &boxAngles[0], &boxAngles[1], &boxAngles[2] );
    401 	boxAxis = boxAngles.ToMat3();
    402 	modelAxis.Identity();
    403 
    404 	idTraceModel itm( bounds );
    405 	idRandom random( 0 );
    406 	idTimer timer;
    407 
    408 	if ( cm_testRandomMany.GetBool() ) {
    409 		// if many traces in one random direction
    410 		for ( i = 0; i < 3; i++ ) {
    411 			testend[0][i] = start[i] + random.CRandomFloat() * cm_testLength.GetFloat();
    412 		}
    413 		for ( k = 1; k < cm_testTimes.GetInteger(); k++ ) {
    414 			testend[k] = testend[0];
    415 		}
    416 	} else {
    417 		// many traces each in a different random direction
    418 		for ( k = 0; k < cm_testTimes.GetInteger(); k++ ) {
    419 			for ( i = 0; i < 3; i++ ) {
    420 				testend[k][i] = start[i] + random.CRandomFloat() * cm_testLength.GetFloat();
    421 			}
    422 		}
    423 	}
    424 
    425 	// translational collision detection
    426 	timer.Clear();
    427 	timer.Start();
    428 	for ( i = 0; i < cm_testTimes.GetInteger(); i++ ) {
    429 		Translation( &trace, start, testend[i], &itm, boxAxis, CONTENTS_SOLID|CONTENTS_PLAYERCLIP, cm_testModel.GetInteger(), vec3_origin, modelAxis );
    430 	}
    431 	timer.Stop();
    432 	t = timer.Milliseconds();
    433 	if ( t < min_translation ) min_translation = t;
    434 	if ( t > max_translation ) max_translation = t;
    435 	num_translation++;
    436 	total_translation += t;
    437 	if ( cm_testTimes.GetInteger() > 9999 ) {
    438 		sprintf( buf, "%3dK", (int ) ( cm_testTimes.GetInteger() / 1000 ) );
    439 	} else {
    440 		sprintf( buf, "%4d", cm_testTimes.GetInteger() );
    441 	}
    442 	common->Printf("%s translations: %4d milliseconds, (min = %d, max = %d, av = %1.1f)\n", buf, t, min_translation, max_translation, (float) total_translation / num_translation );
    443 
    444 	if ( cm_testRandomMany.GetBool() ) {
    445 		// if many traces in one random direction
    446 		for ( i = 0; i < 3; i++ ) {
    447 			testend[0][i] = start[i] + random.CRandomFloat() * cm_testRadius.GetFloat();
    448 		}
    449 		for ( k = 1; k < cm_testTimes.GetInteger(); k++ ) {
    450 			testend[k] = testend[0];
    451 		}
    452 	} else {
    453 		// many traces each in a different random direction
    454 		for ( k = 0; k < cm_testTimes.GetInteger(); k++ ) {
    455 			for ( i = 0; i < 3; i++ ) {
    456 				testend[k][i] = start[i] + random.CRandomFloat() * cm_testRadius.GetFloat();
    457 			}
    458 		}
    459 	}
    460 
    461 	if ( cm_testRotation.GetBool() ) {
    462 		// rotational collision detection
    463 		idVec3 vec( random.CRandomFloat(), random.CRandomFloat(), random.RandomFloat() );
    464 		vec.Normalize();
    465 		idRotation rotation( vec3_origin, vec, cm_testAngle.GetFloat() );
    466 
    467 		timer.Clear();
    468 		timer.Start();
    469 		for ( i = 0; i < cm_testTimes.GetInteger(); i++ ) {
    470 			rotation.SetOrigin( testend[i] );
    471 			Rotation( &trace, start, rotation, &itm, boxAxis, CONTENTS_SOLID|CONTENTS_PLAYERCLIP, cm_testModel.GetInteger(), vec3_origin, modelAxis );
    472 		}
    473 		timer.Stop();
    474 		t = timer.Milliseconds();
    475 		if ( t < min_rotation ) min_rotation = t;
    476 		if ( t > max_rotation ) max_rotation = t;
    477 		num_rotation++;
    478 		total_rotation += t;
    479 		if ( cm_testTimes.GetInteger() > 9999 ) {
    480 			sprintf( buf, "%3dK", (int ) ( cm_testTimes.GetInteger() / 1000 ) );
    481 		} else {
    482 			sprintf( buf, "%4d", cm_testTimes.GetInteger() );
    483 		}
    484 		common->Printf("%s rotation: %4d milliseconds, (min = %d, max = %d, av = %1.1f)\n", buf, t, min_rotation, max_rotation, (float) total_rotation / num_rotation );
    485 	}
    486 
    487 	Mem_Free( testend );
    488 	testend = NULL;
    489 }