as released 2006-10-13
This commit is contained in:
parent
0d7517fbb2
commit
b96d945884
9 changed files with 0 additions and 9241 deletions
|
@ -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;
|
|
||||||
}
|
|
|
@ -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 );
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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
|
@ -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
|
@ -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
Loading…
Reference in a new issue