as released 2006-10-13

This commit is contained in:
archive 2006-10-13 00:00:00 +00:00
parent 0d7517fbb2
commit b96d945884
9 changed files with 0 additions and 9241 deletions

View file

@ -1,48 +0,0 @@
/*
===============================================================================
Trace model vs. polygonal model collision detection.
===============================================================================
*/
#include "../idlib/precompiled.h"
#pragma hdrstop
#include "CollisionModel_local.h"
/*
===============================================================================
Retrieving contacts
===============================================================================
*/
/*
==================
idCollisionModelManagerLocal::Contacts
==================
*/
int idCollisionModelManagerLocal::Contacts( contactInfo_t *contacts, const int maxContacts, const idVec3 &start, const idVec6 &dir, const float depth,
const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
cmHandle_t model, const idVec3 &origin, const idMat3 &modelAxis ) {
trace_t results;
idVec3 end;
// same as Translation but instead of storing the first collision we store all collisions as contacts
idCollisionModelManagerLocal::getContacts = true;
idCollisionModelManagerLocal::contacts = contacts;
idCollisionModelManagerLocal::maxContacts = maxContacts;
idCollisionModelManagerLocal::numContacts = 0;
end = start + dir.SubVec3(0) * depth;
idCollisionModelManagerLocal::Translation( &results, start, end, trm, trmAxis, contentMask, model, origin, modelAxis );
if ( dir.SubVec3(1).LengthSqr() != 0.0f ) {
// FIXME: rotational contacts
}
idCollisionModelManagerLocal::getContacts = false;
idCollisionModelManagerLocal::maxContacts = 0;
return idCollisionModelManagerLocal::numContacts;
}

View file

@ -1,614 +0,0 @@
/*
===============================================================================
Trace model vs. polygonal model collision detection.
===============================================================================
*/
#include "../idlib/precompiled.h"
#pragma hdrstop
#include "CollisionModel_local.h"
/*
===============================================================================
Contents test
===============================================================================
*/
/*
================
idCollisionModelManagerLocal::TestTrmVertsInBrush
returns true if any of the trm vertices is inside the brush
================
*/
bool idCollisionModelManagerLocal::TestTrmVertsInBrush( cm_traceWork_t *tw, cm_brush_t *b ) {
int i, j, numVerts, bestPlane;
float d, bestd;
idVec3 *p;
if ( b->checkcount == idCollisionModelManagerLocal::checkCount ) {
return false;
}
b->checkcount = idCollisionModelManagerLocal::checkCount;
if ( !(b->contents & tw->contents) ) {
return false;
}
// if the brush bounds don't intersect the trace bounds
if ( !b->bounds.IntersectsBounds( tw->bounds ) ) {
return false;
}
if ( tw->pointTrace ) {
numVerts = 1;
}
else {
numVerts = tw->numVerts;
}
for ( j = 0; j < numVerts; j++ ) {
p = &tw->vertices[j].p;
// see if the point is inside the brush
bestPlane = 0;
bestd = -idMath::INFINITY;
for ( i = 0; i < b->numPlanes; i++ ) {
d = b->planes[i].Distance( *p );
if ( d >= 0.0f ) {
break;
}
if ( d > bestd ) {
bestd = d;
bestPlane = i;
}
}
if ( i >= b->numPlanes ) {
tw->trace.fraction = 0.0f;
tw->trace.c.type = CONTACT_TRMVERTEX;
tw->trace.c.normal = b->planes[bestPlane].Normal();
tw->trace.c.dist = b->planes[bestPlane].Dist();
tw->trace.c.contents = b->contents;
tw->trace.c.material = b->material;
tw->trace.c.point = *p;
tw->trace.c.modelFeature = 0;
tw->trace.c.trmFeature = j;
return true;
}
}
return false;
}
/*
================
CM_SetTrmEdgeSidedness
================
*/
#define CM_SetTrmEdgeSidedness( edge, bpl, epl, bitNum ) { \
if ( !(edge->sideSet & (1<<bitNum)) ) { \
float fl; \
fl = (bpl).PermutedInnerProduct( epl ); \
edge->side = (edge->side & ~(1<<bitNum)) | (FLOATSIGNBITSET(fl) << bitNum); \
edge->sideSet |= (1 << bitNum); \
} \
}
/*
================
CM_SetTrmPolygonSidedness
================
*/
#define CM_SetTrmPolygonSidedness( v, plane, bitNum ) { \
if ( !((v)->sideSet & (1<<bitNum)) ) { \
float fl; \
fl = plane.Distance( (v)->p ); \
/* cannot use float sign bit because it is undetermined when fl == 0.0f */ \
if ( fl < 0.0f ) { \
(v)->side |= (1 << bitNum); \
} \
else { \
(v)->side &= ~(1 << bitNum); \
} \
(v)->sideSet |= (1 << bitNum); \
} \
}
/*
================
idCollisionModelManagerLocal::TestTrmInPolygon
returns true if the trm intersects the polygon
================
*/
bool idCollisionModelManagerLocal::TestTrmInPolygon( cm_traceWork_t *tw, cm_polygon_t *p ) {
int i, j, k, edgeNum, flip, trmEdgeNum, bitNum, bestPlane;
int sides[MAX_TRACEMODEL_VERTS];
float d, bestd;
cm_trmEdge_t *trmEdge;
cm_edge_t *edge;
cm_vertex_t *v, *v1, *v2;
// if already checked this polygon
if ( p->checkcount == idCollisionModelManagerLocal::checkCount ) {
return false;
}
p->checkcount = idCollisionModelManagerLocal::checkCount;
// if this polygon does not have the right contents behind it
if ( !(p->contents & tw->contents) ) {
return false;
}
// if the polygon bounds don't intersect the trace bounds
if ( !p->bounds.IntersectsBounds( tw->bounds ) ) {
return false;
}
// bounds should cross polygon plane
switch( tw->bounds.PlaneSide( p->plane ) ) {
case PLANESIDE_CROSS:
break;
case PLANESIDE_FRONT:
if ( tw->model->isConvex ) {
tw->quickExit = true;
return true;
}
default:
return false;
}
// if the trace model is convex
if ( tw->isConvex ) {
// test if any polygon vertices are inside the trm
for ( i = 0; i < p->numEdges; i++ ) {
edgeNum = p->edges[i];
edge = tw->model->edges + abs(edgeNum);
// if this edge is already tested
if ( edge->checkcount == idCollisionModelManagerLocal::checkCount ) {
continue;
}
for ( j = 0; j < 2; j++ ) {
v = &tw->model->vertices[edge->vertexNum[j]];
// if this vertex is already tested
if ( v->checkcount == idCollisionModelManagerLocal::checkCount ) {
continue;
}
bestPlane = 0;
bestd = -idMath::INFINITY;
for ( k = 0; k < tw->numPolys; k++ ) {
d = tw->polys[k].plane.Distance( v->p );
if ( d >= 0.0f ) {
break;
}
if ( d > bestd ) {
bestd = d;
bestPlane = k;
}
}
if ( k >= tw->numPolys ) {
tw->trace.fraction = 0.0f;
tw->trace.c.type = CONTACT_MODELVERTEX;
tw->trace.c.normal = -tw->polys[bestPlane].plane.Normal();
tw->trace.c.dist = -tw->polys[bestPlane].plane.Dist();
tw->trace.c.contents = p->contents;
tw->trace.c.material = p->material;
tw->trace.c.point = v->p;
tw->trace.c.modelFeature = edge->vertexNum[j];
tw->trace.c.trmFeature = 0;
return true;
}
}
}
}
for ( i = 0; i < p->numEdges; i++ ) {
edgeNum = p->edges[i];
edge = tw->model->edges + abs(edgeNum);
// reset sidedness cache if this is the first time we encounter this edge
if ( edge->checkcount != idCollisionModelManagerLocal::checkCount ) {
edge->sideSet = 0;
}
// pluecker coordinate for edge
tw->polygonEdgePlueckerCache[i].FromLine( tw->model->vertices[edge->vertexNum[0]].p,
tw->model->vertices[edge->vertexNum[1]].p );
v = &tw->model->vertices[edge->vertexNum[INTSIGNBITSET(edgeNum)]];
// reset sidedness cache if this is the first time we encounter this vertex
if ( v->checkcount != idCollisionModelManagerLocal::checkCount ) {
v->sideSet = 0;
}
v->checkcount = idCollisionModelManagerLocal::checkCount;
}
// get side of polygon for each trm vertex
for ( i = 0; i < tw->numVerts; i++ ) {
d = p->plane.Distance( tw->vertices[i].p );
sides[i] = d < 0.0f ? -1 : 1;
}
// test if any trm edges go through the polygon
for ( i = 1; i <= tw->numEdges; i++ ) {
// if the trm edge does not cross the polygon plane
if ( sides[tw->edges[i].vertexNum[0]] == sides[tw->edges[i].vertexNum[1]] ) {
continue;
}
// check from which side to which side the trm edge goes
flip = INTSIGNBITSET( sides[tw->edges[i].vertexNum[0]] );
// test if trm edge goes through the polygon between the polygon edges
for ( j = 0; j < p->numEdges; j++ ) {
edgeNum = p->edges[j];
edge = tw->model->edges + abs(edgeNum);
#if 1
CM_SetTrmEdgeSidedness( edge, tw->edges[i].pl, tw->polygonEdgePlueckerCache[j], i );
if ( INTSIGNBITSET(edgeNum) ^ ((edge->side >> i) & 1) ^ flip ) {
break;
}
#else
d = tw->edges[i].pl.PermutedInnerProduct( tw->polygonEdgePlueckerCache[j] );
if ( flip ) {
d = -d;
}
if ( edgeNum > 0 ) {
if ( d <= 0.0f ) {
break;
}
}
else {
if ( d >= 0.0f ) {
break;
}
}
#endif
}
if ( j >= p->numEdges ) {
tw->trace.fraction = 0.0f;
tw->trace.c.type = CONTACT_EDGE;
tw->trace.c.normal = p->plane.Normal();
tw->trace.c.dist = p->plane.Dist();
tw->trace.c.contents = p->contents;
tw->trace.c.material = p->material;
tw->trace.c.point = tw->vertices[tw->edges[i].vertexNum[ !flip ]].p;
tw->trace.c.modelFeature = *reinterpret_cast<int *>(&p);
tw->trace.c.trmFeature = i;
return true;
}
}
// test if any polygon edges go through the trm polygons
for ( i = 0; i < p->numEdges; i++ ) {
edgeNum = p->edges[i];
edge = tw->model->edges + abs(edgeNum);
if ( edge->checkcount == idCollisionModelManagerLocal::checkCount ) {
continue;
}
edge->checkcount = idCollisionModelManagerLocal::checkCount;
for ( j = 0; j < tw->numPolys; j++ ) {
#if 1
v1 = tw->model->vertices + edge->vertexNum[0];
CM_SetTrmPolygonSidedness( v1, tw->polys[j].plane, j );
v2 = tw->model->vertices + edge->vertexNum[1];
CM_SetTrmPolygonSidedness( v2, tw->polys[j].plane, j );
// if the polygon edge does not cross the trm polygon plane
if ( !(((v1->side ^ v2->side) >> j) & 1) ) {
continue;
}
flip = (v1->side >> j) & 1;
#else
float d1, d2;
v1 = tw->model->vertices + edge->vertexNum[0];
d1 = tw->polys[j].plane.Distance( v1->p );
v2 = tw->model->vertices + edge->vertexNum[1];
d2 = tw->polys[j].plane.Distance( v2->p );
// if the polygon edge does not cross the trm polygon plane
if ( (d1 >= 0.0f && d2 >= 0.0f) || (d1 <= 0.0f && d2 <= 0.0f) ) {
continue;
}
flip = false;
if ( d1 < 0.0f ) {
flip = true;
}
#endif
// test if polygon edge goes through the trm polygon between the trm polygon edges
for ( k = 0; k < tw->polys[j].numEdges; k++ ) {
trmEdgeNum = tw->polys[j].edges[k];
trmEdge = tw->edges + abs(trmEdgeNum);
#if 1
bitNum = abs(trmEdgeNum);
CM_SetTrmEdgeSidedness( edge, trmEdge->pl, tw->polygonEdgePlueckerCache[i], bitNum );
if ( INTSIGNBITSET(trmEdgeNum) ^ ((edge->side >> bitNum) & 1) ^ flip ) {
break;
}
#else
d = trmEdge->pl.PermutedInnerProduct( tw->polygonEdgePlueckerCache[i] );
if ( flip ) {
d = -d;
}
if ( trmEdgeNum > 0 ) {
if ( d <= 0.0f ) {
break;
}
}
else {
if ( d >= 0.0f ) {
break;
}
}
#endif
}
if ( k >= tw->polys[j].numEdges ) {
tw->trace.fraction = 0.0f;
tw->trace.c.type = CONTACT_EDGE;
tw->trace.c.normal = -tw->polys[j].plane.Normal();
tw->trace.c.dist = -tw->polys[j].plane.Dist();
tw->trace.c.contents = p->contents;
tw->trace.c.material = p->material;
tw->trace.c.point = tw->model->vertices[edge->vertexNum[ !flip ]].p;
tw->trace.c.modelFeature = edgeNum;
tw->trace.c.trmFeature = j;
return true;
}
}
}
return false;
}
/*
================
idCollisionModelManagerLocal::PointNode
================
*/
cm_node_t *idCollisionModelManagerLocal::PointNode( const idVec3 &p, cm_model_t *model ) {
cm_node_t *node;
node = model->node;
while ( node->planeType != -1 ) {
if (p[node->planeType] > node->planeDist) {
node = node->children[0];
}
else {
node = node->children[1];
}
assert( node != NULL );
}
return node;
}
/*
================
idCollisionModelManagerLocal::PointContents
================
*/
int idCollisionModelManagerLocal::PointContents( const idVec3 p, cmHandle_t model ) {
int i;
float d;
cm_node_t *node;
cm_brushRef_t *bref;
cm_brush_t *b;
idPlane *plane;
node = idCollisionModelManagerLocal::PointNode( p, idCollisionModelManagerLocal::models[model] );
for ( bref = node->brushes; bref; bref = bref->next ) {
b = bref->b;
// test if the point is within the brush bounds
for ( i = 0; i < 3; i++ ) {
if ( p[i] < b->bounds[0][i] ) {
break;
}
if ( p[i] > b->bounds[1][i] ) {
break;
}
}
if ( i < 3 ) {
continue;
}
// test if the point is inside the brush
plane = b->planes;
for ( i = 0; i < b->numPlanes; i++, plane++ ) {
d = plane->Distance( p );
if ( d >= 0 ) {
break;
}
}
if ( i >= b->numPlanes ) {
return b->contents;
}
}
return 0;
}
/*
==================
idCollisionModelManagerLocal::TransformedPointContents
==================
*/
int idCollisionModelManagerLocal::TransformedPointContents( const idVec3 &p, cmHandle_t model, const idVec3 &origin, const idMat3 &modelAxis ) {
idVec3 p_l;
// subtract origin offset
p_l = p - origin;
if ( modelAxis.IsRotated() ) {
p_l *= modelAxis;
}
return idCollisionModelManagerLocal::PointContents( p_l, model );
}
/*
==================
idCollisionModelManagerLocal::ContentsTrm
==================
*/
int idCollisionModelManagerLocal::ContentsTrm( trace_t *results, const idVec3 &start,
const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis ) {
int i;
bool model_rotated, trm_rotated;
idMat3 invModelAxis, tmpAxis;
idVec3 dir;
ALIGN16( cm_traceWork_t tw; )
// fast point case
if ( !trm || ( trm->bounds[1][0] - trm->bounds[0][0] <= 0.0f &&
trm->bounds[1][1] - trm->bounds[0][1] <= 0.0f &&
trm->bounds[1][2] - trm->bounds[0][2] <= 0.0f ) ) {
results->c.contents = idCollisionModelManagerLocal::TransformedPointContents( start, model, modelOrigin, modelAxis );
results->fraction = ( results->c.contents == 0 );
results->endpos = start;
results->endAxis = trmAxis;
return results->c.contents;
}
idCollisionModelManagerLocal::checkCount++;
tw.trace.fraction = 1.0f;
tw.trace.c.contents = 0;
tw.trace.c.type = CONTACT_NONE;
tw.contents = contentMask;
tw.isConvex = true;
tw.rotation = false;
tw.positionTest = true;
tw.pointTrace = false;
tw.quickExit = false;
tw.numContacts = 0;
tw.model = idCollisionModelManagerLocal::models[model];
tw.start = start - modelOrigin;
tw.end = tw.start;
model_rotated = modelAxis.IsRotated();
if ( model_rotated ) {
invModelAxis = modelAxis.Transpose();
}
// setup trm structure
idCollisionModelManagerLocal::SetupTrm( &tw, trm );
trm_rotated = trmAxis.IsRotated();
// calculate vertex positions
if ( trm_rotated ) {
for ( i = 0; i < tw.numVerts; i++ ) {
// rotate trm around the start position
tw.vertices[i].p *= trmAxis;
}
}
for ( i = 0; i < tw.numVerts; i++ ) {
// set trm at start position
tw.vertices[i].p += tw.start;
}
if ( model_rotated ) {
for ( i = 0; i < tw.numVerts; i++ ) {
// rotate trm around model instead of rotating the model
tw.vertices[i].p *= invModelAxis;
}
}
// add offset to start point
if ( trm_rotated ) {
dir = trm->offset * trmAxis;
tw.start += dir;
tw.end += dir;
} else {
tw.start += trm->offset;
tw.end += trm->offset;
}
if ( model_rotated ) {
// rotate trace instead of model
tw.start *= invModelAxis;
tw.end *= invModelAxis;
}
// setup trm vertices
tw.size.Clear();
for ( i = 0; i < tw.numVerts; i++ ) {
// get axial trm size after rotations
tw.size.AddPoint( tw.vertices[i].p - tw.start );
}
// setup trm edges
for ( i = 1; i <= tw.numEdges; i++ ) {
// edge start, end and pluecker coordinate
tw.edges[i].start = tw.vertices[tw.edges[i].vertexNum[0]].p;
tw.edges[i].end = tw.vertices[tw.edges[i].vertexNum[1]].p;
tw.edges[i].pl.FromLine( tw.edges[i].start, tw.edges[i].end );
}
// setup trm polygons
if ( trm_rotated & model_rotated ) {
tmpAxis = trmAxis * invModelAxis;
for ( i = 0; i < tw.numPolys; i++ ) {
tw.polys[i].plane *= tmpAxis;
}
} else if ( trm_rotated ) {
for ( i = 0; i < tw.numPolys; i++ ) {
tw.polys[i].plane *= trmAxis;
}
} else if ( model_rotated ) {
for ( i = 0; i < tw.numPolys; i++ ) {
tw.polys[i].plane *= invModelAxis;
}
}
for ( i = 0; i < tw.numPolys; i++ ) {
tw.polys[i].plane.FitThroughPoint( tw.edges[abs(tw.polys[i].edges[0])].start );
}
// bounds for full trace, a little bit larger for epsilons
for ( i = 0; i < 3; i++ ) {
if ( tw.start[i] < tw.end[i] ) {
tw.bounds[0][i] = tw.start[i] + tw.size[0][i] - CM_BOX_EPSILON;
tw.bounds[1][i] = tw.end[i] + tw.size[1][i] + CM_BOX_EPSILON;
} else {
tw.bounds[0][i] = tw.end[i] + tw.size[0][i] - CM_BOX_EPSILON;
tw.bounds[1][i] = tw.start[i] + tw.size[1][i] + CM_BOX_EPSILON;
}
if ( idMath::Fabs(tw.size[0][i]) > idMath::Fabs(tw.size[1][i]) ) {
tw.extents[i] = idMath::Fabs( tw.size[0][i] ) + CM_BOX_EPSILON;
} else {
tw.extents[i] = idMath::Fabs( tw.size[1][i] ) + CM_BOX_EPSILON;
}
}
// trace through the model
idCollisionModelManagerLocal::TraceThroughModel( &tw );
*results = tw.trace;
results->fraction = ( results->c.contents == 0 );
results->endpos = start;
results->endAxis = trmAxis;
return results->c.contents;
}
/*
==================
idCollisionModelManagerLocal::Contents
==================
*/
int idCollisionModelManagerLocal::Contents( const idVec3 &start,
const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis ) {
trace_t results;
if ( model < 0 || model > idCollisionModelManagerLocal::maxModels || model > MAX_SUBMODELS ) {
common->Printf("idCollisionModelManagerLocal::Contents: invalid model handle\n");
return 0;
}
if ( !idCollisionModelManagerLocal::models || !idCollisionModelManagerLocal::models[model] ) {
common->Printf("idCollisionModelManagerLocal::Contents: invalid model\n");
return 0;
}
return ContentsTrm( &results, start, trm, trmAxis, contentMask, model, modelOrigin, modelAxis );
}

View file

@ -1,498 +0,0 @@
/*
===============================================================================
Trace model vs. polygonal model collision detection.
===============================================================================
*/
#include "../idlib/precompiled.h"
#pragma hdrstop
#include "CollisionModel_local.h"
/*
===============================================================================
Visualisation code
===============================================================================
*/
const char *cm_contentsNameByIndex[] = {
// HUMANHEAD: Redid these as they were out of sync
"none", //
"solid", // bit 0
"opaque", // 1
"water", // 2
"playerclip", // 3
"monsterclip", // 4
"moveableclip", // 5
"ikclip", // 6
"blood", // 7
"body", // 8
"projectile", // 9
"corpse", // 10
"rendermodel", // 11
"trigger", // 12
"aas_solid", // 13
"aas_obstacle", // 14
"flashlight_trigger", // 15
// HUMANHEAD pdm: added our contents
"forcefield", // 16
"spiritbridge", // 17
"areaportal", // 18
"nocsg", // 19
"block_radiusdamage", // 20
"shootable", // 21
"deathvolume", // 22
"vehicleclip", // 23
"owner_to_owner", // 24
"game_portal", // 25
"shootablebyarrow", // 26
"hunterclip", // 27
// END HUMANHEAD
NULL
};
int cm_contentsFlagByIndex[] = {
// HUMANHEAD: Redid these as they were out of sync
-1, // -1
CONTENTS_SOLID, // bit 0
CONTENTS_OPAQUE, // 1
CONTENTS_WATER, // 2
CONTENTS_PLAYERCLIP, // 3
CONTENTS_MONSTERCLIP, // 4
CONTENTS_MOVEABLECLIP, // 5
CONTENTS_IKCLIP, // 6
CONTENTS_BLOOD, // 7
CONTENTS_BODY, // 8
CONTENTS_PROJECTILE, // 9
CONTENTS_CORPSE, // 10
CONTENTS_RENDERMODEL, // 11
CONTENTS_TRIGGER, // 12
CONTENTS_AAS_SOLID, // 13
CONTENTS_AAS_OBSTACLE, // 14
CONTENTS_FLASHLIGHT_TRIGGER, // 15
// HUMANHEAD pdm: added our contents
CONTENTS_FORCEFIELD, // 16
CONTENTS_SPIRITBRIDGE, // 17
CONTENTS_AREAPORTAL, // 18
CONTENTS_NOCSG, // 19
CONTENTS_BLOCK_RADIUSDAMAGE, // 20
CONTENTS_SHOOTABLE, // 21
CONTENTS_DEATHVOLUME, // 22
CONTENTS_VEHICLECLIP, // 23
CONTENTS_OWNER_TO_OWNER, // 24
CONTENTS_GAME_PORTAL, // 25
CONTENTS_SHOOTABLEBYARROW, // 26
CONTENTS_HUNTERCLIP, // 27
// END HUMANHEAD
0
};
idCVar cm_drawMask( "cm_drawMask", "none", CVAR_GAME, "collision mask", cm_contentsNameByIndex, idCmdSystem::ArgCompletion_String<cm_contentsNameByIndex> );
idCVar cm_drawColor( "cm_drawColor", "1 0 0 .5", CVAR_GAME, "color used to draw the collision models" );
idCVar cm_drawFilled( "cm_drawFilled", "0", CVAR_GAME | CVAR_BOOL, "draw filled polygons" );
idCVar cm_drawInternal( "cm_drawInternal", "1", CVAR_GAME | CVAR_BOOL, "draw internal edges green" );
idCVar cm_drawNormals( "cm_drawNormals", "0", CVAR_GAME | CVAR_BOOL, "draw polygon and edge normals" );
idCVar cm_backFaceCull( "cm_backFaceCull", "0", CVAR_GAME | CVAR_BOOL, "cull back facing polygons" );
idCVar cm_debugCollision( "cm_debugCollision", "0", CVAR_GAME | CVAR_BOOL, "debug the collision detection" );
static idVec4 cm_color;
/*
================
idCollisionModelManagerLocal::ContentsFromString
================
*/
int idCollisionModelManagerLocal::ContentsFromString( const char *string ) const {
int i, contents = 0;
idLexer src( string, idStr::Length( string ), "ContentsFromString" );
idToken token;
while( src.ReadToken( &token ) ) {
if ( token == "," ) {
continue;
}
for ( i = 1; cm_contentsNameByIndex[i] != NULL; i++ ) {
if ( token.Icmp( cm_contentsNameByIndex[i] ) == 0 ) {
contents |= cm_contentsFlagByIndex[i];
break;
}
}
}
return contents;
}
/*
================
idCollisionModelManagerLocal::StringFromContents
================
*/
const char *idCollisionModelManagerLocal::StringFromContents( const int contents ) const {
int i, length = 0;
static char contentsString[MAX_STRING_CHARS];
contentsString[0] = '\0';
for ( i = 1; cm_contentsFlagByIndex[i] != 0; i++ ) {
if ( contents & cm_contentsFlagByIndex[i] ) {
if ( length != 0 ) {
length += idStr::snPrintf( contentsString + length, sizeof( contentsString ) - length, "," );
}
length += idStr::snPrintf( contentsString + length, sizeof( contentsString ) - length, cm_contentsNameByIndex[i] );
}
}
return contentsString;
}
/*
================
idCollisionModelManagerLocal::DrawEdge
================
*/
void idCollisionModelManagerLocal::DrawEdge( cm_model_t *model, int edgeNum, const idVec3 &origin, const idMat3 &axis ) {
int side;
cm_edge_t *edge;
idVec3 start, end, mid;
bool isRotated;
isRotated = axis.IsRotated();
edge = model->edges + abs(edgeNum);
side = edgeNum < 0;
start = model->vertices[edge->vertexNum[side]].p;
end = model->vertices[edge->vertexNum[!side]].p;
if ( isRotated ) {
start *= axis;
end *= axis;
}
start += origin;
end += origin;
if ( edge->internal ) {
if ( cm_drawInternal.GetBool() ) {
session->rw->DebugArrow( colorGreen, start, end, 1 );
}
} else {
if ( edge->numUsers > 2 ) {
session->rw->DebugArrow( colorBlue, start, end, 1 );
} else {
session->rw->DebugArrow( cm_color, start, end, 1 );
}
}
if ( cm_drawNormals.GetBool() ) {
mid = (start + end) * 0.5f;
if ( isRotated ) {
end = mid + 5 * (axis * edge->normal);
} else {
end = mid + 5 * edge->normal;
}
session->rw->DebugArrow( colorCyan, mid, end, 1 );
}
}
/*
================
idCollisionModelManagerLocal::DrawPolygon
================
*/
void idCollisionModelManagerLocal::DrawPolygon( cm_model_t *model, cm_polygon_t *p, const idVec3 &origin, const idMat3 &axis, const idVec3 &viewOrigin ) {
int i, edgeNum;
cm_edge_t *edge;
idVec3 center, end, dir;
if ( cm_backFaceCull.GetBool() ) {
edgeNum = p->edges[0];
edge = model->edges + abs(edgeNum);
dir = model->vertices[edge->vertexNum[0]].p - viewOrigin;
if ( dir * p->plane.Normal() > 0.0f ) {
return;
}
}
if ( cm_drawNormals.GetBool() ) {
center = vec3_origin;
for ( i = 0; i < p->numEdges; i++ ) {
edgeNum = p->edges[i];
edge = model->edges + abs(edgeNum);
center += model->vertices[edge->vertexNum[edgeNum < 0]].p;
}
center *= (1.0f / p->numEdges);
if ( axis.IsRotated() ) {
center = center * axis + origin;
end = center + 5 * (axis * p->plane.Normal());
} else {
center += origin;
end = center + 5 * p->plane.Normal();
}
session->rw->DebugArrow( colorMagenta, center, end, 1 );
}
if ( cm_drawFilled.GetBool() ) {
idFixedWinding winding;
for ( i = p->numEdges - 1; i >= 0; i-- ) {
edgeNum = p->edges[i];
edge = model->edges + abs(edgeNum);
winding += origin + model->vertices[edge->vertexNum[INTSIGNBITSET(edgeNum)]].p * axis;
}
session->rw->DebugPolygon( cm_color, winding );
} else {
for ( i = 0; i < p->numEdges; i++ ) {
edgeNum = p->edges[i];
edge = model->edges + abs(edgeNum);
if ( edge->checkcount == checkCount ) {
continue;
}
edge->checkcount = checkCount;
DrawEdge( model, edgeNum, origin, axis );
}
}
}
/*
================
idCollisionModelManagerLocal::DrawNodePolygons
================
*/
void idCollisionModelManagerLocal::DrawNodePolygons( cm_model_t *model, cm_node_t *node,
const idVec3 &origin, const idMat3 &axis,
const idVec3 &viewOrigin, const float radius ) {
int i;
cm_polygon_t *p;
cm_polygonRef_t *pref;
while (1) {
for ( pref = node->polygons; pref; pref = pref->next ) {
p = pref->p;
if ( radius ) {
// polygon bounds should overlap with trace bounds
for ( i = 0; i < 3; i++ ) {
if ( p->bounds[0][i] > viewOrigin[i] + radius ) {
break;
}
if ( p->bounds[1][i] < viewOrigin[i] - radius ) {
break;
}
}
if ( i < 3 ) {
continue;
}
}
if ( p->checkcount == checkCount ) {
continue;
}
if ( !( p->contents & cm_contentsFlagByIndex[cm_drawMask.GetInteger()] ) ) {
continue;
}
DrawPolygon( model, p, origin, axis, viewOrigin );
p->checkcount = checkCount;
}
if ( node->planeType == -1 ) {
break;
}
if ( radius && viewOrigin[node->planeType] > node->planeDist + radius ) {
node = node->children[0];
} else if ( radius && viewOrigin[node->planeType] < node->planeDist - radius ) {
node = node->children[1];
} else {
DrawNodePolygons( model, node->children[1], origin, axis, viewOrigin, radius );
node = node->children[0];
}
}
}
/*
================
idCollisionModelManagerLocal::DrawModel
================
*/
void idCollisionModelManagerLocal::DrawModel( cmHandle_t handle, const idVec3 &modelOrigin, const idMat3 &modelAxis,
const idVec3 &viewOrigin, const float radius ) {
cm_model_t *model;
idVec3 viewPos;
if ( handle < 0 && handle >= numModels ) {
return;
}
if ( cm_drawColor.IsModified() ) {
sscanf( cm_drawColor.GetString(), "%f %f %f %f", &cm_color.x, &cm_color.y, &cm_color.z, &cm_color.w );
cm_drawColor.ClearModified();
}
model = models[ handle ];
viewPos = (viewOrigin - modelOrigin) * modelAxis.Transpose();
checkCount++;
DrawNodePolygons( model, model->node, modelOrigin, modelAxis, viewPos, radius );
}
/*
===============================================================================
Speed test code
===============================================================================
*/
static idCVar cm_testCollision( "cm_testCollision", "0", CVAR_GAME | CVAR_BOOL, "" );
static idCVar cm_testRotation( "cm_testRotation", "1", CVAR_GAME | CVAR_BOOL, "" );
static idCVar cm_testModel( "cm_testModel", "0", CVAR_GAME | CVAR_INTEGER, "" );
static idCVar cm_testTimes( "cm_testTimes", "1000", CVAR_GAME | CVAR_INTEGER, "" );
static idCVar cm_testRandomMany( "cm_testRandomMany", "0", CVAR_GAME | CVAR_BOOL, "" );
static idCVar cm_testOrigin( "cm_testOrigin", "0 0 0", CVAR_GAME, "" );
static idCVar cm_testReset( "cm_testReset", "0", CVAR_GAME | CVAR_BOOL, "" );
static idCVar cm_testBox( "cm_testBox", "-16 -16 0 16 16 64", CVAR_GAME, "" );
static idCVar cm_testBoxRotation( "cm_testBoxRotation", "0 0 0", CVAR_GAME, "" );
static idCVar cm_testWalk( "cm_testWalk", "1", CVAR_GAME | CVAR_BOOL, "" );
static idCVar cm_testLength( "cm_testLength", "1024", CVAR_GAME | CVAR_FLOAT, "" );
static idCVar cm_testRadius( "cm_testRadius", "64", CVAR_GAME | CVAR_FLOAT, "" );
static idCVar cm_testAngle( "cm_testAngle", "60", CVAR_GAME | CVAR_FLOAT, "" );
static int total_translation;
static int min_translation = 999999;
static int max_translation = -999999;
static int num_translation = 0;
static int total_rotation;
static int min_rotation = 999999;
static int max_rotation = -999999;
static int num_rotation = 0;
static idVec3 start;
static idVec3 *testend;
#include "../sys/sys_public.h"
void idCollisionModelManagerLocal::DebugOutput( const idVec3 &origin ) {
int i, k, t;
char buf[128];
idVec3 end;
idAngles boxAngles;
idMat3 modelAxis, boxAxis;
idBounds bounds;
trace_t trace;
if ( !cm_testCollision.GetBool() ) {
return;
}
testend = (idVec3 *) Mem_Alloc( cm_testTimes.GetInteger() * sizeof(idVec3) );
if ( cm_testReset.GetBool() || ( cm_testWalk.GetBool() && !start.Compare( start ) ) ) {
total_translation = total_rotation = 0;
min_translation = min_rotation = 999999;
max_translation = max_rotation = -999999;
num_translation = num_rotation = 0;
cm_testReset.SetBool( false );
}
if ( cm_testWalk.GetBool() ) {
start = origin;
cm_testOrigin.SetString( va( "%1.2f %1.2f %1.2f", start[0], start[1], start[2] ) );
} else {
sscanf( cm_testOrigin.GetString(), "%f %f %f", &start[0], &start[1], &start[2] );
}
sscanf( cm_testBox.GetString(), "%f %f %f %f %f %f", &bounds[0][0], &bounds[0][1], &bounds[0][2],
&bounds[1][0], &bounds[1][1], &bounds[1][2] );
sscanf( cm_testBoxRotation.GetString(), "%f %f %f", &boxAngles[0], &boxAngles[1], &boxAngles[2] );
boxAxis = boxAngles.ToMat3();
modelAxis.Identity();
idTraceModel itm( bounds );
idRandom random( 0 );
idTimer timer;
if ( cm_testRandomMany.GetBool() ) {
// if many traces in one random direction
for ( i = 0; i < 3; i++ ) {
testend[0][i] = start[i] + random.CRandomFloat() * cm_testLength.GetFloat();
}
for ( k = 1; k < cm_testTimes.GetInteger(); k++ ) {
testend[k] = testend[0];
}
} else {
// many traces each in a different random direction
for ( k = 0; k < cm_testTimes.GetInteger(); k++ ) {
for ( i = 0; i < 3; i++ ) {
testend[k][i] = start[i] + random.CRandomFloat() * cm_testLength.GetFloat();
}
}
}
// translational collision detection
timer.Clear();
timer.Start();
for ( i = 0; i < cm_testTimes.GetInteger(); i++ ) {
Translation( &trace, start, testend[i], &itm, boxAxis, CONTENTS_SOLID|CONTENTS_PLAYERCLIP, cm_testModel.GetInteger(), vec3_origin, modelAxis );
}
timer.Stop();
t = timer.Milliseconds();
if ( t < min_translation ) min_translation = t;
if ( t > max_translation ) max_translation = t;
num_translation++;
total_translation += t;
if ( cm_testTimes.GetInteger() > 9999 ) {
sprintf( buf, "%3dK", (int ) ( cm_testTimes.GetInteger() / 1000 ) );
} else {
sprintf( buf, "%4d", cm_testTimes.GetInteger() );
}
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 );
if ( cm_testRandomMany.GetBool() ) {
// if many traces in one random direction
for ( i = 0; i < 3; i++ ) {
testend[0][i] = start[i] + random.CRandomFloat() * cm_testRadius.GetFloat();
}
for ( k = 1; k < cm_testTimes.GetInteger(); k++ ) {
testend[k] = testend[0];
}
} else {
// many traces each in a different random direction
for ( k = 0; k < cm_testTimes.GetInteger(); k++ ) {
for ( i = 0; i < 3; i++ ) {
testend[k][i] = start[i] + random.CRandomFloat() * cm_testRadius.GetFloat();
}
}
}
if ( cm_testRotation.GetBool() ) {
// rotational collision detection
idVec3 vec( random.CRandomFloat(), random.CRandomFloat(), random.RandomFloat() );
vec.Normalize();
idRotation rotation( vec3_origin, vec, cm_testAngle.GetFloat() );
timer.Clear();
timer.Start();
for ( i = 0; i < cm_testTimes.GetInteger(); i++ ) {
rotation.SetOrigin( testend[i] );
Rotation( &trace, start, rotation, &itm, boxAxis, CONTENTS_SOLID|CONTENTS_PLAYERCLIP, cm_testModel.GetInteger(), vec3_origin, modelAxis );
}
timer.Stop();
t = timer.Milliseconds();
if ( t < min_rotation ) min_rotation = t;
if ( t > max_rotation ) max_rotation = t;
num_rotation++;
total_rotation += t;
if ( cm_testTimes.GetInteger() > 9999 ) {
sprintf( buf, "%3dK", (int ) ( cm_testTimes.GetInteger() / 1000 ) );
} else {
sprintf( buf, "%4d", cm_testTimes.GetInteger() );
}
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 );
}
Mem_Free( testend );
testend = NULL;
}

View file

@ -1,598 +0,0 @@
/*
===============================================================================
Trace model vs. polygonal model collision detection.
===============================================================================
*/
#include "../idlib/precompiled.h"
#pragma hdrstop
#include "CollisionModel_local.h"
#define CM_FILE_EXT "cm"
#define CM_FILEID "CM"
#define CM_FILEVERSION "1.00"
/*
===============================================================================
Writing of collision model file
===============================================================================
*/
void CM_GetNodeBounds( idBounds *bounds, cm_node_t *node );
int CM_GetNodeContents( cm_node_t *node );
/*
================
idCollisionModelManagerLocal::WriteNodes
================
*/
void idCollisionModelManagerLocal::WriteNodes( idFile *fp, cm_node_t *node ) {
fp->WriteFloatString( "\t( %d %f )\n", node->planeType, node->planeDist );
if ( node->planeType != -1 ) {
WriteNodes( fp, node->children[0] );
WriteNodes( fp, node->children[1] );
}
}
/*
================
idCollisionModelManagerLocal::CountPolygonMemory
================
*/
int idCollisionModelManagerLocal::CountPolygonMemory( cm_node_t *node ) const {
cm_polygonRef_t *pref;
cm_polygon_t *p;
int memory;
memory = 0;
for ( pref = node->polygons; pref; pref = pref->next ) {
p = pref->p;
if ( p->checkcount == checkCount ) {
continue;
}
p->checkcount = checkCount;
memory += sizeof( cm_polygon_t ) + ( p->numEdges - 1 ) * sizeof( p->edges[0] );
}
if ( node->planeType != -1 ) {
memory += CountPolygonMemory( node->children[0] );
memory += CountPolygonMemory( node->children[1] );
}
return memory;
}
/*
================
idCollisionModelManagerLocal::WritePolygons
================
*/
void idCollisionModelManagerLocal::WritePolygons( idFile *fp, cm_node_t *node ) {
cm_polygonRef_t *pref;
cm_polygon_t *p;
int i;
for ( pref = node->polygons; pref; pref = pref->next ) {
p = pref->p;
if ( p->checkcount == checkCount ) {
continue;
}
p->checkcount = checkCount;
fp->WriteFloatString( "\t%d (", p->numEdges );
for ( i = 0; i < p->numEdges; i++ ) {
fp->WriteFloatString( " %d", p->edges[i] );
}
fp->WriteFloatString( " ) ( %f %f %f ) %f", p->plane.Normal()[0], p->plane.Normal()[1], p->plane.Normal()[2], p->plane.Dist() );
fp->WriteFloatString( " ( %f %f %f )", p->bounds[0][0], p->bounds[0][1], p->bounds[0][2] );
fp->WriteFloatString( " ( %f %f %f )", p->bounds[1][0], p->bounds[1][1], p->bounds[1][2] );
fp->WriteFloatString( " \"%s\"\n", p->material->GetName() );
}
if ( node->planeType != -1 ) {
WritePolygons( fp, node->children[0] );
WritePolygons( fp, node->children[1] );
}
}
/*
================
idCollisionModelManagerLocal::CountBrushMemory
================
*/
int idCollisionModelManagerLocal::CountBrushMemory( cm_node_t *node ) const {
cm_brushRef_t *bref;
cm_brush_t *b;
int memory;
memory = 0;
for ( bref = node->brushes; bref; bref = bref->next ) {
b = bref->b;
if ( b->checkcount == checkCount ) {
continue;
}
b->checkcount = checkCount;
memory += sizeof( cm_brush_t ) + ( b->numPlanes - 1 ) * sizeof( b->planes[0] );
}
if ( node->planeType != -1 ) {
memory += CountBrushMemory( node->children[0] );
memory += CountBrushMemory( node->children[1] );
}
return memory;
}
/*
================
idCollisionModelManagerLocal::WriteBrushes
================
*/
void idCollisionModelManagerLocal::WriteBrushes( idFile *fp, cm_node_t *node ) {
cm_brushRef_t *bref;
cm_brush_t *b;
int i;
for ( bref = node->brushes; bref; bref = bref->next ) {
b = bref->b;
if ( b->checkcount == checkCount ) {
continue;
}
b->checkcount = checkCount;
fp->WriteFloatString( "\t%d {\n", b->numPlanes );
for ( i = 0; i < b->numPlanes; i++ ) {
fp->WriteFloatString( "\t\t( %f %f %f ) %f\n", b->planes[i].Normal()[0], b->planes[i].Normal()[1], b->planes[i].Normal()[2], b->planes[i].Dist() );
}
fp->WriteFloatString( "\t} ( %f %f %f )", b->bounds[0][0], b->bounds[0][1], b->bounds[0][2] );
fp->WriteFloatString( " ( %f %f %f ) \"%s\"\n", b->bounds[1][0], b->bounds[1][1], b->bounds[1][2], StringFromContents( b->contents ) );
}
if ( node->planeType != -1 ) {
WriteBrushes( fp, node->children[0] );
WriteBrushes( fp, node->children[1] );
}
}
/*
================
idCollisionModelManagerLocal::WriteCollisionModel
================
*/
void idCollisionModelManagerLocal::WriteCollisionModel( idFile *fp, cm_model_t *model ) {
int i, polygonMemory, brushMemory;
fp->WriteFloatString( "collisionModel \"%s\" {\n", model->name.c_str() );
// vertices
fp->WriteFloatString( "\tvertices { /* numVertices = */ %d\n", model->numVertices );
for ( i = 0; i < model->numVertices; i++ ) {
fp->WriteFloatString( "\t/* %d */ ( %f %f %f )\n", i, model->vertices[i].p[0], model->vertices[i].p[1], model->vertices[i].p[2] );
}
fp->WriteFloatString( "\t}\n" );
// edges
fp->WriteFloatString( "\tedges { /* numEdges = */ %d\n", model->numEdges );
for ( i = 0; i < model->numEdges; i++ ) {
fp->WriteFloatString( "\t/* %d */ ( %d %d ) %d %d\n", i, model->edges[i].vertexNum[0], model->edges[i].vertexNum[1], model->edges[i].internal, model->edges[i].numUsers );
}
fp->WriteFloatString( "\t}\n" );
// nodes
fp->WriteFloatString( "\tnodes {\n" );
WriteNodes( fp, model->node );
fp->WriteFloatString( "\t}\n" );
// polygons
checkCount++;
polygonMemory = CountPolygonMemory( model->node );
fp->WriteFloatString( "\tpolygons /* polygonMemory = */ %d {\n", polygonMemory );
checkCount++;
WritePolygons( fp, model->node );
fp->WriteFloatString( "\t}\n" );
// brushes
checkCount++;
brushMemory = CountBrushMemory( model->node );
fp->WriteFloatString( "\tbrushes /* brushMemory = */ %d {\n", brushMemory );
checkCount++;
WriteBrushes( fp, model->node );
fp->WriteFloatString( "\t}\n" );
// closing brace
fp->WriteFloatString( "}\n" );
}
/*
================
idCollisionModelManagerLocal::WriteCollisionModelsToFile
================
*/
void idCollisionModelManagerLocal::WriteCollisionModelsToFile( const char *filename, int firstModel, int lastModel, unsigned int mapFileCRC ) {
int i;
idFile *fp;
idStr name;
name = filename;
name.SetFileExtension( CM_FILE_EXT );
common->Printf( "writing %s\n", name.c_str() );
// _D3XP was saving to fs_cdpath
fp = fileSystem->OpenFileWrite( name, "fs_devpath" );
if ( !fp ) {
common->Warning( "idCollisionModelManagerLocal::WriteCollisionModelsToFile: Error opening file %s\n", name.c_str() );
return;
}
// write file id and version
fp->WriteFloatString( "%s \"%s\"\n\n", CM_FILEID, CM_FILEVERSION );
// write the map file crc
fp->WriteFloatString( "%u\n\n", mapFileCRC );
// write the collision models
for ( i = firstModel; i < lastModel; i++ ) {
WriteCollisionModel( fp, models[ i ] );
}
fileSystem->CloseFile( fp );
}
/*
================
idCollisionModelManagerLocal::WriteCollisionModelForMapEntity
================
*/
bool idCollisionModelManagerLocal::WriteCollisionModelForMapEntity( const idMapEntity *mapEnt, const char *filename, const bool testTraceModel ) {
idFile *fp;
idStr name;
cm_model_t *model;
SetupHash();
model = CollisionModelForMapEntity( mapEnt );
model->name = filename;
name = filename;
name.SetFileExtension( CM_FILE_EXT );
common->Printf( "writing %s\n", name.c_str() );
fp = fileSystem->OpenFileWrite( name, "fs_devpath" );
if ( !fp ) {
common->Printf( "idCollisionModelManagerLocal::WriteCollisionModelForMapEntity: Error opening file %s\n", name.c_str() );
FreeModel( model );
return false;
}
// write file id and version
fp->WriteFloatString( "%s \"%s\"\n\n", CM_FILEID, CM_FILEVERSION );
// write the map file crc
fp->WriteFloatString( "%u\n\n", 0 );
// write the collision model
WriteCollisionModel( fp, model );
fileSystem->CloseFile( fp );
if ( testTraceModel ) {
idTraceModel trm;
TrmFromModel( model, trm );
}
FreeModel( model );
return true;
}
/*
===============================================================================
Loading of collision model file
===============================================================================
*/
/*
================
idCollisionModelManagerLocal::ParseVertices
================
*/
void idCollisionModelManagerLocal::ParseVertices( idLexer *src, cm_model_t *model ) {
int i;
src->ExpectTokenString( "{" );
model->numVertices = src->ParseInt();
model->maxVertices = model->numVertices;
model->vertices = (cm_vertex_t *) Mem_Alloc( model->maxVertices * sizeof( cm_vertex_t ) );
for ( i = 0; i < model->numVertices; i++ ) {
src->Parse1DMatrix( 3, model->vertices[i].p.ToFloatPtr() );
model->vertices[i].side = 0;
model->vertices[i].sideSet = 0;
model->vertices[i].checkcount = 0;
}
src->ExpectTokenString( "}" );
}
/*
================
idCollisionModelManagerLocal::ParseEdges
================
*/
void idCollisionModelManagerLocal::ParseEdges( idLexer *src, cm_model_t *model ) {
int i;
src->ExpectTokenString( "{" );
model->numEdges = src->ParseInt();
model->maxEdges = model->numEdges;
model->edges = (cm_edge_t *) Mem_Alloc( model->maxEdges * sizeof( cm_edge_t ) );
for ( i = 0; i < model->numEdges; i++ ) {
src->ExpectTokenString( "(" );
model->edges[i].vertexNum[0] = src->ParseInt();
model->edges[i].vertexNum[1] = src->ParseInt();
src->ExpectTokenString( ")" );
model->edges[i].side = 0;
model->edges[i].sideSet = 0;
model->edges[i].internal = src->ParseInt();
model->edges[i].numUsers = src->ParseInt();
model->edges[i].normal = vec3_origin;
model->edges[i].checkcount = 0;
model->numInternalEdges += model->edges[i].internal;
}
src->ExpectTokenString( "}" );
}
/*
================
idCollisionModelManagerLocal::ParseNodes
================
*/
cm_node_t *idCollisionModelManagerLocal::ParseNodes( idLexer *src, cm_model_t *model, cm_node_t *parent ) {
cm_node_t *node;
model->numNodes++;
node = AllocNode( model, model->numNodes < NODE_BLOCK_SIZE_SMALL ? NODE_BLOCK_SIZE_SMALL : NODE_BLOCK_SIZE_LARGE );
node->brushes = NULL;
node->polygons = NULL;
node->parent = parent;
src->ExpectTokenString( "(" );
node->planeType = src->ParseInt();
node->planeDist = src->ParseFloat();
src->ExpectTokenString( ")" );
if ( node->planeType != -1 ) {
node->children[0] = ParseNodes( src, model, node );
node->children[1] = ParseNodes( src, model, node );
}
return node;
}
/*
================
idCollisionModelManagerLocal::ParsePolygons
================
*/
void idCollisionModelManagerLocal::ParsePolygons( idLexer *src, cm_model_t *model ) {
cm_polygon_t *p;
int i, numEdges;
idVec3 normal;
idToken token;
if ( src->CheckTokenType( TT_NUMBER, 0, &token ) ) {
model->polygonBlock = (cm_polygonBlock_t *) Mem_Alloc( sizeof( cm_polygonBlock_t ) + token.GetIntValue() );
model->polygonBlock->bytesRemaining = token.GetIntValue();
model->polygonBlock->next = ( (byte *) model->polygonBlock ) + sizeof( cm_polygonBlock_t );
}
src->ExpectTokenString( "{" );
while ( !src->CheckTokenString( "}" ) ) {
// parse polygon
numEdges = src->ParseInt();
p = AllocPolygon( model, numEdges );
p->numEdges = numEdges;
src->ExpectTokenString( "(" );
for ( i = 0; i < p->numEdges; i++ ) {
p->edges[i] = src->ParseInt();
}
src->ExpectTokenString( ")" );
src->Parse1DMatrix( 3, normal.ToFloatPtr() );
p->plane.SetNormal( normal );
p->plane.SetDist( src->ParseFloat() );
src->Parse1DMatrix( 3, p->bounds[0].ToFloatPtr() );
src->Parse1DMatrix( 3, p->bounds[1].ToFloatPtr() );
src->ExpectTokenType( TT_STRING, 0, &token );
// get material
p->material = declManager->FindMaterial( token );
p->contents = p->material->GetContentFlags();
p->checkcount = 0;
// filter polygon into tree
R_FilterPolygonIntoTree( model, model->node, NULL, p );
}
}
/*
================
idCollisionModelManagerLocal::ParseBrushes
================
*/
void idCollisionModelManagerLocal::ParseBrushes( idLexer *src, cm_model_t *model ) {
cm_brush_t *b;
int i, numPlanes;
idVec3 normal;
idToken token;
if ( src->CheckTokenType( TT_NUMBER, 0, &token ) ) {
model->brushBlock = (cm_brushBlock_t *) Mem_Alloc( sizeof( cm_brushBlock_t ) + token.GetIntValue() );
model->brushBlock->bytesRemaining = token.GetIntValue();
model->brushBlock->next = ( (byte *) model->brushBlock ) + sizeof( cm_brushBlock_t );
}
src->ExpectTokenString( "{" );
while ( !src->CheckTokenString( "}" ) ) {
// parse brush
numPlanes = src->ParseInt();
b = AllocBrush( model, numPlanes );
b->numPlanes = numPlanes;
src->ExpectTokenString( "{" );
for ( i = 0; i < b->numPlanes; i++ ) {
src->Parse1DMatrix( 3, normal.ToFloatPtr() );
b->planes[i].SetNormal( normal );
b->planes[i].SetDist( src->ParseFloat() );
}
src->ExpectTokenString( "}" );
src->Parse1DMatrix( 3, b->bounds[0].ToFloatPtr() );
src->Parse1DMatrix( 3, b->bounds[1].ToFloatPtr() );
src->ReadToken( &token );
if ( token.type == TT_NUMBER ) {
b->contents = token.GetIntValue(); // old .cm files use a single integer
} else {
b->contents = ContentsFromString( token );
}
b->checkcount = 0;
b->primitiveNum = 0;
// filter brush into tree
R_FilterBrushIntoTree( model, model->node, NULL, b );
}
}
/*
================
idCollisionModelManagerLocal::ParseCollisionModel
================
*/
bool idCollisionModelManagerLocal::ParseCollisionModel( idLexer *src ) {
cm_model_t *model;
idToken token;
if ( numModels >= MAX_SUBMODELS ) {
common->Error( "LoadModel: no free slots" );
return false;
}
model = AllocModel();
models[numModels ] = model;
numModels++;
// parse the file
src->ExpectTokenType( TT_STRING, 0, &token );
model->name = token;
//HUMANHEAD rww
#if _HH_INLINED_PROC_CLIPMODELS
if (anyInlinedProcClipMats) {
if (token.Cmpn(PROC_CLIPMODEL_STRING_PRFX, strlen(PROC_CLIPMODEL_STRING_PRFX)) == 0) {
numInlinedProcClipModels++;
}
}
#endif
//HUMANHEAD END
src->ExpectTokenString( "{" );
while ( !src->CheckTokenString( "}" ) ) {
src->ReadToken( &token );
if ( token == "vertices" ) {
ParseVertices( src, model );
continue;
}
if ( token == "edges" ) {
ParseEdges( src, model );
continue;
}
if ( token == "nodes" ) {
src->ExpectTokenString( "{" );
model->node = ParseNodes( src, model, NULL );
src->ExpectTokenString( "}" );
continue;
}
if ( token == "polygons" ) {
ParsePolygons( src, model );
continue;
}
if ( token == "brushes" ) {
ParseBrushes( src, model );
continue;
}
src->Error( "ParseCollisionModel: bad token \"%s\"", token.c_str() );
}
// calculate edge normals
checkCount++;
CalculateEdgeNormals( model, model->node );
// get model bounds from brush and polygon bounds
CM_GetNodeBounds( &model->bounds, model->node );
// get model contents
model->contents = CM_GetNodeContents( model->node );
// total memory used by this model
model->usedMemory = model->numVertices * sizeof(cm_vertex_t) +
model->numEdges * sizeof(cm_edge_t) +
model->polygonMemory +
model->brushMemory +
model->numNodes * sizeof(cm_node_t) +
model->numPolygonRefs * sizeof(cm_polygonRef_t) +
model->numBrushRefs * sizeof(cm_brushRef_t);
return true;
}
/*
================
idCollisionModelManagerLocal::LoadCollisionModelFile
================
*/
bool idCollisionModelManagerLocal::LoadCollisionModelFile( const char *name, unsigned int mapFileCRC ) {
idStr fileName;
idToken token;
idLexer *src;
unsigned int crc;
// load it
fileName = name;
fileName.SetFileExtension( CM_FILE_EXT );
src = new idLexer( fileName );
src->SetFlags( LEXFL_NOSTRINGCONCAT | LEXFL_NODOLLARPRECOMPILE );
if ( !src->IsLoaded() ) {
delete src;
return false;
}
if ( !src->ExpectTokenString( CM_FILEID ) ) {
common->Warning( "%s is not an CM file.", fileName.c_str() );
delete src;
return false;
}
if ( !src->ReadToken( &token ) || token != CM_FILEVERSION ) {
common->Warning( "%s has version %s instead of %s", fileName.c_str(), token.c_str(), CM_FILEVERSION );
delete src;
return false;
}
if ( !src->ExpectTokenType( TT_NUMBER, TT_INTEGER, &token ) ) {
common->Warning( "%s has no map file CRC", fileName.c_str() );
delete src;
return false;
}
crc = token.GetUnsignedLongValue();
if ( mapFileCRC && crc != mapFileCRC ) {
common->Printf( "%s is out of date\n", fileName.c_str() );
delete src;
return false;
}
// parse the file
while ( 1 ) {
if ( !src->ReadToken( &token ) ) {
break;
}
if ( token == "collisionModel" ) {
if ( !ParseCollisionModel( src ) ) {
delete src;
return false;
}
continue;
}
src->Error( "idCollisionModelManagerLocal::LoadCollisionModelFile: bad token \"%s\"", token.c_str() );
}
delete src;
return true;
}

File diff suppressed because it is too large Load diff

View file

@ -1,527 +0,0 @@
/*
===============================================================================
Trace model vs. polygonal model collision detection.
===============================================================================
*/
#include "CollisionModel.h"
#define MIN_NODE_SIZE 64.0f
#define MAX_NODE_POLYGONS 128
#define CM_MAX_POLYGON_EDGES 64
#define CIRCLE_APPROXIMATION_LENGTH 64.0f
#define MAX_SUBMODELS 2048
#define TRACE_MODEL_HANDLE MAX_SUBMODELS
#define VERTEX_HASH_BOXSIZE (1<<6) // must be power of 2
#define VERTEX_HASH_SIZE (VERTEX_HASH_BOXSIZE*VERTEX_HASH_BOXSIZE)
#define EDGE_HASH_SIZE (1<<14)
#define NODE_BLOCK_SIZE_SMALL 8
#define NODE_BLOCK_SIZE_LARGE 256
#define REFERENCE_BLOCK_SIZE_SMALL 8
#define REFERENCE_BLOCK_SIZE_LARGE 256
#define MAX_WINDING_LIST 128 // quite a few are generated at times
#define INTEGRAL_EPSILON 0.01f
#define VERTEX_EPSILON 0.1f
#define CHOP_EPSILON 0.1f
typedef struct cm_windingList_s {
int numWindings; // number of windings
idFixedWinding w[MAX_WINDING_LIST]; // windings
idVec3 normal; // normal for all windings
idBounds bounds; // bounds of all windings in list
idVec3 origin; // origin for radius
float radius; // radius relative to origin for all windings
int contents; // winding surface contents
int primitiveNum; // number of primitive the windings came from
} cm_windingList_t;
/*
===============================================================================
Collision model
===============================================================================
*/
typedef struct cm_vertex_s {
idVec3 p; // vertex point
int checkcount; // for multi-check avoidance
unsigned long side; // each bit tells at which side this vertex passes one of the trace model edges
unsigned long sideSet; // each bit tells if sidedness for the trace model edge has been calculated yet
} cm_vertex_t;
typedef struct cm_edge_s {
int checkcount; // for multi-check avoidance
unsigned short internal; // a trace model can never collide with internal edges
unsigned short numUsers; // number of polygons using this edge
unsigned long side; // each bit tells at which side of this edge one of the trace model vertices passes
unsigned long sideSet; // each bit tells if sidedness for the trace model vertex has been calculated yet
int vertexNum[2]; // start and end point of edge
idVec3 normal; // edge normal
} cm_edge_t;
typedef struct cm_polygonBlock_s {
int bytesRemaining;
byte * next;
} cm_polygonBlock_t;
typedef struct cm_polygon_s {
idBounds bounds; // polygon bounds
int checkcount; // for multi-check avoidance
int contents; // contents behind polygon
const idMaterial * material; // material
idPlane plane; // polygon plane
int numEdges; // number of edges
int edges[1]; // variable sized, indexes into cm_edge_t list
} cm_polygon_t;
typedef struct cm_polygonRef_s {
cm_polygon_t * p; // pointer to polygon
struct cm_polygonRef_s *next; // next polygon in chain
} cm_polygonRef_t;
typedef struct cm_polygonRefBlock_s {
cm_polygonRef_t * nextRef; // next polygon reference in block
struct cm_polygonRefBlock_s *next; // next block with polygon references
} cm_polygonRefBlock_t;
typedef struct cm_brushBlock_s {
int bytesRemaining;
byte * next;
} cm_brushBlock_t;
typedef struct cm_brush_s {
int checkcount; // for multi-check avoidance
idBounds bounds; // brush bounds
int contents; // contents of brush
const idMaterial * material; // material
int primitiveNum; // number of brush primitive
int numPlanes; // number of bounding planes
idPlane planes[1]; // variable sized
} cm_brush_t;
typedef struct cm_brushRef_s {
cm_brush_t * b; // pointer to brush
struct cm_brushRef_s * next; // next brush in chain
} cm_brushRef_t;
typedef struct cm_brushRefBlock_s {
cm_brushRef_t * nextRef; // next brush reference in block
struct cm_brushRefBlock_s *next; // next block with brush references
} cm_brushRefBlock_t;
typedef struct cm_node_s {
int planeType; // node axial plane type
float planeDist; // node plane distance
cm_polygonRef_t * polygons; // polygons in node
cm_brushRef_t * brushes; // brushes in node
struct cm_node_s * parent; // parent of this node
struct cm_node_s * children[2]; // node children
} cm_node_t;
typedef struct cm_nodeBlock_s {
cm_node_t * nextNode; // next node in block
struct cm_nodeBlock_s *next; // next block with nodes
} cm_nodeBlock_t;
typedef struct cm_model_s {
idStr name; // model name
idBounds bounds; // model bounds
int contents; // all contents of the model ored together
bool isConvex; // set if model is convex
// model geometry
int maxVertices; // size of vertex array
int numVertices; // number of vertices
cm_vertex_t * vertices; // array with all vertices used by the model
int maxEdges; // size of edge array
int numEdges; // number of edges
cm_edge_t * edges; // array with all edges used by the model
cm_node_t * node; // first node of spatial subdivision
// blocks with allocated memory
cm_nodeBlock_t * nodeBlocks; // list with blocks of nodes
cm_polygonRefBlock_t * polygonRefBlocks; // list with blocks of polygon references
cm_brushRefBlock_t * brushRefBlocks; // list with blocks of brush references
cm_polygonBlock_t * polygonBlock; // memory block with all polygons
cm_brushBlock_t * brushBlock; // memory block with all brushes
// statistics
int numPolygons;
int polygonMemory;
int numBrushes;
int brushMemory;
int numNodes;
int numBrushRefs;
int numPolygonRefs;
int numInternalEdges;
int numSharpEdges;
int numRemovedPolys;
int numMergedPolys;
int usedMemory;
} cm_model_t;
/*
===============================================================================
Data used during collision detection calculations
===============================================================================
*/
typedef struct cm_trmVertex_s {
int used; // true if this vertex is used for collision detection
idVec3 p; // vertex position
idVec3 endp; // end point of vertex after movement
int polygonSide; // side of polygon this vertex is on (rotational collision)
idPluecker pl; // pluecker coordinate for vertex movement
idVec3 rotationOrigin; // rotation origin for this vertex
idBounds rotationBounds; // rotation bounds for this vertex
} cm_trmVertex_t;
typedef struct cm_trmEdge_s {
int used; // true when vertex is used for collision detection
idVec3 start; // start of edge
idVec3 end; // end of edge
int vertexNum[2]; // indexes into cm_traceWork_t->vertices
idPluecker pl; // pluecker coordinate for edge
idVec3 cross; // (z,-y,x) of cross product between edge dir and movement dir
idBounds rotationBounds; // rotation bounds for this edge
idPluecker plzaxis; // pluecker coordinate for rotation about the z-axis
unsigned short bitNum; // vertex bit number
} cm_trmEdge_t;
typedef struct cm_trmPolygon_s {
int used;
idPlane plane; // polygon plane
int numEdges; // number of edges
int edges[MAX_TRACEMODEL_POLYEDGES]; // index into cm_traceWork_t->edges
idBounds rotationBounds; // rotation bounds for this polygon
} cm_trmPolygon_t;
typedef struct cm_traceWork_s {
int numVerts;
cm_trmVertex_t vertices[MAX_TRACEMODEL_VERTS]; // trm vertices
int numEdges;
cm_trmEdge_t edges[MAX_TRACEMODEL_EDGES+1]; // trm edges
int numPolys;
cm_trmPolygon_t polys[MAX_TRACEMODEL_POLYS]; // trm polygons
cm_model_t *model; // model colliding with
idVec3 start; // start of trace
idVec3 end; // end of trace
idVec3 dir; // trace direction
idBounds bounds; // bounds of full trace
idBounds size; // bounds of transformed trm relative to start
idVec3 extents; // largest of abs(size[0]) and abs(size[1]) for BSP trace
int contents; // ignore polygons that do not have any of these contents flags
trace_t trace; // collision detection result
bool rotation; // true if calculating rotational collision
bool pointTrace; // true if only tracing a point
bool positionTest; // true if not tracing but doing a position test
bool isConvex; // true if the trace model is convex
bool axisIntersectsTrm; // true if the rotation axis intersects the trace model
bool getContacts; // true if retrieving contacts
bool quickExit; // set to quickly stop the collision detection calculations
idVec3 origin; // origin of rotation in model space
idVec3 axis; // rotation axis in model space
idMat3 matrix; // rotates axis of rotation to the z-axis
float angle; // angle for rotational collision
float maxTan; // max tangent of half the positive angle used instead of fraction
float radius; // rotation radius of trm start
idRotation modelVertexRotation; // inverse rotation for model vertices
contactInfo_t *contacts; // array with contacts
int maxContacts; // max size of contact array
int numContacts; // number of contacts found
idPlane heartPlane1; // polygons should be near anough the trace heart planes
float maxDistFromHeartPlane1;
idPlane heartPlane2;
float maxDistFromHeartPlane2;
idPluecker polygonEdgePlueckerCache[CM_MAX_POLYGON_EDGES];
idPluecker polygonVertexPlueckerCache[CM_MAX_POLYGON_EDGES];
idVec3 polygonRotationOriginCache[CM_MAX_POLYGON_EDGES];
} cm_traceWork_t;
/*
===============================================================================
Collision Map
===============================================================================
*/
typedef struct cm_procNode_s {
idPlane plane;
int children[2]; // negative numbers are (-1 - areaNumber), 0 = solid
} cm_procNode_t;
class idCollisionModelManagerLocal : public idCollisionModelManager {
public:
// load collision models from a map file
void LoadMap( const idMapFile *mapFile );
// HUMANHEAD pdm: Support for level appending
virtual const char * ContentsName(const int contents) const { return StringFromContents(contents); }
#if DEATHWALK_AUTOLOAD
virtual void AppendMap( const idMapFile *mapFile );
virtual bool WillUseAlreadyLoadedCollisionMap(const idMapFile *mapFile);
#endif
// HUMANHEAD END
// frees all the collision models
void FreeMap( void );
// get clip handle for model
cmHandle_t LoadModel( const char *modelName, const bool precache );
// sets up a trace model for collision with other trace models
cmHandle_t SetupTrmModel( const idTraceModel &trm, const idMaterial *material );
// create trace model from a collision model, returns true if succesfull
bool TrmFromModel( const char *modelName, idTraceModel &trm );
// name of the model
const char * GetModelName( cmHandle_t model ) const;
// bounds of the model
bool GetModelBounds( cmHandle_t model, idBounds &bounds ) const;
// all contents flags of brushes and polygons ored together
bool GetModelContents( cmHandle_t model, int &contents ) const;
// get the vertex of a model
bool GetModelVertex( cmHandle_t model, int vertexNum, idVec3 &vertex ) const;
// get the edge of a model
bool GetModelEdge( cmHandle_t model, int edgeNum, idVec3 &start, idVec3 &end ) const;
// get the polygon of a model
bool GetModelPolygon( cmHandle_t model, int polygonNum, idFixedWinding &winding ) const;
// translates a trm and reports the first collision if any
void Translation( trace_t *results, const idVec3 &start, const idVec3 &end,
const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis );
// rotates a trm and reports the first collision if any
void Rotation( trace_t *results, const idVec3 &start, const idRotation &rotation,
const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis );
// returns the contents the trm is stuck in or 0 if the trm is in free space
int Contents( const idVec3 &start,
const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis );
// stores all contact points of the trm with the model, returns the number of contacts
int Contacts( contactInfo_t *contacts, const int maxContacts, const idVec3 &start, const idVec6 &dir, const float depth,
const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis );
// test collision detection
void DebugOutput( const idVec3 &origin );
// draw a model
void DrawModel( cmHandle_t model, const idVec3 &origin, const idMat3 &axis,
const idVec3 &viewOrigin, const float radius );
// print model information, use -1 handle for accumulated model info
void ModelInfo( cmHandle_t model );
// list all loaded models
void ListModels( void );
// write a collision model file for the map entity
bool WriteCollisionModelForMapEntity( const idMapEntity *mapEnt, const char *filename, const bool testTraceModel = true );
//HUMANHEAD rww
#if _HH_INLINED_PROC_CLIPMODELS
int GetNumInlinedProcClipModels(void);
#endif
//HUMANHEAD END
private: // CollisionMap_translate.cpp
int TranslateEdgeThroughEdge( idVec3 &cross, idPluecker &l1, idPluecker &l2, float *fraction );
void TranslateTrmEdgeThroughPolygon( cm_traceWork_t *tw, cm_polygon_t *poly, cm_trmEdge_t *trmEdge );
void TranslateTrmVertexThroughPolygon( cm_traceWork_t *tw, cm_polygon_t *poly, cm_trmVertex_t *v, int bitNum );
void TranslatePointThroughPolygon( cm_traceWork_t *tw, cm_polygon_t *poly, cm_trmVertex_t *v );
void TranslateVertexThroughTrmPolygon( cm_traceWork_t *tw, cm_trmPolygon_t *trmpoly, cm_polygon_t *poly, cm_vertex_t *v, idVec3 &endp, idPluecker &pl );
bool TranslateTrmThroughPolygon( cm_traceWork_t *tw, cm_polygon_t *p );
void SetupTranslationHeartPlanes( cm_traceWork_t *tw );
void SetupTrm( cm_traceWork_t *tw, const idTraceModel *trm );
private: // CollisionMap_rotate.cpp
int CollisionBetweenEdgeBounds( cm_traceWork_t *tw, const idVec3 &va, const idVec3 &vb,
const idVec3 &vc, const idVec3 &vd, float tanHalfAngle,
idVec3 &collisionPoint, idVec3 &collisionNormal );
int RotateEdgeThroughEdge( cm_traceWork_t *tw, const idPluecker &pl1,
const idVec3 &vc, const idVec3 &vd,
const float minTan, float &tanHalfAngle );
int EdgeFurthestFromEdge( cm_traceWork_t *tw, const idPluecker &pl1,
const idVec3 &vc, const idVec3 &vd,
float &tanHalfAngle, float &dir );
void RotateTrmEdgeThroughPolygon( cm_traceWork_t *tw, cm_polygon_t *poly, cm_trmEdge_t *trmEdge );
int RotatePointThroughPlane( const cm_traceWork_t *tw, const idVec3 &point, const idPlane &plane,
const float angle, const float minTan, float &tanHalfAngle );
int PointFurthestFromPlane( const cm_traceWork_t *tw, const idVec3 &point, const idPlane &plane,
const float angle, float &tanHalfAngle, float &dir );
int RotatePointThroughEpsilonPlane( const cm_traceWork_t *tw, const idVec3 &point, const idVec3 &endPoint,
const idPlane &plane, const float angle, const idVec3 &origin,
float &tanHalfAngle, idVec3 &collisionPoint, idVec3 &endDir );
void RotateTrmVertexThroughPolygon( cm_traceWork_t *tw, cm_polygon_t *poly, cm_trmVertex_t *v, int vertexNum);
void RotateVertexThroughTrmPolygon( cm_traceWork_t *tw, cm_trmPolygon_t *trmpoly, cm_polygon_t *poly,
cm_vertex_t *v, idVec3 &rotationOrigin );
bool RotateTrmThroughPolygon( cm_traceWork_t *tw, cm_polygon_t *p );
void BoundsForRotation( const idVec3 &origin, const idVec3 &axis, const idVec3 &start, const idVec3 &end, idBounds &bounds );
void Rotation180( trace_t *results, const idVec3 &rorg, const idVec3 &axis,
const float startAngle, const float endAngle, const idVec3 &start,
const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
cmHandle_t model, const idVec3 &origin, const idMat3 &modelAxis );
private: // CollisionMap_contents.cpp
bool TestTrmVertsInBrush( cm_traceWork_t *tw, cm_brush_t *b );
bool TestTrmInPolygon( cm_traceWork_t *tw, cm_polygon_t *p );
cm_node_t * PointNode( const idVec3 &p, cm_model_t *model );
int PointContents( const idVec3 p, cmHandle_t model );
int TransformedPointContents( const idVec3 &p, cmHandle_t model, const idVec3 &origin, const idMat3 &modelAxis );
int ContentsTrm( trace_t *results, const idVec3 &start,
const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis );
private: // CollisionMap_trace.cpp
void TraceTrmThroughNode( cm_traceWork_t *tw, cm_node_t *node );
void TraceThroughAxialBSPTree_r( cm_traceWork_t *tw, cm_node_t *node, float p1f, float p2f, idVec3 &p1, idVec3 &p2);
void TraceThroughModel( cm_traceWork_t *tw );
void RecurseProcBSP_r( trace_t *results, int parentNodeNum, int nodeNum, float p1f, float p2f, const idVec3 &p1, const idVec3 &p2 );
private: // CollisionMap_load.cpp
void Clear( void );
void FreeTrmModelStructure( void );
// model deallocation
void RemovePolygonReferences_r( cm_node_t *node, cm_polygon_t *p );
void RemoveBrushReferences_r( cm_node_t *node, cm_brush_t *b );
void FreeNode( cm_node_t *node );
void FreePolygonReference( cm_polygonRef_t *pref );
void FreeBrushReference( cm_brushRef_t *bref );
void FreePolygon( cm_model_t *model, cm_polygon_t *poly );
void FreeBrush( cm_model_t *model, cm_brush_t *brush );
void FreeTree_r( cm_model_t *model, cm_node_t *headNode, cm_node_t *node );
void FreeModel( cm_model_t *model );
// merging polygons
void ReplacePolygons( cm_model_t *model, cm_node_t *node, cm_polygon_t *p1, cm_polygon_t *p2, cm_polygon_t *newp );
cm_polygon_t * TryMergePolygons( cm_model_t *model, cm_polygon_t *p1, cm_polygon_t *p2 );
bool MergePolygonWithTreePolygons( cm_model_t *model, cm_node_t *node, cm_polygon_t *polygon );
void MergeTreePolygons( cm_model_t *model, cm_node_t *node );
// finding internal edges
bool PointInsidePolygon( cm_model_t *model, cm_polygon_t *p, idVec3 &v );
void FindInternalEdgesOnPolygon( cm_model_t *model, cm_polygon_t *p1, cm_polygon_t *p2 );
void FindInternalPolygonEdges( cm_model_t *model, cm_node_t *node, cm_polygon_t *polygon );
void FindInternalEdges( cm_model_t *model, cm_node_t *node );
void FindContainedEdges( cm_model_t *model, cm_polygon_t *p );
// loading of proc BSP tree
void ParseProcNodes( idLexer *src );
//HUMANHEAD rww
#if _HH_INLINED_PROC_CLIPMODELS
void CheckProcModelSurfClip(idLexer *src);
#endif
//HUMANHEAD END
void LoadProcBSP( const char *name );
// removal of contained polygons
int R_ChoppedAwayByProcBSP( int nodeNum, idFixedWinding *w, const idVec3 &normal, const idVec3 &origin, const float radius );
int ChoppedAwayByProcBSP( const idFixedWinding &w, const idPlane &plane, int contents );
void ChopWindingListWithBrush( cm_windingList_t *list, cm_brush_t *b );
void R_ChopWindingListWithTreeBrushes( cm_windingList_t *list, cm_node_t *node );
idFixedWinding *WindingOutsideBrushes( idFixedWinding *w, const idPlane &plane, int contents, int patch, cm_node_t *headNode );
// creation of axial BSP tree
cm_model_t * AllocModel( void );
cm_node_t * AllocNode( cm_model_t *model, int blockSize );
cm_polygonRef_t*AllocPolygonReference( cm_model_t *model, int blockSize );
cm_brushRef_t * AllocBrushReference( cm_model_t *model, int blockSize );
cm_polygon_t * AllocPolygon( cm_model_t *model, int numEdges );
cm_brush_t * AllocBrush( cm_model_t *model, int numPlanes );
void AddPolygonToNode( cm_model_t *model, cm_node_t *node, cm_polygon_t *p );
void AddBrushToNode( cm_model_t *model, cm_node_t *node, cm_brush_t *b );
void SetupTrmModelStructure( void );
void R_FilterPolygonIntoTree( cm_model_t *model, cm_node_t *node, cm_polygonRef_t *pref, cm_polygon_t *p );
void R_FilterBrushIntoTree( cm_model_t *model, cm_node_t *node, cm_brushRef_t *pref, cm_brush_t *b );
cm_node_t * R_CreateAxialBSPTree( cm_model_t *model, cm_node_t *node, const idBounds &bounds );
cm_node_t * CreateAxialBSPTree( cm_model_t *model, cm_node_t *node );
// creation of raw polygons
void SetupHash(void);
void ShutdownHash(void);
void ClearHash( idBounds &bounds );
int HashVec(const idVec3 &vec);
int GetVertex( cm_model_t *model, const idVec3 &v, int *vertexNum );
int GetEdge( cm_model_t *model, const idVec3 &v1, const idVec3 &v2, int *edgeNum, int v1num );
void CreatePolygon( cm_model_t *model, idFixedWinding *w, const idPlane &plane, const idMaterial *material, int primitiveNum );
void PolygonFromWinding( cm_model_t *model, idFixedWinding *w, const idPlane &plane, const idMaterial *material, int primitiveNum );
void CalculateEdgeNormals( cm_model_t *model, cm_node_t *node );
void CreatePatchPolygons( cm_model_t *model, idSurface_Patch &mesh, const idMaterial *material, int primitiveNum );
void ConvertPatch( cm_model_t *model, const idMapPatch *patch, int primitiveNum );
void ConvertBrushSides( cm_model_t *model, const idMapBrush *mapBrush, int primitiveNum );
void ConvertBrush( cm_model_t *model, const idMapBrush *mapBrush, int primitiveNum );
void PrintModelInfo( const cm_model_t *model );
void AccumulateModelInfo( cm_model_t *model );
void RemapEdges( cm_node_t *node, int *edgeRemap );
void OptimizeArrays( cm_model_t *model );
void FinishModel( cm_model_t *model );
void BuildModels( const idMapFile *mapFile );
cmHandle_t FindModel( const char *name );
cm_model_t * CollisionModelForMapEntity( const idMapEntity *mapEnt ); // brush/patch model from .map
cm_model_t * LoadRenderModel( const char *fileName ); // ASE/LWO models
bool TrmFromModel_r( idTraceModel &trm, cm_node_t *node );
bool TrmFromModel( const cm_model_t *model, idTraceModel &trm );
private: // CollisionMap_files.cpp
// writing
void WriteNodes( idFile *fp, cm_node_t *node );
int CountPolygonMemory( cm_node_t *node ) const;
void WritePolygons( idFile *fp, cm_node_t *node );
int CountBrushMemory( cm_node_t *node ) const;
void WriteBrushes( idFile *fp, cm_node_t *node );
void WriteCollisionModel( idFile *fp, cm_model_t *model );
void WriteCollisionModelsToFile( const char *filename, int firstModel, int lastModel, unsigned int mapFileCRC );
// loading
cm_node_t * ParseNodes( idLexer *src, cm_model_t *model, cm_node_t *parent );
void ParseVertices( idLexer *src, cm_model_t *model );
void ParseEdges( idLexer *src, cm_model_t *model );
void ParsePolygons( idLexer *src, cm_model_t *model );
void ParseBrushes( idLexer *src, cm_model_t *model );
bool ParseCollisionModel( idLexer *src );
bool LoadCollisionModelFile( const char *name, unsigned int mapFileCRC );
private: // CollisionMap_debug
int ContentsFromString( const char *string ) const;
const char * StringFromContents( const int contents ) const;
void DrawEdge( cm_model_t *model, int edgeNum, const idVec3 &origin, const idMat3 &axis );
void DrawPolygon( cm_model_t *model, cm_polygon_t *p, const idVec3 &origin, const idMat3 &axis,
const idVec3 &viewOrigin );
void DrawNodePolygons( cm_model_t *model, cm_node_t *node, const idVec3 &origin, const idMat3 &axis,
const idVec3 &viewOrigin, const float radius );
private: // collision map data
idStr mapName;
unsigned int mapFileTime;
int loaded;
// for multi-check avoidance
int checkCount;
// models
int maxModels;
int numModels;
cm_model_t ** models;
// polygons and brush for trm model
cm_polygonRef_t*trmPolygons[MAX_TRACEMODEL_POLYS];
cm_brushRef_t * trmBrushes[1];
const idMaterial *trmMaterial;
// for data pruning
int numProcNodes;
cm_procNode_t * procNodes;
// for retrieving contact points
bool getContacts;
contactInfo_t * contacts;
int maxContacts;
int numContacts;
//HUMANHEAD rww
#if _HH_INLINED_PROC_CLIPMODELS
idList<const char *> inlinedProcClipModelMats;
int numInlinedProcClipModels;
bool anyInlinedProcClipMats;
#endif
//HUMANHEAD END
};
// for debugging
extern idCVar cm_debugCollision;

File diff suppressed because it is too large Load diff

View file

@ -1,229 +0,0 @@
/*
===============================================================================
Trace model vs. polygonal model collision detection.
===============================================================================
*/
#include "../idlib/precompiled.h"
#pragma hdrstop
#include "CollisionModel_local.h"
/*
===============================================================================
Trace through the spatial subdivision
===============================================================================
*/
/*
================
idCollisionModelManagerLocal::TraceTrmThroughNode
================
*/
void idCollisionModelManagerLocal::TraceTrmThroughNode( cm_traceWork_t *tw, cm_node_t *node ) {
cm_polygonRef_t *pref;
cm_brushRef_t *bref;
// position test
if ( tw->positionTest ) {
// if already stuck in solid
if ( tw->trace.fraction == 0.0f ) {
return;
}
// test if any of the trm vertices is inside a brush
for ( bref = node->brushes; bref; bref = bref->next ) {
if ( idCollisionModelManagerLocal::TestTrmVertsInBrush( tw, bref->b ) ) {
return;
}
}
// if just testing a point we're done
if ( tw->pointTrace ) {
return;
}
// test if the trm is stuck in any polygons
for ( pref = node->polygons; pref; pref = pref->next ) {
if ( idCollisionModelManagerLocal::TestTrmInPolygon( tw, pref->p ) ) {
return;
}
}
}
else if ( tw->rotation ) {
// rotate through all polygons in this leaf
for ( pref = node->polygons; pref; pref = pref->next ) {
if ( idCollisionModelManagerLocal::RotateTrmThroughPolygon( tw, pref->p ) ) {
return;
}
}
}
else {
// trace through all polygons in this leaf
for ( pref = node->polygons; pref; pref = pref->next ) {
if ( idCollisionModelManagerLocal::TranslateTrmThroughPolygon( tw, pref->p ) ) {
return;
}
}
}
}
/*
================
idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r
================
*/
//#define NO_SPATIAL_SUBDIVISION
void idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( cm_traceWork_t *tw, cm_node_t *node, float p1f, float p2f, idVec3 &p1, idVec3 &p2) {
float t1, t2, offset;
float frac, frac2;
float idist;
idVec3 mid;
int side;
float midf;
if ( !node ) {
return;
}
if ( tw->quickExit ) {
return; // stop immediately
}
if ( tw->trace.fraction <= p1f ) {
return; // already hit something nearer
}
// if we need to test this node for collisions
if ( node->polygons || (tw->positionTest && node->brushes) ) {
// trace through node with collision data
idCollisionModelManagerLocal::TraceTrmThroughNode( tw, node );
}
// if already stuck in solid
if ( tw->positionTest && tw->trace.fraction == 0.0f ) {
return;
}
// if this is a leaf node
if ( node->planeType == -1 ) {
return;
}
#ifdef NO_SPATIAL_SUBDIVISION
idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, node->children[0], p1f, p2f, p1, p2 );
idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, node->children[1], p1f, p2f, p1, p2 );
return;
#endif
// distance from plane for trace start and end
t1 = p1[node->planeType] - node->planeDist;
t2 = p2[node->planeType] - node->planeDist;
// adjust the plane distance appropriately for mins/maxs
offset = tw->extents[node->planeType];
// see which sides we need to consider
if ( t1 >= offset && t2 >= offset ) {
idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, node->children[0], p1f, p2f, p1, p2 );
return;
}
if ( t1 < -offset && t2 < -offset ) {
idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, node->children[1], p1f, p2f, p1, p2 );
return;
}
if ( t1 < t2 ) {
idist = 1.0f / (t1-t2);
side = 1;
frac2 = (t1 + offset) * idist;
frac = (t1 - offset) * idist;
} else if (t1 > t2) {
idist = 1.0f / (t1-t2);
side = 0;
frac2 = (t1 - offset) * idist;
frac = (t1 + offset) * idist;
} else {
side = 0;
frac = 1.0f;
frac2 = 0.0f;
}
// move up to the node
if ( frac < 0.0f ) {
frac = 0.0f;
}
else if ( frac > 1.0f ) {
frac = 1.0f;
}
midf = p1f + (p2f - p1f)*frac;
mid[0] = p1[0] + frac*(p2[0] - p1[0]);
mid[1] = p1[1] + frac*(p2[1] - p1[1]);
mid[2] = p1[2] + frac*(p2[2] - p1[2]);
idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, node->children[side], p1f, midf, p1, mid );
// go past the node
if ( frac2 < 0.0f ) {
frac2 = 0.0f;
}
else if ( frac2 > 1.0f ) {
frac2 = 1.0f;
}
midf = p1f + (p2f - p1f)*frac2;
mid[0] = p1[0] + frac2*(p2[0] - p1[0]);
mid[1] = p1[1] + frac2*(p2[1] - p1[1]);
mid[2] = p1[2] + frac2*(p2[2] - p1[2]);
idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, node->children[side^1], midf, p2f, mid, p2 );
}
/*
================
idCollisionModelManagerLocal::TraceThroughModel
================
*/
void idCollisionModelManagerLocal::TraceThroughModel( cm_traceWork_t *tw ) {
float d;
int i, numSteps;
idVec3 start, end;
idRotation rot;
if ( !tw->rotation ) {
// trace through spatial subdivision and then through leafs
idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, tw->model->node, 0, 1, tw->start, tw->end );
}
else {
// approximate the rotation with a series of straight line movements
// total length covered along circle
d = tw->radius * DEG2RAD( tw->angle );
// if more than one step
if ( d > CIRCLE_APPROXIMATION_LENGTH ) {
// number of steps for the approximation
numSteps = (int) (CIRCLE_APPROXIMATION_LENGTH / d);
// start of approximation
start = tw->start;
// trace circle approximation steps through the BSP tree
for ( i = 0; i < numSteps; i++ ) {
// calculate next point on approximated circle
rot.Set( tw->origin, tw->axis, tw->angle * ((float) (i+1) / numSteps) );
end = start * rot;
// trace through spatial subdivision and then through leafs
idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, tw->model->node, 0, 1, start, end );
// no need to continue if something was hit already
if ( tw->trace.fraction < 1.0f ) {
return;
}
start = end;
}
}
else {
start = tw->start;
}
// last step of the approximation
idCollisionModelManagerLocal::TraceThroughAxialBSPTree_r( tw, tw->model->node, 0, 1, start, tw->end );
}
}

File diff suppressed because it is too large Load diff