/* ================ idCollisionModelManagerLocal::RotateVertexThroughTrmPolygon ================ */ void idCollisionModelManagerLocal::RotateVertexThroughTrmPolygon( cm_traceWork_t *tw, cm_trmPolygon_t *trmpoly, cm_polygon_t *poly, cm_vertex_t *v, idVec3 &rotationOrigin ) { int i, edgeNum; float tanHalfAngle; idVec3 dir, endp, endDir, collisionPoint; idPluecker pl; cm_trmEdge_t *edge; // if the polygon vertex is behind the trm plane it cannot collide with the trm polygon within a 180 degrees rotation if( tw->isConvex && tw->axisIntersectsTrm && trmpoly->plane.Distance( v->p ) < 0.0f ) { return; } // if the model vertex is outside the trm polygon rotation bounds if( !trmpoly->rotationBounds.ContainsPoint( v->p ) ) { return; } // if the rotation axis goes through the polygon vertex dir = v->p - rotationOrigin; if( dir * dir < ROTATION_AXIS_EPSILON * ROTATION_AXIS_EPSILON ) { return; } // calculate vertex end position endp = v->p; tw->modelVertexRotation.RotatePoint( endp ); // rotate the vertex through the epsilon plane if( !RotatePointThroughEpsilonPlane( tw, v->p, endp, trmpoly->plane, -tw->angle, rotationOrigin, tanHalfAngle, collisionPoint, endDir ) ) { return; } if( idMath::Fabs( tanHalfAngle ) < tw->maxTan ) { // verify if 'collisionPoint' moving along 'endDir' moves between polygon edges pl.FromRay( collisionPoint, endDir ); for( i = 0; i < trmpoly->numEdges; i++ ) { edgeNum = trmpoly->edges[i]; edge = tw->edges + abs( edgeNum ); if( edgeNum < 0 ) { if( pl.PermutedInnerProduct( edge->pl ) > 0.0f ) { return; } } else { if( pl.PermutedInnerProduct( edge->pl ) < 0.0f ) { return; } } } tw->maxTan = idMath::Fabs( tanHalfAngle ); // collision plane is the flipped trm polygon plane tw->trace.c.normal = -trmpoly->plane.Normal(); tw->trace.c.dist = tw->trace.c.normal * v->p; tw->trace.c.contents = poly->contents; tw->trace.c.material = poly->material; tw->trace.c.type = CONTACT_MODELVERTEX; tw->trace.c.modelFeature = v - tw->model->vertices; tw->trace.c.trmFeature = trmpoly - tw->polys; tw->trace.c.point = v->p; } }
/* ================ idCollisionModelManagerLocal::RotateTrmVertexThroughPolygon ================ */ void idCollisionModelManagerLocal::RotateTrmVertexThroughPolygon( cm_traceWork_t *tw, cm_polygon_t *poly, cm_trmVertex_t *v, int vertexNum ) { int i; float tanHalfAngle; idVec3 endDir, collisionPoint; idPluecker pl; // if the trm vertex is behind the polygon plane it cannot collide with the polygon within a 180 degrees rotation if ( tw->isConvex && tw->axisIntersectsTrm && v->polygonSide ) { return; } // if the trace model vertex rotation bounds do not intersect the polygon bounds if ( !v->rotationBounds.IntersectsBounds( poly->bounds ) ) { return; } // vertex rotation bounds should cross polygon plane if ( v->rotationBounds.PlaneSide( poly->plane ) != SIDE_CROSS ) { return; } // rotate the vertex through the epsilon plane if ( !RotatePointThroughEpsilonPlane( tw, v->p, v->endp, poly->plane, tw->angle, v->rotationOrigin, tanHalfAngle, collisionPoint, endDir ) ) { return; } if ( idMath::Fabs( tanHalfAngle ) < tw->maxTan ) { // verify if 'collisionPoint' moving along 'endDir' moves between polygon edges pl.FromRay( collisionPoint, endDir ); for ( i = 0; i < poly->numEdges; i++ ) { if ( poly->edges[i] < 0 ) { if ( pl.PermutedInnerProduct( tw->polygonEdgePlueckerCache[i] ) > 0.0f ) { return; } } else { if ( pl.PermutedInnerProduct( tw->polygonEdgePlueckerCache[i] ) < 0.0f ) { return; } } } tw->maxTan = idMath::Fabs( tanHalfAngle ); // collision plane is the polygon plane tw->trace.c.normal = poly->plane.Normal(); tw->trace.c.dist = poly->plane.Dist(); tw->trace.c.contents = poly->contents; tw->trace.c.material = poly->material; tw->trace.c.type = CONTACT_TRMVERTEX; tw->trace.c.modelFeature = *reinterpret_cast<int *>(&poly); tw->trace.c.trmFeature = v - tw->vertices; tw->trace.c.point = collisionPoint; } }