bool MFCollision_RaySphereTest(const MFVector& rayPos, const MFVector& rayDir, const MFVector& spherePos, float radius, MFRayIntersectionResult *pResult) { MFVector diff = rayPos - spherePos; // calcuate the coefficients float a = rayDir.MagSquared3(); float b = (2.0f*rayDir).Dot3(diff); float c = diff.MagSquared3() - radius*radius; // calculate the stuff under the root sign, if it's negative no (real) solutions exist float d = b*b - 4.0f*a*c; if(d < 0.0f) // this means ray misses cylinder return false; float root = MFSqrt(d); float rcp2a = MFRcp(2.0f*a); float t1 = (-b - root)*rcp2a; float t2 = (-b + root)*rcp2a; if(t2 < 0.0f || t1 > 1.0f) return false; if(pResult) { pResult->time = MFMax(t1, 0.0f); pResult->surfaceNormal.Mad3(rayDir, pResult->time, diff); pResult->surfaceNormal.Normalise3(); } return true; }
MFQuaternion MFMatrix::GetRotationQ() const { MFQuaternion q; float trace = m[0] + m[5] + m[10] + 1.0f; if(trace > 0.0f) { float s = MFRSqrt(trace) * 0.5f; q.w = 0.25f / s; q.x = (m[9] - m[6]) * s; q.y = (m[2] - m[8]) * s; q.z = (m[4] - m[1]) * s; } else { if(m[0] > m[5] && m[0] > m[10]) { float s = 2.0f * MFSqrt(1.0f + m[0] - m[5] - m[10]); float invS = 1.0f / s; q.x = 0.25f * s; q.y = (m[1] + m[4]) * invS; q.z = (m[2] + m[8]) * invS; q.w = (m[6] - m[9]) * invS; } else if(m[5] > m[10]) { float s = 2.0f * MFSqrt(1.0f + m[5] - m[0] - m[10]); float invS = 1.0f / s; q.x = (m[1] + m[4]) * invS; q.y = 0.25f * s; q.z = (m[6] + m[9]) * invS; q.w = (m[2] - m[8]) * invS; } else { float s = 2.0f * MFSqrt(1.0f + m[10] - m[0] - m[5]); float invS = 1.0f / s; q.x = (m[2] + m[8] ) * invS; q.y = (m[6] + m[9] ) * invS; q.z = 0.25f * s; q.w = (m[1] - m[4] ) * invS; } } return q; }
void MFParticleSystem_DrawRotating(MFParticleSystem *pParticleSystem, const MFMatrix <v) { int numParticles = pParticleSystem->particles.GetLength(); if(!numParticles) return; float fadeStart = pParticleSystem->params.life - pParticleSystem->params.fadeDelay; MFMaterial_SetMaterial(pParticleSystem->pMaterial); MFPrimitive(PT_TriList, 0); MFBegin(numParticles * 6); MFParticle **ppI = pParticleSystem->particles.Begin(); while(*ppI) { MFParticle *pParticle = *ppI; float dt = MFSystem_TimeDelta(); pParticle->rot += pParticleSystem->params.rotationRate * dt; pParticle->size += pParticleSystem->params.scaleRate * dt; pParticle->velocity += pParticleSystem->params.force * dt; pParticle->pos += pParticle->velocity * dt; float t = pParticle->size * 0.5f; float rad = MFSqrt(t*t*2); float xoff = MFCos(-pParticle->rot + 0.7853981f)*rad; float yoff = MFSin(-pParticle->rot + 0.7853981f)*rad; float alpha = MFMin(pParticle->life / fadeStart, 1.0f); MFVector pos = ApplyMatrixH(pParticle->pos, ltv); MFSetColourV(MakeVector(pParticle->colour, pParticle->colour.w * alpha)); MFSetTexCoord1(1, 0); MFSetPosition(pos.x + xoff, pos.y + yoff, pos.z); MFSetTexCoord1(0, 1); MFSetPosition(pos.x - xoff, pos.y - yoff, pos.z); MFSetTexCoord1(0, 0); MFSetPosition(pos.x - yoff, pos.y + xoff, pos.z); MFSetTexCoord1(1, 0); MFSetPosition(pos.x + xoff, pos.y + yoff, pos.z); MFSetTexCoord1(1, 1); MFSetPosition(pos.x + yoff, pos.y - xoff, pos.z); MFSetTexCoord1(0, 1); MFSetPosition(pos.x - xoff, pos.y - yoff, pos.z); pParticle->life -= dt; if(pParticle->life < 0.0f) pParticleSystem->particles.Destroy(ppI); ppI++; } MFEnd(); }
void MFInputInternal_ApplySphericalDeadZone(float *pX, float *pY) { float length = *pX**pX + *pY**pY; if(length) { length = MFSqrt(length); float scale = 1.0f / length * MFClamp(0.0f, (length - gGamepadDeadZone) / (1.0f - gGamepadDeadZone), 1.0f); *pX *= scale; *pY *= scale; } }
void MFCollision_CalculateDynamicBoundingVolume(MFCollisionItem *pItem) { switch(pItem->pTemplate->type) { case MFCT_Mesh: { MFCollisionMesh *pMesh = (MFCollisionMesh*)pItem->pTemplate->pCollisionTemplateData; MFBoundingVolume &vol = pItem->pTemplate->boundingVolume; vol.min = vol.max = vol.boundingSphere = MakeVector(pMesh->pTriangles[0].verts[0], 0.0f); for(int a=0; a<pMesh->numTris; a++) { MFCollisionTriangle &tri = pMesh->pTriangles[a]; for(int b=0; b<3; b++) { vol.min = MFMin(vol.min, tri.verts[b]); vol.max = MFMin(vol.max, tri.verts[b]); vol.min.w = vol.max.w = 0.0f; // if point is outside bounding sphere MFVector diff = tri.verts[b] - vol.boundingSphere; float mag = diff.MagSquared3(); if(mag > vol.boundingSphere.w*vol.boundingSphere.w) { // fit sphere to include point mag = MFSqrt(mag) - vol.boundingSphere.w; mag *= 0.5f; diff.Normalise3(); vol.boundingSphere.Mad3(diff, mag, vol.boundingSphere); vol.boundingSphere.w += mag; } } } break; } default: MFDebug_Assert(false, "Invalid item type"); } }
bool MFCollision_RayCylinderTest(const MFVector& rayPos, const MFVector& rayDir, const MFVector& cylinderPos, const MFVector& cylinderDir, float cylinderRadius, bool capped, MFRayIntersectionResult *pResult, float *pCylinderTime) { MFVector local = rayPos - cylinderPos; float rayD = rayDir.Dot3(cylinderDir); float T0 = local.Dot3(cylinderDir); // bring T0 into 0.0-1.0 range float invMagSq = MFRcp(cylinderDir.MagSquared3()); rayD *= invMagSq; T0 *= invMagSq; // calculate some intermediate vectors MFVector v1 = rayDir - rayD*cylinderDir; MFVector v2 = local - T0*cylinderDir; // calculate coeff in quadratic formula float a = v1.MagSquared3(); float b = (2.0f*v1).Dot3(v2); float c = v2.MagSquared3() - cylinderRadius*cylinderRadius; // calculate the stuff under the root sign, if it's negative no (real) solutions exist float d = b*b - 4.0f*a*c; if(d < 0.0f) // this means ray misses cylinder return false; float root = MFSqrt(d); float rcp2a = MFRcp(2.0f*a); float t1 = (-b - root)*rcp2a; float t2 = (-b + root)*rcp2a; if(t1 > 1.0f || t2 < 0.0f) return false; // the cylinder is beyond the ray.. if(capped || pCylinderTime || pResult) { float t = MFMax(t1, 0.0f); // get the t for the cylinders ray MFVector intersectedRay; intersectedRay.Mad3(rayDir, t, local); float ct = intersectedRay.Dot3(cylinderDir) * invMagSq; if(capped && (ct < 0.0f || ct > 1.0f)) { // we need to test the caps // TODO: this is REALLY slow!! can be majorly improved!! // generate a plane for the cap MFVector point, plane; if(rayD > 0.0f) { // the near one point = cylinderPos; plane = MFCollision_MakePlaneFromPointAndNormal(point, -cylinderDir); } else { // the far one point = cylinderPos + cylinderDir; plane = MFCollision_MakePlaneFromPointAndNormal(point, cylinderDir); } // test the ray against the plane bool collide = MFCollision_RayPlaneTest(rayPos, rayDir, plane, pResult); if(collide) { // calculate the intersection point intersectedRay.Mad3(rayDir, pResult->time, rayPos); intersectedRay.Sub3(intersectedRay, point); // and see if its within the cylinders radius if(intersectedRay.MagSquared3() <= cylinderRadius * cylinderRadius) { return true; } } return false; } if(pResult) { pResult->time = t; pResult->surfaceNormal.Mad3(cylinderDir, -ct, intersectedRay); pResult->surfaceNormal.Normalise3(); } if(pCylinderTime) { *pCylinderTime = ct; } } return true; }