/************************************************** * Calculates one step for the tank based on its * movement and rotation vectors. It then works out * how that movement affects its orientation on the * terrain and runs it against the collision engine. * * This function should be written as procedurally as possible * because it is called every frame for every tank. **************************************************/ void Tank::move() { mRotation[1] += mCurrentRotationRate; float ySin = sin(TO_RADIANS(mRotation[1])); float yCos = cos(TO_RADIANS(mRotation[1])); Vector3D<float> driveMomentum; driveMomentum[0] = ySin * mCurrentMoveRate; driveMomentum[2] = yCos * mCurrentMoveRate; Vector3D<float> newPosition = mPosition + driveMomentum; if (mTurretConstantRotate) { mHeadRotation += mHeadRotationDirection; } if (mAIRotateCalled) { if (abs(mHeadRotation - mHeadTargetDirection) < mHeadRotationRate) { mHeadRotation = mHeadTargetDirection; mHeadTargetDirection = mHeadRotation; } else { mHeadRotation += mHeadRotationDirection; mHeadTargetDirection -= mHeadRotationRate; } } //transform the four control points to determine how the tank should sit //on the terrrain mTransformedBackLeftControl = mBackLeftControl; mTransformedBackRightControl = mBackRightControl; mTransformedFrontLeftControl = mFrontLeftControl; mTransformedFrontRightControl = mFrontRightControl; mTransformedFrontLeftControl[0] = mFrontLeftControl[0] * yCos + mFrontLeftControl[2] * ySin; mTransformedFrontLeftControl[2] = mFrontLeftControl[0] * -ySin + mFrontLeftControl[2] * yCos; mTransformedFrontLeftControl[0] += newPosition[0]; mTransformedFrontLeftControl[2] += newPosition[2]; mTransformedFrontLeftControl[1] += mTerrain->findHeight(mTransformedFrontLeftControl[0], mTransformedFrontLeftControl[2]) + mTankSize[1] / 2.0; float highestControlPoint = mTransformedFrontLeftControl[1]; float lowestControlPoint = mTransformedFrontLeftControl[1]; mTransformedFrontRightControl[0] = mFrontRightControl[0] * yCos + mFrontRightControl[2] * ySin; mTransformedFrontRightControl[2] = mFrontRightControl[0] * -ySin + mFrontRightControl[2] * yCos; mTransformedFrontRightControl[0] += newPosition[0]; mTransformedFrontRightControl[2] += newPosition[2]; mTransformedFrontRightControl[1] += mTerrain->findHeight(mTransformedFrontRightControl[0], mTransformedFrontRightControl[2]) + mTankSize[1] / 2.0; if (mTransformedFrontRightControl[1] > highestControlPoint) { highestControlPoint = mTransformedFrontRightControl[1]; } else if (mTransformedFrontRightControl[1] < lowestControlPoint) { lowestControlPoint = mTransformedFrontRightControl[1]; } mTransformedBackLeftControl[0] = mBackLeftControl[0] * yCos + mBackLeftControl[2] * ySin; mTransformedBackLeftControl[2] = mBackLeftControl[0] * -ySin + mBackLeftControl[2] * yCos; mTransformedBackLeftControl[0] += newPosition[0]; mTransformedBackLeftControl[2] += newPosition[2]; mTransformedBackLeftControl[1] += mTerrain->findHeight(mTransformedBackLeftControl[0], mTransformedBackLeftControl[2]) + mTankSize[1] / 2.0; if ( mTransformedBackLeftControl[1] > highestControlPoint) { highestControlPoint = mTransformedBackLeftControl[1]; } else if (mTransformedBackLeftControl[1] < lowestControlPoint) { lowestControlPoint = mTransformedBackLeftControl[1]; } mTransformedBackRightControl[0] = mBackRightControl[0] * yCos + mBackRightControl[2] * ySin; mTransformedBackRightControl[2] = mBackRightControl[0] * -ySin + mBackRightControl[2] * yCos; mTransformedBackRightControl[0] += newPosition[0]; mTransformedBackRightControl[2] += newPosition[2]; mTransformedBackRightControl[1] += mTerrain->findHeight(mTransformedBackRightControl[0], mTransformedBackRightControl[2]) + mTankSize[1] / 2.0; if (mTransformedBackRightControl[1] > highestControlPoint) { highestControlPoint = mTransformedBackRightControl[1]; } else if (mTransformedBackRightControl[1] < lowestControlPoint) { lowestControlPoint = mTransformedBackRightControl[1]; } //use the transformed control points to determine what angle the tank should sit at float zFront = atan((mTransformedFrontLeftControl[1] - mTransformedFrontRightControl[1]) / mTankSize[0]); float zBack = atan((mTransformedBackLeftControl[1] - mTransformedBackRightControl[1]) / mTankSize[0]); mRotation[2] = (abs(zFront) > abs(zBack)) ? TO_DEGREES(zFront) : TO_DEGREES(zBack); float xLeft = atan(( mTransformedBackLeftControl[1] - mTransformedFrontLeftControl[1]) / mTankSize[0]); float xRight = atan(( mTransformedBackRightControl[1] - mTransformedFrontRightControl[1]) / mTankSize[0]); mRotation[0] = (abs(xLeft) > abs(xRight)) ? TO_DEGREES(xLeft) : TO_DEGREES(xRight); //set the position to the highest of the four control points mPosition[1] = (highestControlPoint + lowestControlPoint) / 2.0 + mTankSize[1] / 2.0; mPreviousPosition = mPosition; float friction = mTerrain->getFriction(mPosition[0], mPosition[2]); float cmr = fabs(mCurrentMoveRate); driveMomentum *= friction; mMomentum *= (1.0f - friction); if (mMomentum.isZero()) mMomentum.set(0.0f); float magnitude = mMomentum.length(); mMomentum += driveMomentum; if (mMomentum.length() > cmr) { mMomentum.normalizeTo(magnitude > cmr ? magnitude : cmr); } mPosition += mMomentum; if (mPosition[0] < 1.25) { mPosition[0] = 1.25; } else if (mPosition[0] > mTerrainWidth - 2.25) { mPosition[0] = mTerrainWidth - 2.25; } if (mPosition[2] < 1.25) { mPosition[2] = 1.25; } else if (mPosition[2] > mTerrainHeight - 2.25) { mPosition[2] = mTerrainHeight - 2.25; } }
void Frustum::enclose( const Frustum & other ) { vec3 n = glm::normalize(other.origin - other.at); vec3 u = glm::normalize(glm::cross(other.up, n)); vec3 v = glm::normalize(glm::cross(n, u)); if( type == Projection::PERSPECTIVE ) this->orient( origin, other.getCenter(), up ); mat4 m = this->getViewMatrix(); vec3 p[8]; // Get 8 points that define the frustum if( other.type == Projection::PERSPECTIVE ) { float dy = other.mNear * tanf( (float)TO_RADIANS(other.fovy) / 2.0f ); float dx = other.ar * dy; vec3 c = other.origin - n * other.mNear; p[0] = c + u * dx + v * dy; p[1] = c - u * dx + v * dy; p[2] = c - u * dx - v * dy; p[3] = c + u * dx - v * dy; dy = other.mFar * tanf( (float)TO_RADIANS(other.fovy) / 2.0f ); dx = other.ar * dy; c = other.origin - n * other.mFar; p[4] = c + u * dx + v * dy; p[5] = c - u * dx + v * dy; p[6] = c - u * dx - v * dy; p[7] = c + u * dx - v * dy; } else { vec3 c = other.origin - n * other.mNear; p[0] = c + u * other.xmax + v * other.ymax; p[1] = c + u * other.xmax + v * other.ymin; p[2] = c + u * other.xmin + v * other.ymax; p[3] = c + u * other.xmin + v * other.ymin; c = other.origin - n * other.mFar; p[4] = c + u * other.xmax + v * other.ymax; p[5] = c + u * other.xmax + v * other.ymin; p[6] = c + u * other.xmin + v * other.ymax; p[7] = c + u * other.xmin + v * other.ymin; } // Adjust frustum to contain if( type == Projection::PERSPECTIVE ) { fovy = 0.0f; mFar = 0.0f; mNear = std::numeric_limits<float>::max(); float maxHorizAngle = 0.0f; for( int i = 0; i < 8; i++) { // Convert to local space vec4 pt = m * vec4(p[i],1.0f); if( pt.z < 0.0f ) { float d = -pt.z; float angle = atanf( fabs(pt.x) / d ); if( angle > maxHorizAngle ) maxHorizAngle = angle; angle = (float)TO_DEGREES( atanf( fabs(pt.y) / d ) ); if( angle * 2.0f > fovy ) fovy = angle * 2.0f; if( mNear > d ) mNear = d; if( mFar < d ) mFar = d; } } float h = ( mNear * tanf( (float)TO_RADIANS(fovy)/ 2.0f) ) * 2.0f; float w = ( mNear * tanf( maxHorizAngle ) ) * 2.0f; ar = w / h; } else { xmin = ymin = mNear = std::numeric_limits<float>::max(); xmax = ymax = mFar = std::numeric_limits<float>::min(); for( int i = 0; i < 8; i++) { // Convert to local space vec4 pt = m * vec4(p[i],1.0f); if( xmin > pt.x ) xmin = pt.x; if( xmax < pt.x ) xmax = pt.x; if( ymin > pt.y ) ymin = pt.y; if( ymax < pt.y ) ymax = pt.y; if( mNear > -pt.z ) mNear = -pt.z; if( mFar < -pt.z ) mFar = -pt.z; } } }