void G2API_CollisionDetect(CollisionRecord_t *collRecMap, CGhoul2Info_v &ghoul2, const vec3_t angles, const vec3_t position, int frameNumber, int entNum, vec3_t rayStart, vec3_t rayEnd, vec3_t scale, CMiniHeap *G2VertSpace, int traceFlags, int useLod) { if ((int)&ghoul2) { vec3_t transRayStart, transRayEnd; // make sure we have transformed the whole skeletons for each model G2_ConstructGhoulSkeleton(ghoul2, frameNumber, NULL, true, angles, position, scale, false); // pre generate the world matrix - used to transform the incoming ray G2_GenerateWorldMatrix(angles, position); // now having done that, time to build the model G2_TransformModel(ghoul2, frameNumber, scale, G2VertSpace, useLod); // model is built. Lets check to see if any triangles are actually hit. // first up, translate the ray to model space TransformAndTranslatePoint(rayStart, transRayStart, &worldMatrixInv); TransformAndTranslatePoint(rayEnd, transRayEnd, &worldMatrixInv); // now walk each model and check the ray against each poly - sigh, this is SO expensive. I wish there was a better way to do this. G2_TraceModels(ghoul2, transRayStart, transRayEnd, collRecMap, entNum, traceFlags, useLod); // now sort the resulting array of collision records so they are distance ordered qsort( collRecMap, MAX_G2_COLLISIONS, sizeof( CCollisionRecord ), QsortDistance ); } }
void G2API_AddSkinGore(CGhoul2Info_v &ghoul2,SSkinGoreData &gore) { if (VectorLength(gore.rayDirection)<.1f) { assert(0); // can't add gore without a shot direction return; } // make sure we have transformed the whole skeletons for each model G2_ConstructGhoulSkeleton(ghoul2, gore.currentTime, NULL, true, gore.angles, gore.position, gore.scale, false); // pre generate the world matrix - used to transform the incoming ray G2_GenerateWorldMatrix(gore.angles, gore.position); // first up, translate the ray to model space vec3_t transRayDirection, transHitLocation; TransformAndTranslatePoint(gore.hitLocation, transHitLocation, &worldMatrixInv); TransformPoint(gore.rayDirection, transRayDirection, &worldMatrixInv); int lod; ResetGoreTag(); for (lod=0;lod<4;lod++) { // now having done that, time to build the model // FIXME: where does G2VertSpaceServer come from? // G2_TransformModel(ghoul2, gore.currentTime, gore.scale,G2VertSpaceServer, lod,true); // now walk each model and compute new texture coordinates G2_TraceModels(ghoul2, transHitLocation, transRayDirection, 0, gore.entNum, 0, lod); } }
void G2API_CollisionDetect(CollisionRecord_t *collRecMap, g2handle_t g2h, const vec3_t angles, const vec3_t position, int frameNumber, int entNum, const vec3_t rayStart, const vec3_t rayEnd, const vec3_t scale, CMiniHeap *G2VertSpace, int traceFlags, int useLod, float fRadius) { CGhoul2Info_v *ghoul2 = G2API_GetGhoul2Model(g2h); if (ghoul2) { vec3_t transRayStart, transRayEnd; // make sure we have transformed the whole skeletons for each model G2_ConstructGhoulSkeleton(*ghoul2, frameNumber, NULL, true, angles, position, scale, false); // pre generate the world matrix - used to transform the incoming ray G2_GenerateWorldMatrix(angles, position); #ifdef G2_COLLISION_ENABLED G2VertSpace->ResetHeap(); #endif // now having done that, time to build the model G2_TransformModel(*ghoul2, frameNumber, scale, G2VertSpace, useLod); // model is built. Lets check to see if any triangles are actually hit. // first up, translate the ray to model space TransformAndTranslatePoint(rayStart, transRayStart, &worldMatrixInv); TransformAndTranslatePoint(rayEnd, transRayEnd, &worldMatrixInv); // now walk each model and check the ray against each poly - sigh, this is SO expensive. I wish there was a better way to do this. G2_TraceModels(*ghoul2, transRayStart, transRayEnd, collRecMap, entNum, traceFlags, useLod, fRadius); #ifdef G2_COLLISION_ENABLED int i; for ( i = 0; i < MAX_G2_COLLISIONS && collRecMap[i].mEntityNum != -1; i ++ ); // now sort the resulting array of collision records so they are distance ordered qsort( collRecMap, i, sizeof( CCollisionRecord ), QsortDistance ); #else // now sort the resulting array of collision records so they are distance ordered qsort( collRecMap, MAX_G2_COLLISIONS, sizeof( CCollisionRecord ), QsortDistance ); #endif } }
// now we're at poly level, check each model space transformed poly against the model world transfomed ray static bool G2_RadiusTracePolys( const mdxmSurface_t *surface, CTraceSurface &TS ) { int i,j; vec3_t basis1; vec3_t basis2; vec3_t taxis; vec3_t saxis; basis2[0]=0.0f; basis2[1]=0.0f; basis2[2]=1.0f; vec3_t v3RayDir; VectorSubtract(TS.rayEnd, TS.rayStart, v3RayDir); CrossProduct(v3RayDir,basis2,basis1); if (DotProduct(basis1,basis1)<.1f) { basis2[0]=0.0f; basis2[1]=1.0f; basis2[2]=0.0f; CrossProduct(v3RayDir,basis2,basis1); } CrossProduct(v3RayDir,basis1,basis2); // Give me a shot direction not a bunch of zeros :) -Gil // assert(DotProduct(basis1,basis1)>.0001f); // assert(DotProduct(basis2,basis2)>.0001f); VectorNormalize(basis1); VectorNormalize(basis2); const float c=cosf(0);//theta const float s=sinf(0);//theta VectorScale(basis1, 0.5f * c / TS.m_fRadius,taxis); VectorMA(taxis, 0.5f * s / TS.m_fRadius,basis2,taxis); VectorScale(basis1,-0.5f * s /TS.m_fRadius,saxis); VectorMA( saxis, 0.5f * c /TS.m_fRadius,basis2,saxis); const float * const verts = (float *)TS.TransformedVertsArray[surface->thisSurfaceIndex]; const int numVerts = surface->numVerts; int flags=63; //rayDir/=lengthSquared(raydir); const float f = VectorLengthSquared(v3RayDir); v3RayDir[0]/=f; v3RayDir[1]/=f; v3RayDir[2]/=f; for ( j = 0; j < numVerts; j++ ) { const int pos=j*5; vec3_t delta; delta[0]=verts[pos+0]-TS.rayStart[0]; delta[1]=verts[pos+1]-TS.rayStart[1]; delta[2]=verts[pos+2]-TS.rayStart[2]; const float s=DotProduct(delta,saxis)+0.5f; const float t=DotProduct(delta,taxis)+0.5f; const float u=DotProduct(delta,v3RayDir); int vflags=0; if (s>0) { vflags|=1; } if (s<1) { vflags|=2; } if (t>0) { vflags|=4; } if (t<1) { vflags|=8; } if (u>0) { vflags|=16; } if (u<1) { vflags|=32; } vflags=(~vflags); flags&=vflags; GoreVerts[j].flags=vflags; } if (flags) { return false; // completely off the gore splotch (so presumably hit nothing? -Ste) } const int numTris = surface->numTriangles; const mdxmTriangle_t * const tris = (mdxmTriangle_t *) ((byte *)surface + surface->ofsTriangles); for ( j = 0; j < numTris; j++ ) { assert(tris[j].indexes[0]>=0&&tris[j].indexes[0]<numVerts); assert(tris[j].indexes[1]>=0&&tris[j].indexes[1]<numVerts); assert(tris[j].indexes[2]>=0&&tris[j].indexes[2]<numVerts); flags=63& GoreVerts[tris[j].indexes[0]].flags& GoreVerts[tris[j].indexes[1]].flags& GoreVerts[tris[j].indexes[2]].flags; if (flags) { continue; } else { // we hit a triangle, so init a collision record... // for (i=0; i<MAX_G2_COLLISIONS;i++) { if (TS.collRecMap[i].mEntityNum == -1) { CCollisionRecord &newCol = TS.collRecMap[i]; newCol.mPolyIndex = j; newCol.mEntityNum = TS.entNum; newCol.mSurfaceIndex = surface->thisSurfaceIndex; newCol.mModelIndex = TS.modelIndex; // if (face>0) // { newCol.mFlags = G2_FRONTFACE; // } // else // { // newCol.mFlags = G2_BACKFACE; // } //get normal from triangle const float *A = &verts[(tris[j].indexes[0] * 5)]; const float *B = &verts[(tris[j].indexes[1] * 5)]; const float *C = &verts[(tris[j].indexes[2] * 5)]; vec3_t normal; vec3_t edgeAC, edgeBA; VectorSubtract(C, A, edgeAC); VectorSubtract(B, A, edgeBA); CrossProduct(edgeBA, edgeAC, normal); // transform normal (but don't translate) into world angles TransformPoint(normal, newCol.mCollisionNormal, &worldMatrix); VectorNormalize(newCol.mCollisionNormal); newCol.mMaterial = newCol.mLocation = 0; // exit now if we should if (TS.eG2TraceType == G2_RETURNONHIT) { TS.hitOne = true; return true; } //i don't know the hitPoint, but let's just assume it's the first vert for now... const float *hitPoint = A; vec3_t distVect; VectorSubtract(hitPoint, TS.rayStart, distVect); newCol.mDistance = VectorLength(distVect); // put the hit point back into world space TransformAndTranslatePoint(hitPoint, newCol.mCollisionPosition, &worldMatrix); newCol.mBarycentricI = newCol.mBarycentricJ = 0.0f; break; } } if (i==MAX_G2_COLLISIONS) { //assert(i!=MAX_G2_COLLISIONS); // run out of collision record space - happens OFTEN TS.hitOne = true; //force stop recursion return true; // return true to avoid wasting further time, but no hit will result without a record } } } return false; }
// now we're at poly level, check each model space transformed poly against the model world transfomed ray static bool G2_TracePolys(const mdxmSurface_t *surface, const mdxmSurfHierarchy_t *surfInfo, CTraceSurface &TS) { int i, j, numTris; // whip through and actually transform each vertex const mdxmTriangle_t *tris = (mdxmTriangle_t *) ((byte *)surface + surface->ofsTriangles); const float *verts = (float *)TS.TransformedVertsArray[surface->thisSurfaceIndex]; numTris = surface->numTriangles; for ( j = 0; j < numTris; j++ ) { float face; vec3_t hitPoint, normal; // determine actual coords for this triangle const float *point1 = &verts[(tris[j].indexes[0] * 5)]; const float *point2 = &verts[(tris[j].indexes[1] * 5)]; const float *point3 = &verts[(tris[j].indexes[2] * 5)]; // did we hit it? if (G2_SegmentTriangleTest(TS.rayStart, TS.rayEnd, point1, point2, point3, qtrue, qtrue, hitPoint, normal, &face)) { // find space in the collision records for this record for (i=0; i<MAX_G2_COLLISIONS;i++) { if (TS.collRecMap[i].mEntityNum == -1) { CCollisionRecord &newCol = TS.collRecMap[i]; vec3_t distVect; float x_pos = 0, y_pos = 0; newCol.mPolyIndex = j; newCol.mEntityNum = TS.entNum; newCol.mSurfaceIndex = surface->thisSurfaceIndex; newCol.mModelIndex = TS.modelIndex; if (face>0) { newCol.mFlags = G2_FRONTFACE; } else { newCol.mFlags = G2_BACKFACE; } VectorSubtract(hitPoint, TS.rayStart, distVect); newCol.mDistance = VectorLength(distVect); // put the hit point back into world space TransformAndTranslatePoint(hitPoint, newCol.mCollisionPosition, &worldMatrix); // transform normal (but don't translate) into world angles TransformPoint(normal, newCol.mCollisionNormal, &worldMatrix); VectorNormalize(newCol.mCollisionNormal); newCol.mMaterial = newCol.mLocation = 0; // Determine our location within the texture, and barycentric coordinates G2_BuildHitPointST(point1, point1[3], point1[4], point2, point2[3], point2[4], point3, point3[3], point3[4], hitPoint, &x_pos, &y_pos,newCol.mBarycentricI,newCol.mBarycentricJ); /* const shader_t *shader = 0; // now, we know what surface this hit belongs to, we need to go get the shader handle so we can get the correct hit location and hit material info if ( cust_shader ) { shader = cust_shader; } else if ( skin ) { int j; // match the surface name to something in the skin file shader = tr.defaultShader; for ( j = 0 ; j < skin->numSurfaces ; j++ ) { // the names have both been lowercased if ( !strcmp( skin->surfaces[j]->name, surfInfo->name ) ) { shader = skin->surfaces[j]->shader; break; } } } else { shader = R_GetShaderByHandle( surfInfo->shaderIndex ); } // do we even care to decide what the hit or location area's are? If we don't have them in the shader there is little point if ((shader->hitLocation) || (shader->hitMaterial)) { // ok, we have a floating point position. - determine location in data we need to look at if (shader->hitLocation) { newCol.mLocation = *(hitMatReg[shader->hitLocation].loc + ((int)(y_pos * hitMatReg[shader->hitLocation].height) * hitMatReg[shader->hitLocation].width) + ((int)(x_pos * hitMatReg[shader->hitLocation].width))); Com_Printf("G2_TracePolys hit location: %d\n", newCol.mLocation); } if (shader->hitMaterial) { newCol.mMaterial = *(hitMatReg[shader->hitMaterial].loc + ((int)(y_pos * hitMatReg[shader->hitMaterial].height) * hitMatReg[shader->hitMaterial].width) + ((int)(x_pos * hitMatReg[shader->hitMaterial].width))); } } */ // exit now if we should if (TS.eG2TraceType == G2_RETURNONHIT) { TS.hitOne = true; return true; } break; } } if (i==MAX_G2_COLLISIONS) { assert(i!=MAX_G2_COLLISIONS); // run out of collision record space - will probalbly never happen TS.hitOne = true; //force stop recursion return true; // return true to avoid wasting further time, but no hit will result without a record } } } return false; }