//------------------------------------------------------------------------------- // @ Slerp() //------------------------------------------------------------------------------- // Spherical linearly interpolate two quaternions // This will always take the shorter path between them //------------------------------------------------------------------------------- void Slerp( IvQuat& result, const IvQuat& start, const IvQuat& end, float t ) { // get cosine of "angle" between quaternions float cosTheta = start.Dot( end ); float startInterp, endInterp; // if "angle" between quaternions is less than 90 degrees if ( cosTheta >= kEpsilon ) { // if angle is greater than zero if ( (1.0f - cosTheta) > kEpsilon ) { // use standard slerp float theta = acosf( cosTheta ); float recipSinTheta = 1.0f/IvSin( theta ); startInterp = IvSin( (1.0f - t)*theta )*recipSinTheta; endInterp = IvSin( t*theta )*recipSinTheta; } // angle is close to zero else { // use linear interpolation startInterp = 1.0f - t; endInterp = t; } } // otherwise, take the shorter route else { // if angle is less than 180 degrees if ( (1.0f + cosTheta) > kEpsilon ) { // use slerp w/negation of start quaternion float theta = acosf( -cosTheta ); float recipSinTheta = 1.0f/IvSin( theta ); startInterp = IvSin( (t-1.0f)*theta )*recipSinTheta; endInterp = IvSin( t*theta )*recipSinTheta; } // angle is close to 180 degrees else { // use lerp w/negation of start quaternion startInterp = t - 1.0f; endInterp = t; } } result = startInterp*start + endInterp*end; } // End of Slerp()
//------------------------------------------------------------------------------- // @ Player::CreateCylinder() //------------------------------------------------------------------------------- // Create vertex arrays for a cylinder centered around the origin //------------------------------------------------------------------------------- void Player::CreateCylinder() { // Creates a grid of points, shaped into a cylinder. In order to avoid a // texturing anomaly, we cannot simply share the vertical seam edge vertices // They must be duplicated; one copy must have a U-coord of 0.0, the other a // U-coord of 1.0f const unsigned int steps = 32; mCylinderVerts = IvRenderer::mRenderer->GetResourceManager()->CreateVertexBuffer( kTCPFormat, (steps + 1) * steps, nullptr, kDefaultUsage); IvTCPVertex* tempVerts0 = (IvTCPVertex*)(mCylinderVerts->BeginLoadData()); // temporary pointers that can be stepped along the arrays const float phiIncrement = kPI / (steps - 1); const float thetaIncrement = kTwoPI / steps; unsigned int i,j; // A double loop, walking around and down the cylinder for (j = 0; j <= steps; j++) { float theta = thetaIncrement * j; float u = j / (float)steps; float sinTheta, cosTheta; IvSinCos(theta, sinTheta, cosTheta); for (i = 0; i < steps; i++) { float phi = -kHalfPI + phiIncrement * i; float v = i / (float)(steps - 1); if (i == 0) { tempVerts0->position = IvVector3(0.0f, 0.0f, -mRadius); } else if (i == (steps - 1)) { tempVerts0->position = IvVector3(0.0f, 0.0f, mRadius); } else { tempVerts0->position = IvVector3(mRadius * cosTheta, mRadius * sinTheta, mRadius * IvSin(phi)); } tempVerts0->texturecoord = IvVector2(u, v); tempVerts0->color.mAlpha = tempVerts0->color.mRed = tempVerts0->color.mGreen = tempVerts0->color.mBlue = 255; tempVerts0++; } } mCylinderVerts->EndLoadData(); // Create index arrays - just a 32x31-quad mesh of triangles // Each of the 32 strips has 31 * 2 triangles plus two dummy indices // This means that there are 31 * 2 + 2 + 2 (two extra to start the // strip, and two extra to end the previous strip) indices in each // strip, although we can avoid two indices in the first strip, as // there is no previous strip to be ended in that case. Thus, // 64 + 66 * 31 indices for the entire cylinder unsigned int cylinderIndexCount = steps * 2 + (steps - 1) * (steps * 2 + 2); mCylinderIndices = IvRenderer::mRenderer->GetResourceManager()->CreateIndexBuffer( cylinderIndexCount, nullptr, kDefaultUsage); UInt32* tempIndices = (UInt32*)mCylinderIndices->BeginLoadData(); for (j = 0; j < steps; j++) { UInt32 baseIndex0 = steps * j; UInt32 baseIndex1 = steps * (j + 1); // restart the strip by doubling the last and next indices if (j != 0) { *(tempIndices++) = tempIndices[-1]; *(tempIndices++) = baseIndex0; } unsigned int i; for (i = 0; i < steps; i++) { *(tempIndices++) = baseIndex0; *(tempIndices++) = baseIndex1; baseIndex0++; baseIndex1++; } } mCylinderIndices->EndLoadData(); } // End of Player::CreateCylinder()