示例#1
0
/*
============
idTraceModel::Shrink
============
*/
void idTraceModel::Shrink( const float m ) {
	int i, j, edgeNum;
	traceModelEdge_t *edge;
	idVec3 dir;

	if ( type == TRM_POLYGON ) {
		for ( i = 0; i < numEdges; i++ ) {
			edgeNum = polys[0].edges[i];
			edge = &edges[abs(edgeNum)];
			dir = verts[ edge->v[ INT32_SIGNBITSET(edgeNum) ] ] - verts[ edge->v[ INT32_SIGNBITNOTSET(edgeNum) ] ];
			if ( dir.Normalize() < 2.0f * m ) {
				continue;
			}
			dir *= m;
			verts[ edge->v[ 0 ] ] -= dir;
			verts[ edge->v[ 1 ] ] += dir;
		}
		return;
	}

	for ( i = 0; i < numPolys; i++ ) {
		polys[i].dist -= m;

		for ( j = 0; j < polys[i].numEdges; j++ ) {
			edgeNum = polys[i].edges[j];
			edge = &edges[abs(edgeNum)];
			verts[ edge->v[ INT32_SIGNBITSET(edgeNum) ] ] -= polys[i].normal * m;
		}
	}
}
示例#2
0
/*
=================
UpdateVertexIndex
=================
*/
ID_INLINE int UpdateVertexIndex( int vertexIndexNum[2], int *vertexRemap, int *vertexCopyIndex, int vertNum ) {
	int s = INT32_SIGNBITSET( vertexRemap[vertNum] );
	vertexIndexNum[0] = vertexRemap[vertNum];
	vertexRemap[vertNum] = vertexIndexNum[s];
	vertexIndexNum[1] += s;
	vertexCopyIndex[vertexRemap[vertNum]] = vertNum;
	return vertexRemap[vertNum];
}
示例#3
0
/*
============
idAASLocal::GetEdgeVertexNumbers
============
*/
void idAASLocal::GetEdgeVertexNumbers( int edgeNum, int verts[2] ) const {
	if ( !file ) {
		verts[0] = verts[1] = 0;
		return;
	}
	const int *v = file->GetEdge( abs(edgeNum) ).vertexNum;
	verts[0] = v[INT32_SIGNBITSET(edgeNum)];
	verts[1] = v[INT32_SIGNBITNOTSET(edgeNum)];
}
示例#4
0
/*
============
idAASLocal::GetEdge
============
*/
void idAASLocal::GetEdge( int edgeNum, idVec3 &start, idVec3 &end ) const {
	if ( !file ) {
		start.Zero();
		end.Zero();
		return;
	}
	const int *v = file->GetEdge( abs(edgeNum) ).vertexNum;
	start = file->GetVertex( v[INT32_SIGNBITSET(edgeNum)] );
	end = file->GetVertex( v[INT32_SIGNBITNOTSET(edgeNum)] );
}
示例#5
0
/*
============
idAASLocal::ShowAASBadAreas
============
*/
void idAASLocal::ShowAASBadAreas( int mode ) const {

	if ( file == NULL ) {
		return;
	}

	float height = file->GetSettings().boundingBox[1][2] - file->GetSettings().boundingBox[0][2];

	for ( int i = 0; i < file->GetNumAreas(); i++ ) {
		const aasArea_t &area = file->GetArea( i );

		idVec3 mid;
		mid.Zero();

		for ( int j = 0; j < area.numEdges; j++ ) {
			int edgeNum = file->GetEdgeIndex( area.firstEdge + j );
			const aasEdge_t &edge = file->GetEdge( abs( edgeNum ) );
			mid += file->GetVertex( edge.vertexNum[ INT32_SIGNBITSET( edgeNum ) ] );
		}

		mid /= area.numEdges;

		bool bad = false;

		if ( mode == 1 || mode == 3 ) {
			int j;
			for ( j = 0; j < 4; j++ ) {
				int areaNum = file->PointAreaNum( mid + file->GetSettings().invGravityDir * ( j * height )  );
				if ( areaNum == i ) {
					break;
				}
			}
			if ( j >= 4 ) {
				bad = true;
			}
		}

		if ( mode == 2 || mode == 3 ) {
#if 1
			if ( ( area.flags & AAS_AREA_NOPUSH ) != 0 ) {
				bad = true;
			}
#else
			idVec3 pushed = mid;
			if ( file->PushPointIntoArea( i, pushed ) ) {
				bad = true;
			}
#endif
		}

		if ( bad ) {
			DrawArea( i );
		}
	}
}
示例#6
0
/*
============
idTraceModel::GetPolygonArea
============
*/
float idTraceModel::GetPolygonArea( int polyNum ) const {
	int i;
	idVec3 base, v1, v2, cross;
	float total;
	const traceModelPoly_t *poly;

	if ( polyNum < 0 || polyNum >= numPolys ) {
		return 0.0f;
	}
	poly = &polys[polyNum];
	total = 0.0f;
	base = verts[ edges[ abs(poly->edges[0]) ].v[ INT32_SIGNBITSET( poly->edges[0] ) ] ];
	for ( i = 0; i < poly->numEdges; i++ ) {
		v1 = verts[ edges[ abs(poly->edges[i]) ].v[ INT32_SIGNBITSET( poly->edges[i] ) ] ] - base;
		v2 = verts[ edges[ abs(poly->edges[i]) ].v[ INT32_SIGNBITNOTSET( poly->edges[i] ) ] ] - base;
		cross = v1.Cross( v2 );
		total += cross.Length();
	}
	return total * 0.5f;
}
示例#7
0
/*
============
idTraceModel::Rotate
============
*/
void idTraceModel::Rotate( const idMat3 &rotation ) {
	int i, j, edgeNum;

	for ( i = 0; i < numVerts; i++ ) {
		verts[i] *= rotation;
	}

	bounds.Clear();
	for ( i = 0; i < numPolys; i++ ) {
		polys[i].normal *= rotation;
		polys[i].bounds.Clear();
		edgeNum = 0;
		for ( j = 0; j < polys[i].numEdges; j++ ) {
			edgeNum = polys[i].edges[j];
			polys[i].bounds.AddPoint( verts[edges[abs(edgeNum)].v[INT32_SIGNBITSET(edgeNum)]] );
		}
		polys[i].dist = polys[i].normal * verts[edges[abs(edgeNum)].v[INT32_SIGNBITSET(edgeNum)]];
		bounds += polys[i].bounds;
	}

	GenerateEdgeNormals();
}
示例#8
0
/*
============
idTraceModel::SetupOctahedron
============
*/
void idTraceModel::SetupOctahedron( const idBounds &octBounds ) {
	int i, e0, e1, v0, v1, v2;
	idVec3 v;

	if ( type != TRM_OCTAHEDRON ) {
		InitOctahedron();
	}

	offset = ( octBounds[0] + octBounds[1] ) * 0.5f;
	v[0] = octBounds[1][0] - offset[0];
	v[1] = octBounds[1][1] - offset[1];
	v[2] = octBounds[1][2] - offset[2];

	// set vertices
	verts[0].Set( offset.x + v[0], offset.y, offset.z );
	verts[1].Set( offset.x - v[0], offset.y, offset.z );
	verts[2].Set( offset.x, offset.y + v[1], offset.z );
	verts[3].Set( offset.x, offset.y - v[1], offset.z );
	verts[4].Set( offset.x, offset.y, offset.z + v[2] );
	verts[5].Set( offset.x, offset.y, offset.z - v[2] );

	// set polygons
	for ( i = 0; i < numPolys; i++ ) {
		e0 = polys[i].edges[0];
		e1 = polys[i].edges[1];
		v0 = edges[abs(e0)].v[INT32_SIGNBITSET(e0)];
		v1 = edges[abs(e0)].v[INT32_SIGNBITNOTSET(e0)];
		v2 = edges[abs(e1)].v[INT32_SIGNBITNOTSET(e1)];
		// polygon plane
		polys[i].normal = ( verts[v1] - verts[v0] ).Cross( verts[v2] - verts[v0] );
		polys[i].normal.Normalize();
		polys[i].dist = polys[i].normal * verts[v0];
		// polygon bounds
		polys[i].bounds[0] = polys[i].bounds[1] = verts[v0];
		polys[i].bounds.AddPoint( verts[v1] );
		polys[i].bounds.AddPoint( verts[v2] );
	}

	// trm bounds
	bounds = octBounds;

	GenerateEdgeNormals();
}
示例#9
0
/*
============
idTraceModel::GetProjectionSilhouetteEdges
============
*/
int idTraceModel::GetProjectionSilhouetteEdges( const idVec3 &projectionOrigin, int silEdges[MAX_TRACEMODEL_EDGES] ) const {
	int i, j, edgeNum;
	int edgeIsSilEdge[MAX_TRACEMODEL_EDGES+1];
	const traceModelPoly_t *poly;
	idVec3 dir;

	memset( edgeIsSilEdge, 0, sizeof( edgeIsSilEdge ) );

	for ( i = 0; i < numPolys; i++ ) {
		poly = &polys[i];
		edgeNum = poly->edges[0];
		dir = verts[ edges[abs(edgeNum)].v[ INT32_SIGNBITSET(edgeNum) ] ] - projectionOrigin;
		if ( dir * poly->normal < 0.0f ) {
			for ( j = 0; j < poly->numEdges; j++ ) {
				edgeNum = poly->edges[j];
				edgeIsSilEdge[abs(edgeNum)] ^= 1;
			}
		}
	}

	return GetOrderedSilhouetteEdges( edgeIsSilEdge, silEdges );
}
/*
================
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();
		}
		common->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[INT32_SIGNBITSET( edgeNum )]].p * axis;
		}
		common->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 );
		}
	}
}
示例#11
0
/*
====================
idSurface_Polytope::SplitPolytope
====================
*/
int idSurface_Polytope::SplitPolytope( const idPlane &plane, const float epsilon, idSurface_Polytope **front, idSurface_Polytope **back ) const {
	int side, i, j, s, v0, v1, v2, edgeNum;
	idSurface *surface[2];
	idSurface_Polytope *polytopeSurfaces[2], *surf;
	int *onPlaneEdges[2];

	onPlaneEdges[0] = (int *) _alloca( indexes.Num() / 3 * sizeof( int ) );
	onPlaneEdges[1] = (int *) _alloca( indexes.Num() / 3 * sizeof( int ) );

	side = Split( plane, epsilon, &surface[0], &surface[1], onPlaneEdges[0], onPlaneEdges[1] );

	*front = polytopeSurfaces[0] = new (TAG_IDLIB_SURFACE) idSurface_Polytope;
	*back = polytopeSurfaces[1] = new (TAG_IDLIB_SURFACE) idSurface_Polytope;

	for ( s = 0; s < 2; s++ ) {
		if ( surface[s] ) {
			polytopeSurfaces[s] = new idSurface_Polytope( *surface[s] );
			delete surface[s];
			surface[s] = NULL;
		}
	}

	*front = polytopeSurfaces[0];
	*back = polytopeSurfaces[1];

	if ( side != SIDE_CROSS ) {
		return side;
	}

	// add triangles to close off the front and back polytope
	for ( s = 0; s < 2; s++ ) {

		surf = polytopeSurfaces[s];

		edgeNum = surf->edgeIndexes[onPlaneEdges[s][0]];
		v0 = surf->edges[abs(edgeNum)].verts[INT32_SIGNBITSET(edgeNum)];
		v1 = surf->edges[abs(edgeNum)].verts[INT32_SIGNBITNOTSET(edgeNum)];

		for ( i = 1; onPlaneEdges[s][i] >= 0; i++ ) {
			for ( j = i+1; onPlaneEdges[s][j] >= 0; j++ ) {
				edgeNum = surf->edgeIndexes[onPlaneEdges[s][j]];
				if ( v1 == surf->edges[abs(edgeNum)].verts[INT32_SIGNBITSET(edgeNum)] ) {
					v1 = surf->edges[abs(edgeNum)].verts[INT32_SIGNBITNOTSET(edgeNum)];
					SwapValues( onPlaneEdges[s][i], onPlaneEdges[s][j] );
					break;
				}
			}
		}

		for ( i = 2; onPlaneEdges[s][i] >= 0; i++ ) {
			edgeNum = surf->edgeIndexes[onPlaneEdges[s][i]];
			v1 = surf->edges[abs(edgeNum)].verts[INT32_SIGNBITNOTSET(edgeNum)];
			v2 = surf->edges[abs(edgeNum)].verts[INT32_SIGNBITSET(edgeNum)];
			surf->indexes.Append( v0 );
			surf->indexes.Append( v1 );
			surf->indexes.Append( v2 );
		}

		surf->GenerateEdgeIndexes();
	}

	return side;
}
/*
================
idCollisionModelManagerLocal::RotateTrmEdgeThroughPolygon
================
*/
void idCollisionModelManagerLocal::RotateTrmEdgeThroughPolygon( cm_traceWork_t *tw, cm_polygon_t *poly, cm_trmEdge_t *trmEdge ) {
	int i, j, edgeNum;
	float f1, f2, startTan, dir, tanHalfAngle;
	cm_edge_t *edge;
	cm_vertex_t *v1, *v2;
	idVec3 collisionPoint, collisionNormal, origin, epsDir;
	idPluecker epsPl;
	idBounds bounds;

	// if the trm is convex and the rotation axis intersects the trm
	if ( tw->isConvex && tw->axisIntersectsTrm ) {
		// if both points are behind the polygon the edge cannot collide within a 180 degrees rotation
		if ( tw->vertices[trmEdge->vertexNum[0]].polygonSide & tw->vertices[trmEdge->vertexNum[1]].polygonSide ) {
			return;
		}
	}

	// if the trace model edge rotation bounds do not intersect the polygon bounds
	if ( !trmEdge->rotationBounds.IntersectsBounds( poly->bounds ) ) {
		return;
	}

	// edge rotation bounds should cross polygon plane
	if ( trmEdge->rotationBounds.PlaneSide( poly->plane ) != SIDE_CROSS ) {
		return;
	}

	// check edges for a collision
	for ( i = 0; i < poly->numEdges; i++ ) {
		edgeNum = poly->edges[i];
		edge = tw->model->edges + abs(edgeNum);

		// if this edge is already checked
		if ( edge->checkcount == idCollisionModelManagerLocal::checkCount ) {
			continue;
		}

		// can never collide with internal edges
		if ( edge->internal ) {
			continue;
		}

		v1 = tw->model->vertices + edge->vertexNum[INT32_SIGNBITSET( edgeNum )];
		v2 = tw->model->vertices + edge->vertexNum[INT32_SIGNBITNOTSET( edgeNum )];

		// edge bounds
		for ( j = 0; j < 3; j++ ) {
			if ( v1->p[j] > v2->p[j] ) {
				bounds[0][j] = v2->p[j];
				bounds[1][j] = v1->p[j];
			}
			else {
				bounds[0][j] = v1->p[j];
				bounds[1][j] = v2->p[j];
			}
		}

		// if the trace model edge rotation bounds do not intersect the polygon edge bounds
		if ( !trmEdge->rotationBounds.IntersectsBounds( bounds ) ) {
			continue;
		}

		f1 = trmEdge->pl.PermutedInnerProduct( tw->polygonEdgePlueckerCache[i] );

		// pluecker coordinate for epsilon expanded edge
		epsDir = edge->normal * (CM_CLIP_EPSILON+CM_PL_RANGE_EPSILON);
		epsPl.FromLine( tw->model->vertices[edge->vertexNum[0]].p + epsDir,
						tw->model->vertices[edge->vertexNum[1]].p + epsDir );

		f2 = trmEdge->pl.PermutedInnerProduct( epsPl );

		// if the rotating edge is inbetween the polygon edge and the epsilon expanded edge
		if ( ( f1 < 0.0f && f2 > 0.0f ) || ( f1 > 0.0f && f2 < 0.0f ) ) {

			if ( !EdgeFurthestFromEdge( tw, trmEdge->plzaxis, v1->p, v2->p, startTan, dir ) ) {
				continue;
			}

			if ( dir <= 0.0f ) {
				// moving towards the polygon edge so stop immediately
				tanHalfAngle = 0.0f;
			}
			else if ( idMath::Fabs( startTan ) >= tw->maxTan ) {
				// never going to get beyond the start tangent during the current rotation
				continue;
			}
			else {
				// collide with the epsilon expanded edge
				if ( !RotateEdgeThroughEdge(tw, trmEdge->plzaxis, v1->p + epsDir, v2->p + epsDir, idMath::Fabs( startTan ), tanHalfAngle ) ) {
					tanHalfAngle = startTan;
				}
			}
		}
		else {
			// collide with the epsilon expanded edge
			epsDir = edge->normal * CM_CLIP_EPSILON;
			if ( !RotateEdgeThroughEdge(tw, trmEdge->plzaxis, v1->p + epsDir, v2->p + epsDir, 0.0f, tanHalfAngle ) ) {
				continue;
			}
		}

		if ( idMath::Fabs( tanHalfAngle ) >= tw->maxTan ) {
			continue;
		}

		// check if the collision is between the edge bounds
		if ( !CollisionBetweenEdgeBounds( tw, trmEdge->start, trmEdge->end, v1->p, v2->p,
												tanHalfAngle, collisionPoint, collisionNormal ) ) {
			continue;
		}

		// allow rotation if the rotation axis goes through the collisionPoint
		origin = tw->origin + tw->axis * ( tw->axis * ( collisionPoint - tw->origin ) );
		if ( ( collisionPoint - origin ).LengthSqr() < ROTATION_AXIS_EPSILON * ROTATION_AXIS_EPSILON ) {
			continue;
		}

		// fill in trace structure
		tw->maxTan = idMath::Fabs( tanHalfAngle );
		tw->trace.c.normal = collisionNormal;
		tw->trace.c.normal.Normalize();
		tw->trace.c.dist = tw->trace.c.normal * v1->p;
		// make sure the collision plane faces the trace model
		if ( (tw->trace.c.normal * trmEdge->start) - tw->trace.c.dist < 0 ) {
			tw->trace.c.normal = -tw->trace.c.normal;
			tw->trace.c.dist = -tw->trace.c.dist;
		}
		tw->trace.c.contents = poly->contents;
		tw->trace.c.material = poly->material;
		tw->trace.c.type = CONTACT_EDGE;
		tw->trace.c.modelFeature = edgeNum;
		tw->trace.c.trmFeature = trmEdge - tw->edges;
		tw->trace.c.point = collisionPoint;
		// if no collision can be closer
		if ( tw->maxTan == 0.0f ) {
			break;
		}
	}
}
/*
================
idCollisionModelManagerLocal::Rotation180
================
*/
void idCollisionModelManagerLocal::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 &modelOrigin, const idMat3 &modelAxis ) {
	int i, j, edgeNum;
	float d, maxErr, initialTan;
	bool model_rotated, trm_rotated;
	idVec3 dir, dir1, dir2, tmp, vr, vup, org, at, bt;
	idMat3 invModelAxis, endAxis, tmpAxis;
	idRotation startRotation, endRotation;
	idPluecker plaxis;
	cm_trmPolygon_t *poly;
	cm_trmEdge_t *edge;
	cm_trmVertex_t *vert;
	ALIGN16( static cm_traceWork_t tw );

	if ( model < 0 || model > MAX_SUBMODELS || model > idCollisionModelManagerLocal::maxModels ) {
		common->Printf("idCollisionModelManagerLocal::Rotation180: invalid model handle\n");
		return;
	}
	if ( !idCollisionModelManagerLocal::models[model] ) {
		common->Printf("idCollisionModelManagerLocal::Rotation180: invalid model\n");
		return;
	}

	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 = true;
	tw.positionTest = false;
	tw.axisIntersectsTrm = false;
	tw.quickExit = false;
	tw.angle = endAngle - startAngle;
	assert( tw.angle > -180.0f && tw.angle < 180.0f );
	tw.maxTan = initialTan = idMath::Fabs( tan( ( idMath::PI / 360.0f ) * tw.angle ) );
	tw.model = idCollisionModelManagerLocal::models[model];
	tw.start = start - modelOrigin;
	// rotation axis, axis is assumed to be normalized
	tw.axis = axis;
//	assert( tw.axis[0] * tw.axis[0] + tw.axis[1] * tw.axis[1] + tw.axis[2] * tw.axis[2] > 0.99f );
	// rotation origin projected into rotation plane through tw.start
	tw.origin = rorg - modelOrigin;
	d = (tw.axis * tw.origin) - ( tw.axis * tw.start );
	tw.origin = tw.origin - d * tw.axis;
	// radius of rotation
	tw.radius = ( tw.start - tw.origin ).Length();
	// maximum error of the circle approximation traced through the axial BSP tree
	d = tw.radius * tw.radius - (CIRCLE_APPROXIMATION_LENGTH*CIRCLE_APPROXIMATION_LENGTH*0.25f);
	if ( d > 0.0f ) {
		maxErr = tw.radius - idMath::Sqrt( d );
	} else {
		maxErr = tw.radius;
	}

	model_rotated = modelAxis.IsRotated();
	if ( model_rotated ) {
		invModelAxis = modelAxis.Transpose();
		tw.axis *= invModelAxis;
		tw.origin *= invModelAxis;
	}

	startRotation.Set( tw.origin, tw.axis, startAngle );
	endRotation.Set( tw.origin, tw.axis, endAngle );

	// create matrix which rotates the rotation axis to the z-axis
	tw.axis.NormalVectors( vr, vup );
	tw.matrix[0][0] = vr[0];
	tw.matrix[1][0] = vr[1];
	tw.matrix[2][0] = vr[2];
	tw.matrix[0][1] = -vup[0];
	tw.matrix[1][1] = -vup[1];
	tw.matrix[2][1] = -vup[2];
	tw.matrix[0][2] = tw.axis[0];
	tw.matrix[1][2] = tw.axis[1];
	tw.matrix[2][2] = tw.axis[2];

	// if optimized point trace
	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 ) ) {

		if ( model_rotated ) {
			// rotate trace instead of model
			tw.start *= invModelAxis;
		}
		tw.end = tw.start;
		// if we start at a specific angle
		if ( startAngle != 0.0f ) {
			startRotation.RotatePoint( tw.start );
		}
		// calculate end position of rotation
		endRotation.RotatePoint( tw.end );

		// calculate rotation origin projected into rotation plane through the vertex
		tw.numVerts = 1;
		tw.vertices[0].p = tw.start;
		tw.vertices[0].endp = tw.end;
		tw.vertices[0].used = true;
		tw.vertices[0].rotationOrigin = tw.origin + tw.axis * ( tw.axis * ( tw.vertices[0].p - tw.origin ) );
		BoundsForRotation( tw.vertices[0].rotationOrigin, tw.axis, tw.start, tw.end, tw.vertices[0].rotationBounds );
		// rotation bounds
		tw.bounds = tw.vertices[0].rotationBounds;
		tw.numEdges = tw.numPolys = 0;

		// collision with single point
		tw.pointTrace = true;

		// extents is set to maximum error of the circle approximation traced through the axial BSP tree
		tw.extents[0] = tw.extents[1] = tw.extents[2] = maxErr + CM_BOX_EPSILON;

		// setup rotation heart plane
		tw.heartPlane1.SetNormal( tw.axis );
		tw.heartPlane1.FitThroughPoint( tw.start );
		tw.maxDistFromHeartPlane1 = CM_BOX_EPSILON;

		// trace through the model
		idCollisionModelManagerLocal::TraceThroughModel( &tw );

		// store results
		*results = tw.trace;
		results->endpos = start;
		if ( tw.maxTan == initialTan ) {
			results->fraction = 1.0f;
		} else {
			results->fraction = idMath::Fabs( atan( tw.maxTan ) * ( 2.0f * 180.0f / idMath::PI ) / tw.angle );
		}
		assert( results->fraction <= 1.0f );
		endRotation.Set( rorg, axis, startAngle + (endAngle-startAngle) * results->fraction );
		endRotation.RotatePoint( results->endpos );
		results->endAxis.Identity();

		if ( results->fraction < 1.0f ) {
			// rotate trace plane normal if there was a collision with a rotated model
			if ( model_rotated ) {
				results->c.normal *= modelAxis;
				results->c.point *= modelAxis;
			}
			results->c.point += modelOrigin;
			results->c.dist += modelOrigin * results->c.normal;
		}
		return;
	}

	tw.pointTrace = false;

	// 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++ ) {
			tw.vertices[i].p *= invModelAxis;
		}
	}
	for ( i = 0; i < tw.numVerts; i++ ) {
		tw.vertices[i].endp = tw.vertices[i].p;
	}
	// if we start at a specific angle
	if ( startAngle != 0.0f ) {
		for ( i = 0; i < tw.numVerts; i++ ) {
			startRotation.RotatePoint( tw.vertices[i].p );
		}
	}
	for ( i = 0; i < tw.numVerts; i++ ) {
		// end position of vertex
		endRotation.RotatePoint( tw.vertices[i].endp );
	}

	// add offset to start point
	if ( trm_rotated ) {
		tw.start += trm->offset * trmAxis;
	} else {
		tw.start += trm->offset;
	}
	// if the model is rotated
	if ( model_rotated ) {
		// rotate trace instead of model
		tw.start *= invModelAxis;
	}
	tw.end = tw.start;
	// if we start at a specific angle
	if ( startAngle != 0.0f ) {
		startRotation.RotatePoint( tw.start );
	}
	// calculate end position of rotation
	endRotation.RotatePoint( tw.end );

	// setup trm vertices
	for ( vert = tw.vertices, i = 0; i < tw.numVerts; i++, vert++ ) {
		// calculate rotation origin projected into rotation plane through the vertex
		vert->rotationOrigin = tw.origin + tw.axis * ( tw.axis * ( vert->p - tw.origin ) );
		// calculate rotation bounds for this vertex
		BoundsForRotation( vert->rotationOrigin, tw.axis, vert->p, vert->endp, vert->rotationBounds );
		// if the rotation axis goes through the vertex then the vertex is not used
		d = ( vert->p - vert->rotationOrigin ).LengthSqr();
		if ( d > ROTATION_AXIS_EPSILON * ROTATION_AXIS_EPSILON ) {
			vert->used = true;
		}
	}

	// setup trm edges
	for ( edge = tw.edges + 1, i = 1; i <= tw.numEdges; i++, edge++ ) {
		// if the rotation axis goes through both the edge vertices then the edge is not used
		if ( tw.vertices[edge->vertexNum[0]].used | tw.vertices[edge->vertexNum[1]].used ) {
			edge->used = true;
		}
		// edge start, end and pluecker coordinate
		edge->start = tw.vertices[edge->vertexNum[0]].p;
		edge->end = tw.vertices[edge->vertexNum[1]].p;
		edge->pl.FromLine( edge->start, edge->end );
		// pluecker coordinate for edge being rotated about the z-axis
		at = ( edge->start - tw.origin ) * tw.matrix;
		bt = ( edge->end - tw.origin ) * tw.matrix;
		edge->plzaxis.FromLine( at, bt );
		// get edge rotation bounds from the rotation bounds of both vertices
		edge->rotationBounds = tw.vertices[edge->vertexNum[0]].rotationBounds;
		edge->rotationBounds.AddBounds( tw.vertices[edge->vertexNum[1]].rotationBounds );
		// used to calculate if the rotation axis intersects the trm
		edge->bitNum = 0;
	}

	tw.bounds.Clear();

	// rotate trm polygon planes
	if ( trm_rotated & model_rotated ) {
		tmpAxis = trmAxis * invModelAxis;
		for ( poly = tw.polys, i = 0; i < tw.numPolys; i++, poly++ ) {
			poly->plane *= tmpAxis;
		}
	} else if ( trm_rotated ) {
		for ( poly = tw.polys, i = 0; i < tw.numPolys; i++, poly++ ) {
			poly->plane *= trmAxis;
		}
	} else if ( model_rotated ) {
		for ( poly = tw.polys, i = 0; i < tw.numPolys; i++, poly++ ) {
			poly->plane *= invModelAxis;
		}
	}

	// setup trm polygons
	for ( poly = tw.polys, i = 0; i < tw.numPolys; i++, poly++ ) {
		poly->used = true;
		// set trm polygon plane distance
		poly->plane.FitThroughPoint( tw.edges[abs(poly->edges[0])].start );
		// get polygon bounds from edge bounds
		poly->rotationBounds.Clear();
		for ( j = 0; j < poly->numEdges; j++ ) {
			// add edge rotation bounds to polygon rotation bounds
			edge = &tw.edges[abs( poly->edges[j] )];
			poly->rotationBounds.AddBounds( edge->rotationBounds );
		}
		// get trace bounds from polygon bounds
		tw.bounds.AddBounds( poly->rotationBounds );
	}

	// extents including the maximum error of the circle approximation traced through the axial BSP tree
	for ( i = 0; i < 3; i++ ) {
		tw.size[0][i] = tw.bounds[0][i] - tw.start[i];
		tw.size[1][i] = tw.bounds[1][i] - tw.start[i];
		if ( idMath::Fabs( tw.size[0][i] ) > idMath::Fabs( tw.size[1][i] ) ) {
			tw.extents[i] = idMath::Fabs( tw.size[0][i] ) + maxErr + CM_BOX_EPSILON;
		} else {
			tw.extents[i] = idMath::Fabs( tw.size[1][i] ) + maxErr + CM_BOX_EPSILON;
		}
	}

	// for back-face culling
	if ( tw.isConvex ) {
		if ( tw.start == tw.origin ) {
			tw.axisIntersectsTrm = true;
		} else {
			// determine if the rotation axis intersects the trm
			plaxis.FromRay( tw.origin, tw.axis );
			for ( poly = tw.polys, i = 0; i < tw.numPolys; i++, poly++ ) {
				// back face cull polygons
				if ( poly->plane.Normal() * tw.axis > 0.0f ) {
					continue;
				}
				// test if the axis goes between the polygon edges
				for ( j = 0; j < poly->numEdges; j++ ) {
					edgeNum = poly->edges[j];
					edge = tw.edges + abs( edgeNum );
					if ( ( edge->bitNum & 2 ) == 0 ) {
						d = plaxis.PermutedInnerProduct( edge->pl );
						edge->bitNum = ( ( d < 0.0f ) ? 1 : 0 ) | 2;
					}
					if ( ( edge->bitNum ^ INT32_SIGNBITSET( edgeNum ) ) & 1 ) {
						break;
					}
				}
				if ( j >= poly->numEdges ) {
					tw.axisIntersectsTrm = true;
					break;
				}
			}
		}
	}

	// setup rotation heart plane
	tw.heartPlane1.SetNormal( tw.axis );
	tw.heartPlane1.FitThroughPoint( tw.start );
	tw.maxDistFromHeartPlane1 = 0.0f;
	for ( i = 0; i < tw.numVerts; i++ ) {
		d = idMath::Fabs( tw.heartPlane1.Distance( tw.vertices[i].p ) );
		if ( d > tw.maxDistFromHeartPlane1 ) {
			tw.maxDistFromHeartPlane1 = d;
		}
	}
	tw.maxDistFromHeartPlane1 += CM_BOX_EPSILON;

	// inverse rotation to rotate model vertices towards trace model
	tw.modelVertexRotation.Set( tw.origin, tw.axis, -tw.angle );

	// trace through the model
	idCollisionModelManagerLocal::TraceThroughModel( &tw );

	// store results
	*results = tw.trace;
	results->endpos = start;
	if ( tw.maxTan == initialTan ) {
		results->fraction = 1.0f;
	} else {
		results->fraction = idMath::Fabs( atan( tw.maxTan ) * ( 2.0f * 180.0f / idMath::PI ) / tw.angle );
	}
	assert( results->fraction <= 1.0f );
	endRotation.Set( rorg, axis, startAngle + (endAngle-startAngle) * results->fraction );
	endRotation.RotatePoint( results->endpos );
	results->endAxis = trmAxis * endRotation.ToMat3();

	if ( results->fraction < 1.0f ) {
		// rotate trace plane normal if there was a collision with a rotated model
		if ( model_rotated ) {
			results->c.normal *= modelAxis;
			results->c.point *= modelAxis;
		}
		results->c.point += modelOrigin;
		results->c.dist += modelOrigin * results->c.normal;
	}
}
/*
================
idCollisionModelManagerLocal::RotateTrmThroughPolygon

  returns true if the polygon blocks the complete rotation
================
*/
bool idCollisionModelManagerLocal::RotateTrmThroughPolygon( cm_traceWork_t *tw, cm_polygon_t *p ) {
	int i, j, k, edgeNum;
	float d;
	cm_trmVertex_t *bv;
	cm_trmEdge_t *be;
	cm_trmPolygon_t *bp;
	cm_vertex_t *v;
	cm_edge_t *e;
	idVec3 *rotationOrigin;

	// 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 the trace bounds do not intersect the polygon bounds
	if ( !tw->bounds.IntersectsBounds( p->bounds ) ) {
		return false;
	}

	// back face culling
	if ( tw->isConvex ) {
		// if the center of the convex trm is behind the polygon plane
		if ( p->plane.Distance( tw->start ) < 0.0f ) {
			// if the rotation axis intersects the trace model
			if ( tw->axisIntersectsTrm ) {
				return false;
			}
			else {
				// if the direction of motion at the start and end position of the
				// center of the trm both go towards or away from the polygon plane
				// or if the intersections of the rotation axis with the expanded heart planes
				// are both in front of the polygon plane
			}
		}
	}

	// if the polygon is too far from the first heart plane
	d = p->bounds.PlaneDistance( tw->heartPlane1 );
	if ( idMath::Fabs(d) > tw->maxDistFromHeartPlane1 ) {
		return false;
	}

	// rotation 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;
	}

	for ( i = 0; i < tw->numVerts; i++ ) {
		bv = tw->vertices + i;
		// calculate polygon side this vertex is on
		d = p->plane.Distance( bv->p );
		bv->polygonSide = ( d < 0.0f );
	}

	for ( i = 0; i < p->numEdges; i++ ) {
		edgeNum = p->edges[i];
		e = tw->model->edges + abs(edgeNum);
		v = tw->model->vertices + e->vertexNum[INT32_SIGNBITSET( edgeNum )];

		// pluecker coordinate for edge
		tw->polygonEdgePlueckerCache[i].FromLine( tw->model->vertices[e->vertexNum[0]].p,
													tw->model->vertices[e->vertexNum[1]].p );

		// calculate rotation origin projected into rotation plane through the vertex
		tw->polygonRotationOriginCache[i] = tw->origin + tw->axis * ( tw->axis * ( v->p - tw->origin ) );
	}
	// copy first to last so we can easily cycle through
	tw->polygonRotationOriginCache[p->numEdges] = tw->polygonRotationOriginCache[0];

	// fast point rotation
	if ( tw->pointTrace ) {
		RotateTrmVertexThroughPolygon( tw, p, &tw->vertices[0], 0 );
	}
	else {
		// rotate trm vertices through polygon
		for ( i = 0; i < tw->numVerts; i++ ) {
			bv = tw->vertices + i;
			if ( bv->used ) {
				RotateTrmVertexThroughPolygon( tw, p, bv, i );
			}
		}

		// rotate trm edges through polygon
		for ( i = 1; i <= tw->numEdges; i++ ) {
			be = tw->edges + i;
			if ( be->used ) {
				RotateTrmEdgeThroughPolygon( tw, p, be );
			}
		}

		// rotate all polygon vertices through the trm
		for ( i = 0; i < p->numEdges; i++ ) {
			edgeNum = p->edges[i];
			e = tw->model->edges + abs(edgeNum);

			if ( e->checkcount == idCollisionModelManagerLocal::checkCount ) {
				continue;
			}
			// set edge check count
			e->checkcount = idCollisionModelManagerLocal::checkCount;
			// can never collide with internal edges
			if ( e->internal ) {
				continue;
			}
			// got to check both vertices because we skip internal edges
			for ( k = 0; k < 2; k++ ) {

				v = tw->model->vertices + e->vertexNum[k ^ INT32_SIGNBITSET( edgeNum )];

				// if this vertex is already checked
				if ( v->checkcount == idCollisionModelManagerLocal::checkCount ) {
					continue;
				}
				// set vertex check count
				v->checkcount = idCollisionModelManagerLocal::checkCount;

				// if the vertex is outside the trm rotation bounds
				if ( !tw->bounds.ContainsPoint( v->p ) ) {
					continue;
				}

				rotationOrigin = &tw->polygonRotationOriginCache[i+k];

				for ( j = 0; j < tw->numPolys; j++ ) {
					bp = tw->polys + j;
					if ( bp->used ) {
						RotateVertexThroughTrmPolygon( tw, bp, p, v, *rotationOrigin );
					}
				}
			}
		}
	}

	return ( tw->maxTan == 0.0f );
}
示例#15
0
/*
============
idTraceModel::SetupDodecahedron
============
*/
void idTraceModel::SetupDodecahedron( const idBounds &dodBounds ) {
	int i, e0, e1, e2, e3, v0, v1, v2, v3, v4;
	float s, d;
	idVec3 a, b, c;

	if ( type != TRM_DODECAHEDRON ) {
		InitDodecahedron();
	}

	a[0] = a[1] = a[2] = 0.5773502691896257f; // 1.0f / ( 3.0f ) ^ 0.5f;
	b[0] = b[1] = b[2] = 0.3568220897730899f; // ( ( 3.0f - ( 5.0f ) ^ 0.5f ) / 6.0f ) ^ 0.5f;
	c[0] = c[1] = c[2] = 0.9341723589627156f; // ( ( 3.0f + ( 5.0f ) ^ 0.5f ) / 6.0f ) ^ 0.5f;
	d = 0.5f / c[0];
	s = ( dodBounds[1][0] - dodBounds[0][0] ) * d;
	a[0] *= s;
	b[0] *= s;
	c[0] *= s;
	s = ( dodBounds[1][1] - dodBounds[0][1] ) * d;
	a[1] *= s;
	b[1] *= s;
	c[1] *= s;
	s = ( dodBounds[1][2] - dodBounds[0][2] ) * d;
	a[2] *= s;
	b[2] *= s;
	c[2] *= s;

	offset = ( dodBounds[0] + dodBounds[1] ) * 0.5f;

	// set vertices
	verts[ 0].Set( offset.x + a[0], offset.y + a[1], offset.z + a[2] );
	verts[ 1].Set( offset.x + a[0], offset.y + a[1], offset.z - a[2] );
	verts[ 2].Set( offset.x + a[0], offset.y - a[1], offset.z + a[2] );
	verts[ 3].Set( offset.x + a[0], offset.y - a[1], offset.z - a[2] );
	verts[ 4].Set( offset.x - a[0], offset.y + a[1], offset.z + a[2] );
	verts[ 5].Set( offset.x - a[0], offset.y + a[1], offset.z - a[2] );
	verts[ 6].Set( offset.x - a[0], offset.y - a[1], offset.z + a[2] );
	verts[ 7].Set( offset.x - a[0], offset.y - a[1], offset.z - a[2] );
	verts[ 8].Set( offset.x + b[0], offset.y + c[1], offset.z        );
	verts[ 9].Set( offset.x - b[0], offset.y + c[1], offset.z        );
	verts[10].Set( offset.x + b[0], offset.y - c[1], offset.z        );
	verts[11].Set( offset.x - b[0], offset.y - c[1], offset.z        );
	verts[12].Set( offset.x + c[0], offset.y       , offset.z + b[2] );
	verts[13].Set( offset.x + c[0], offset.y       , offset.z - b[2] );
	verts[14].Set( offset.x - c[0], offset.y       , offset.z + b[2] );
	verts[15].Set( offset.x - c[0], offset.y       , offset.z - b[2] );
	verts[16].Set( offset.x       , offset.y + b[1], offset.z + c[2] );
	verts[17].Set( offset.x       , offset.y - b[1], offset.z + c[2] );
	verts[18].Set( offset.x       , offset.y + b[1], offset.z - c[2] );
	verts[19].Set( offset.x       , offset.y - b[1], offset.z - c[2] );

	// set polygons
	for ( i = 0; i < numPolys; i++ ) {
		e0 = polys[i].edges[0];
		e1 = polys[i].edges[1];
		e2 = polys[i].edges[2];
		e3 = polys[i].edges[3];
		v0 = edges[abs(e0)].v[INT32_SIGNBITSET(e0)];
		v1 = edges[abs(e0)].v[INT32_SIGNBITNOTSET(e0)];
		v2 = edges[abs(e1)].v[INT32_SIGNBITNOTSET(e1)];
		v3 = edges[abs(e2)].v[INT32_SIGNBITNOTSET(e2)];
		v4 = edges[abs(e3)].v[INT32_SIGNBITNOTSET(e3)];
		// polygon plane
		polys[i].normal = ( verts[v1] - verts[v0] ).Cross( verts[v2] - verts[v0] );
		polys[i].normal.Normalize();
		polys[i].dist = polys[i].normal * verts[v0];
		// polygon bounds
		polys[i].bounds[0] = polys[i].bounds[1] = verts[v0];
		polys[i].bounds.AddPoint( verts[v1] );
		polys[i].bounds.AddPoint( verts[v2] );
		polys[i].bounds.AddPoint( verts[v3] );
		polys[i].bounds.AddPoint( verts[v4] );
	}

	// trm bounds
	bounds = dodBounds;

	GenerateEdgeNormals();
}