The-Simpsons-Hit-and-Run/game/code/worldsim/redbrick/geometryvehicle.cpp

3385 lines
107 KiB
C++

/*===========================================================================
geometryvehicle.cpp
created Dec 7, 2001
by Greg Mayer
Copyright (c) 2001 Radical Entertainment, Inc.
All rights reserved.
===========================================================================*/
#include <camera/supercammanager.h>
#include <contexts/bootupcontext.h>
#include <worldsim/character/characterrenderable.h>
#include <worldsim/redbrick/geometryvehicle.h>
#include <worldsim/redbrick/vehicle.h>
#include <worldsim/redbrick/wheel.h>
#include <worldsim/avatar.h>
#include <worldsim/avatarmanager.h>
#include <worldsim/vehiclecentral.h>
#include <render/RenderManager/RenderManager.h>
#include <p3d/anim/compositedrawable.hpp>
#include <p3d/billboardobject.hpp>
#include <p3d/anim/multicontroller.hpp>
#include <p3d/anim/poseanimation.hpp>
#include <p3d/camera.hpp>
#include <p3d/directionallight.hpp>
#include <p3d/light.hpp>
#include <p3d/matrixstack.hpp>
#include <p3d/shadow.hpp>
#include <p3d/view.hpp>
#include <p3d/effects/particlesystem.hpp>
#include <pddi/pddi.hpp>
#include <p3d/utility.hpp>
#include <typeinfo>
#include <p3d/anim/visibilityanimation.hpp>
#include <raddebug.hpp>
#include <raddebugwatch.hpp>
#include <mission/statepropcollectible.h>
#include <memory/srrmemory.h>
#include <mission/gameplaymanager.h>
#include <render/particles/particlemanager.h>
#include <radmath/util.hpp>
#include <debug/debuginfo.h>
#include <worldsim/redbrick/trafficbodydrawable.h>
#include <worldsim/coins/sparkle.h>
//#define SHADOW_EDITTING
const int TYPICAL_NUMBER_OF_FRAME_CONTROLLERS = 16;
// this is by artist design... the value is between 0 and 255
static const int INCAR_ROOF_ALPHA = 100;
// The velocity at which variable emission particle systems
// reach their peak (13.5 meters/second ~ 50 kph)
static const float PARTICLE_SYSTEM_MAX_VELOCITY = 13.5f;
static const float MAX_Y_OFFSET = 0.25f; // Max distance the shadow will raise to avoid Z Chew.
// Listing of special frame controllers
// This list might be best moved into some sort of script file or data chunk
// rather than being hardcoded if many more get added
// Currently its got framecontrollers for the flame effects on the hoverbike
static const GeometryVehicle::VehicleFrameController FRAME_CONTROLLER_DATA[] =
{
// These are reversable framecontrollers
{ "BQG_flame4Shape", NULL, true, eNone, 0, 1.0f, 0, 0 },
{ "BQG_flame3Shape", NULL, true, eNone, 0, 1.0f, 0, 0 },
{ "BQG_flame2Shape", NULL, true, eNone, 1.0f, 0, 0, 0 },
{ "BQG_flame1Shape", NULL, true, eNone, 1.0f, 0, 0, 0 },
{ "BQG_flame5Shape", NULL, true, eNone, 1.0f, 0, 0, 0 },
{ "BQG_flame6Shape", NULL, true, eNone, 1.0f, 0, 0, 0 },
{ "EFX_backfireSystShape", NULL, false, eBackfire, 0,0,0, 0 },
{ "BQG_backfireflashGroupShape", NULL, false, eBackfire, 0,0,0 },
{ "PTRN_ship", NULL, false, eNone, 0, 0, 1.0f/25.0f, 0 },
{ "PTRN_redbrick", NULL, false, eNone, 0, 0, 0.08f, 5.0f }
//,
// { "PTRN_ship", NULL, false, eNone, 2.0f,-2.0f,0,0 }
};
const rmt::Vector BARRACUDA_COLLECTIBLE_POS( 0, 0.4f, -3.0f );
const rmt::Vector JEEP_COLLECTIBLE_POS( -0.237f, 0.216f, -2.243f );
const rmt::Vector DUNE_COLLECTIBLE_ROT( rmt::DegToRadian( -90 ), rmt::DegToRadian( 0 ), rmt::DegToRadian( 0 ));
const rmt::Vector DUNE_COLLECTIBLE_POS( 0, 0.714f, 0);
const float BARREL_RADIUS = 0.351f;
const rmt::Vector WITCH_COLLECTIBLE_POS( 0, 0.4f, -1.31f - BARREL_RADIUS );
const rmt::Vector COFFIN_COLLECTIBLE_POS( 0, 0.4f, -1.59f - BARREL_RADIUS );
const rmt::Vector HALLO_COLLECTIBLE_POS( 0, 0.4f, -3.467f - BARREL_RADIUS );
const rmt::Matrix DEFAULT_COLLECTIBLE_TRANSFORM( 0.9219f, -0.3875f, 0.0f, 0.0f,
0.3797f, 0.9034f, -0.1994f, 0.0f,
0.0773f, 0.1838f, 0.9799f, 0.0f,
0.0f, 0.1270f, -2.6610f, 1.0f );
static const int NUM_FRAME_CONTROLLERS = sizeof( FRAME_CONTROLLER_DATA ) / sizeof( FRAME_CONTROLLER_DATA[0] );
static bool sbDrawVehicle = true;
static float refractiveIndex = 10.0f;
//------------------------------------------------------------------------
GeometryVehicle::GeometryVehicle():
m_Collectible( NULL ),
m_EnvRef( 0x40 )
{
mCompositeDrawable = 0;
mChassisGeometry = 0;
mAnim = 0;
mAnimRevPerSecondBase = 1.0f;
mVehicleOwner = 0;
//mRevMult = 0.5f;
//mRevMult = 0.4f;
mRevMult = 0.1f; // good for frink - anyone else need this?
mHoodShader = 0;
mTrunkShader = 0;
mDoorPShader = 0;
mDoorDShader = 0;
mHoodTextureDam = 0;
mTrunkTextureDam = 0;
mDoorPTextureDam = 0;
mDoorDTextureDam = 0;
mHoodTextureNorm = 0;
mTrunkTextureNorm = 0;
mDoorPTextureNorm = 0;
mDoorDTextureNorm = 0;
mChassisShader = 0;
mChassisTextureNorm = 0;
mChassisTextureDam = 0;
mParticleEmitter = 0;
mVariableEmissionParticleSystem = 0;
mEngineParticleAttr.mType = ParticleEnum::eNull;
mLeftWheelParticleAttr.mType = ParticleEnum::eNull;
mRightWheelParticleAttr.mType = ParticleEnum::eNull;
mTailPipeParticleAttr.mType = ParticleEnum::eNull;
mSkidMarkGenerator = 0;
mSpecialEffect = ParticleEnum::eNull;
mLastPosition = rmt::Vector (0.0f, 0.0f, 0.0f);
mCurEnvMapRotation = 0.0f;
mBrakeLightJoints[0] = -1;
mBrakeLightJoints[1] = -1;
mBrakeLightJoints[2] = -1;
mBrakeLightJoints[3] = -1;
mReverseLightJoints[0] = -1;
mReverseLightJoints[1] = -1;
mReverseLightJoints[2] = -1;
mReverseLightJoints[3] = -1;
mTrafficBodyDrawable = NULL;
mTrafficDoorDrawable = NULL;
for( int i = 0; i < 4; ++i )
{
mShadowPointAdjustments[ i ][ 0 ] = 0.0f;
mShadowPointAdjustments[ i ][ 1 ] = 0.0f;
}
mFadeAlpha = 255;
for( int i=0; i<NUM_BRAKELIGHT_BBQS; i++ )
{
mBrakeLights[i] = NULL;
}
#ifdef RAD_WIN32
mFrinkArc = NULL;
#endif
mUsingTrafficModel = false;
/*
for( int i=0; i<NUM_HEADLIGHT_BBQGS; i++ )
{
mHeadLights[i] = NULL;
}
*/
mHasGhostGlow = false;
for( int i=0; i<NUM_GHOSTGLOW_BBQGS; i++ )
{
mGhostGlows[i] = NULL;
}
mHasNukeGlow = false;
for( int i=0; i<NUM_NUKEGLOW_BBQGS; i++ )
{
mNukeGlows[i] = NULL;
}
mBrakeLightsOn = false;
mBrakeLightScale = 0.0f;
mHeadLightScale = 0.0f;
mEnableLights = true; // sets visibility on headlights and brakelights
mLightsOffDueToDamage = false;
mRoofShader = NULL;
mRoofAlpha = 255;
mRoofTargetAlpha = 255;
mRoofOpacShape = NULL;
mRoofAlphaShape = NULL;
for( int i = 0; i < MAX_REFRACTION_SHADERS; ++i )
{
mRefractionShader[ i ] = NULL;
}
// Lets make a collectible transform
// Hard code it for now. Later use car specific ones from Kevin
m_CollectibleTransform = DEFAULT_COLLECTIBLE_TRANSFORM;
mFrameControllers.reserve( TYPICAL_NUMBER_OF_FRAME_CONTROLLERS );
//
// Add refractive index to the watcher
//
static bool refractiveIndexAdded = false;
if( !refractiveIndexAdded )
{
radDbgWatchAddFloat( &refractiveIndex, "RefractionShader", "RefraciveIndex", 0, 0, -20.0f, 20.0f );
refractiveIndexAdded = true;
}
}
//------------------------------------------------------------------------
GeometryVehicle::~GeometryVehicle()
{
#ifdef SHADOW_EDITTING
for( int i = 0; i < 4; ++i )
{
radDbgWatchDelete( &(mShadowPointAdjustments[ i ][ 0 ]) );
radDbgWatchDelete( &(mShadowPointAdjustments[ i ][ 1 ]) );
}
#endif
if(mCompositeDrawable)
{
GetRenderManager()->mEntityDeletionList.Add((tRefCounted*&)mCompositeDrawable);
mCompositeDrawable = 0;
}
if(mVariableEmissionParticleSystem)
{
GetRenderManager()->mEntityDeletionList.Add((tRefCounted*&)mVariableEmissionParticleSystem);
mVariableEmissionParticleSystem = 0;
}
if(mChassisGeometry)
{
mChassisGeometry->Release();
mChassisGeometry = 0;
}
if(mAnim)
{
mAnim->Release();
mAnim = 0;
}
for( int i = 0; i < MAX_REFRACTION_SHADERS; ++i )
{
tRefCounted::Release( mRefractionShader[ i ] );
mRefractionShader[ i ] = 0;
}
// damage state crapola
if(mHoodShader) mHoodShader->Release();
if(mTrunkShader) mTrunkShader->Release();
if(mDoorPShader) mDoorPShader->Release();
if(mDoorDShader) mDoorDShader->Release();
if(mHoodTextureNorm) mHoodTextureNorm->Release();
if(mTrunkTextureNorm) mTrunkTextureNorm->Release();
if(mDoorPTextureNorm) mDoorPTextureNorm->Release();
if(mDoorDTextureNorm) mDoorDTextureNorm->Release();
if(mHoodTextureDam) mHoodTextureDam->Release();
if(mTrunkTextureDam) mTrunkTextureDam->Release();
if(mDoorPTextureDam) mDoorPTextureDam->Release();
if(mDoorDTextureDam) mDoorDTextureDam->Release();
if(mChassisShader) mChassisShader->Release();
if(mChassisTextureNorm) mChassisTextureNorm->Release();
if(mChassisTextureDam) mChassisTextureDam->Release();
delete mParticleEmitter;
if ( mSpecialEffect != ParticleEnum::eNull )
{
GetParticleManager()->DeleteSystem( mSpecialEffect );
}
if ( mVariableEmissionParticleSystem != 0 )
{
mVariableEmissionParticleSystem->ReleaseParticles();
mVariableEmissionParticleSystem = 0;
}
if(mSkidMarkGenerator)
{
delete mSkidMarkGenerator;
}
if( mTrafficBodyDrawable )
{
mTrafficBodyDrawable->Release();
mTrafficBodyDrawable = NULL;
}
if( mTrafficDoorDrawable )
{
mTrafficDoorDrawable->Release();
mTrafficDoorDrawable = NULL;
}
for( int i=0; i<NUM_BRAKELIGHT_BBQS; i++ )
{
if( mBrakeLights[i] )
{
mBrakeLights[i]->Release();
mBrakeLights[i] = NULL;
}
}
#ifdef RAD_WIN32
if( mFrinkArc )
{
mFrinkArc->Release();
mFrinkArc = NULL;
}
#endif
/*
for( int i=0; i<NUM_HEADLIGHT_BBQGS; i++ )
{
if( mHeadLights[i] )
{
mHeadLights[i]->Release();
mHeadLights[i] = NULL;
}
}
*/
for( int i=0; i<NUM_GHOSTGLOW_BBQGS; i++ )
{
if( mGhostGlows[i] )
{
mGhostGlows[i]->Release();
mGhostGlows[i] = NULL;
}
}
for( int i=0; i<NUM_NUKEGLOW_BBQGS; i++ )
{
if( mNukeGlows[i] )
{
mNukeGlows[i]->Release();
mNukeGlows[i] = NULL;
}
}
if( mRoofShader )
{
mRoofShader->Release();
mRoofShader = NULL;
}
if( mRoofOpacShape )
{
mRoofOpacShape = NULL;
}
if( mRoofAlphaShape )
{
mRoofAlphaShape = NULL;
}
for ( unsigned int fc = 0 ; fc < mFrameControllers.size() ; fc++ )
{
mFrameControllers[fc].frameController->Release();
}
if ( m_Collectible != NULL )
{
m_Collectible->Release();
m_Collectible = NULL;
}
}
//------------------------------------------------------------------------
bool GeometryVehicle::Init( const char* name, Vehicle* owner, int num)
{
#ifdef SHADOW_EDITTING
for( int i = 0; i < 4; ++i )
{
mShadowPointAdjustments[ i ][ 0 ] = 0.0f;
mShadowPointAdjustments[ i ][ 1 ] = 0.0f;
char text[ 128 ];
sprintf( text, "%s Shadow point %d X", name, i );
radDbgWatchAddFloat( &(mShadowPointAdjustments[ i ][ 0 ]), text, "VehicleShadow", 0, 0, -5.0f, 5.0f );
sprintf( text, "%s Shadow point %d Y", name, i );
radDbgWatchAddFloat( &(mShadowPointAdjustments[ i ][ 1 ]), text, "VehicleShadow", 0, 0, -5.0f, 5.0f );
}
#endif
mVehicleOwner = owner;
mCurEnvMapRotation = 0.0f;
return GetArt(name);
}
//=============================================================================
// GeometryVehicle::InitSkidMarks
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void GeometryVehicle::InitSkidMarks()
{
// called from vehicle Init
// only for user vehicles
GameMemoryAllocator gma = GetGameplayManager()->GetCurrentMissionHeap();
mSkidMarkGenerator = new(gma)SkidMarkGenerator;
int i;
for(i = 0; i < 4; i++)
{
// initial value
rmt::Vector offset = mVehicleOwner->mSuspensionRestPoints[i];
offset.y -= mVehicleOwner->mWheels[i]->mRadius;
mSkidMarkGenerator->SetWheelOffset(i, offset); // need to do this everyframe
float length = mVehicleOwner->mWheels[i]->mRadius * 0.6f;
//float width = mVehicleOwner->mWheels[i]->mRadius * 0.5f; //??
float width = mVehicleOwner->mWheels[i]->mRadius * 0.8f; //??
mSkidMarkGenerator->SetWheelDimensions(i, width, length);
//void GenerateSkid( int wheel, const SkidData& );
//void Update();
}
}
//=============================================================================
// GeometryVehicle::InitParticles
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void GeometryVehicle::InitParticles()
{
MEMTRACK_PUSH_GROUP( "GeometryVehicle" );
GameMemoryAllocator gma = GetGameplayManager()->GetCurrentMissionHeap();
mParticleEmitter = new(gma)VehicleParticleEmitter;
rmt::Vector smokeOffset = mVehicleOwner->GetSmokeOffset();
mParticleEmitter->SetPartLocation(VehicleParticleEmitter::eEngine, smokeOffset);
rmt::Vector wheelOffset = mVehicleOwner->GetWheel0Offset();
mParticleEmitter->SetPartLocation(VehicleParticleEmitter::eRightBackTire, wheelOffset);
wheelOffset = mVehicleOwner->GetWheel1Offset();
mParticleEmitter->SetPartLocation(VehicleParticleEmitter::eLeftBackTire, wheelOffset);
MEMTRACK_POP_GROUP("GeometryVehicle");
}
//=============================================================================
// GeometryVehicle::GetHeadlightScale
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: float
//
//=============================================================================
float GeometryVehicle::GetHeadlightScale()
{
return mHeadLightScale;
}
//=============================================================================
// GeometryVehicle::SetHeadlightScale
//=============================================================================
// Description: Comment
//
// Parameters: ( float scale )
//
// Return: void
//
//=============================================================================
void GeometryVehicle::SetHeadlightScale( float scale )
{
rAssert( 0.0f <= scale );
this->mHeadLightScale = scale;
}
//=============================================================================
// GeometryVehicle::AttachCollectible
//=============================================================================
// Description: Comment
//
// Parameters: ( StatePropCollectible* drawable )
//
// Return: bool
//
//=============================================================================
bool GeometryVehicle::AttachCollectible( StatePropCollectible* drawable )
{
bool wasAttached;
// We only have one slot for a collectible per vehicle
// check that this vehicle's slot is currently empty
if ( m_Collectible == NULL )
{
tRefCounted::Assign( m_Collectible, drawable );
rmt::Matrix identity;
identity.Identity();
drawable->SetTransform( identity );
m_Collectible->EnableCollisionVolume( false );
m_Collectible->SetState( 1 );
m_Collectible->RemoveFromDSG();
m_Collectible->EnableHudIcon( false );
m_Collectible->EnableCollisionTesting( false );
wasAttached = true;
}
else
{
wasAttached = false;
}
return wasAttached;
}
//=============================================================================
// GeometryVehicle::GetAttachedCollectible
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: StatePropCollectible
//
//=============================================================================
StatePropCollectible* GeometryVehicle::GetAttachedCollectible()
{
return m_Collectible;
}
//=============================================================================
// GeometryVehicle::DetachCollectible
//=============================================================================
// Description: Comment
//
// Parameters: ( const rmt::Vector& velocity, bool explode )
//
// Return: void
//
//=============================================================================
void GeometryVehicle::DetachCollectible( const rmt::Vector& velocity, bool explode )
{
if ( m_Collectible )
{
m_Collectible->EnableHudIcon( false );
m_Collectible->EnableCollisionVolume( false );
m_Collectible->SetState( 0 );
sim::SimState* sim = m_Collectible->GetSimState();
if ( sim )
{
sim->ResetVelocities();
}
m_Collectible->AddToDSG();
// Lets set the transform to have no rotation, but position remains the same
rmt::Matrix transform;
transform.Identity();
transform.FillTranslate( m_CollectibleTransform.Row(3) + mVehicleOwner->GetPosition() );
m_Collectible->SetTransform(transform);
m_Collectible->Release();
if ( explode )
m_Collectible->Explode();
m_Collectible = NULL;
}
}
//=============================================================================
// GeometryVehicle::Display
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void GeometryVehicle::Display()
{
BEGIN_PROFILE("GeometryVehicle::Display SetUp")
rmt::Vector pos = mVehicleOwner->GetPosition ();
rmt::Vector movement = pos - mLastPosition;
bool smokeFirst = true; // Used to fix draw order problem with the smoke and a vehicle's windshield.
tCamera* camera = p3d::context->GetView()->GetCamera();
rAssert( camera );
const rmt::Matrix& camTrans = camera->GetCameraToWorldMatrix();
if( mVehicleOwner->mVehicleType == VT_USER )
{
// Set the rotation vector on all the car's shaders.
// Base the rotation on how far the car has moved in the last known direction,
// so that the reflection map moves across the car when the car moves. -- jdy
//
bool fucked = false;
if ( mLastPosition.MagnitudeSqr() != 0.0f &&
( rmt::Fabs( movement.x ) > 1000.0f ||
rmt::Fabs( movement.y ) > 1000.0f ||
rmt::Fabs( movement.z ) > 1000.0f ) )
{
//TODO: What the hell is causing this?
//mVehicleOwner position and facing are fucked.
//We've moved too far. Clamp.
pos = mLastPosition;
fucked = true;
}
if ( !fucked )
{
float distance = movement.DotProduct( mVehicleOwner->GetFacing() );
rAssert( !rmt::IsNan( distance ) );
if( rmt::IsNan( distance ) )
{
distance = 0.0f;
}
if( rmt::Fabs( distance ) > 0.01f && rmt::Fabs( distance ) < 50.0f ) // Car must move at least 1 cm for an adjustment to be made
{
// Find the normal of the plane defined by the direction of movement and the camera facing.
//This will be the axis we rotate around.
// Note that the reflection map is relative to the object so we need to transform everything
//into the object's space.
rmt::Matrix carOri = mVehicleOwner->GetTransform();
carOri.Invert();
carOri.FillTranslate( rmt::Vector( 0.0f, 0.0f, 0.0f ) );
rmt::Vector camRelCar;
carOri.Transform( camTrans.Row( 2 ), &camRelCar );
rmt::Vector carRelMovement;
carOri.Transform( movement, &carRelMovement );
rmt::Vector axis;
float camMovementFacing = carRelMovement.Dot( camRelCar );
if( camMovementFacing < 0.0f )
{
axis.CrossProduct(camRelCar, carRelMovement);
}
else
{
axis.CrossProduct(carRelMovement, camRelCar);
}
// Check if the car is moving towards or away from the camera.
mCurEnvMapRotation += distance * 0.05f;
while( mCurEnvMapRotation >= rmt::PI_2 )
{
mCurEnvMapRotation -= rmt::PI_2;
}
while( mCurEnvMapRotation < 0.0f )
{
mCurEnvMapRotation += rmt::PI_2;
}
float mag;
float angle;
CartesianToPolar( axis.x, axis.y, &mag, &angle );
tShaderVectorBroadcast cbPos( PDDI_SP_ROTVEC, rmt::Vector( mCurEnvMapRotation, 0.0f, -angle ) );
int count = mCompositeDrawable->GetNumDrawableElement ();
for (int i = 0; i < count; i++)
{
tCompositeDrawable::DrawableElement* pElement = mCompositeDrawable->GetDrawableElement( i );
tDrawable* pDrawable = pElement->GetDrawable();
pDrawable->ProcessShaders( cbPos );
}
}
// Remember the position of the car for next time
//
mLastPosition = pos;
}
}
else
{
mLastPosition = pos;
}
rmt::Vector vehicleVelocity;
mVehicleOwner->GetVelocity( &vehicleVelocity );
if(mEngineParticleAttr.mType != ParticleEnum::eNull)
{
// Figure out which to draw first, the smoke or the car.
//We do this by transforming the SmokeOffset into world space and then dot product with the
//the camera's facing vector. If it is towards the camera we draw the smoke after the car.
//Crude, but quick and hopefully there won't be too many visual artifacts.
rmt::Matrix facing = mVehicleOwner->mTransform;
facing.FillTranslate( rmt::Vector( 0.0f, 0.0f, 0.0f ) );
rmt::Vector smoke = mVehicleOwner->GetSmokeOffset();
facing.Transform( smoke, &smoke );
float dot = smoke.DotProduct( camTrans.Row( 2 ) );
smokeFirst = dot > 0.6f;
if( ( mEngineParticleAttr.mType == ParticleEnum::eEngineSmokeLight ) ||
( mEngineParticleAttr.mType == ParticleEnum::eEngineSmokeMedium ) )
{
GetSparkleManager()->AddSmoke( mVehicleOwner->mTransform, mVehicleOwner->GetSmokeOffset(), movement, ( ( 0.4f - mVehicleOwner->GetVehicleLifePercentage( mVehicleOwner->mHitPoints ) ) * 2.5f ) );
}
else
{
// draw some particles
//mEngineParticleAttr.mVelocity = vehicleVelocity / 45.0f;
mParticleEmitter->Generate( VehicleParticleEmitter::eEngine,
mEngineParticleAttr, mVehicleOwner->mTransform);
// TODO - HOW ABOUT TRAFFIC - WITH THE ONE-TIME POOF!! DON'T DRAW CONTINUOUSLY
}
}
if ( mSpecialEffect != ParticleEnum::eNull )
{
ParticleAttributes attr;
attr.mType = mSpecialEffect;
mParticleEmitter->Generate( VehicleParticleEmitter::eSpecialEmitter,
attr, mVehicleOwner->mTransform);
}
// If this vehicle has tailpipe particles, generate them, always
// 31.25 (trails too long)
//mTailPipeParticleAttr.mVelocity = vehicleVelocity / 29.0f;
if ( mTailPipeParticleAttr.mType != ParticleEnum::eNull )
{
mParticleEmitter->Generate( VehicleParticleEmitter::eRightTailPipe,
mTailPipeParticleAttr, mVehicleOwner->mTransform );
mParticleEmitter->Generate( VehicleParticleEmitter::eLeftTailPipe,
mTailPipeParticleAttr, mVehicleOwner->mTransform );
}
if(mLeftWheelParticleAttr.mType != ParticleEnum::eNull)
{
mParticleEmitter->Generate( VehicleParticleEmitter::eLeftBackTire,
mLeftWheelParticleAttr, mVehicleOwner->mTransform);
}
if(mRightWheelParticleAttr.mType != ParticleEnum::eNull)
{
mParticleEmitter->Generate( VehicleParticleEmitter::eRightBackTire,
mRightWheelParticleAttr, mVehicleOwner->mTransform);
}
// if( mVehicleOwner->mVehicleType == VT_USER )
{
// Change the vehicle environment reflection
//depending on if it is interior or damaged.
unsigned char blend;
if( !mVehicleOwner->mInterior )
{
blend = m_EnvRef;
}
else
{
blend = m_EnvRef >> 2; // Quarter value for interior.
}
float damage = mVehicleOwner->GetVehicleLifePercentage(mVehicleOwner->mHitPoints);
damage = rmt::Clamp( ( damage * 0.75f ) + 0.25f, 0.0f, 1.0f );
blend = (unsigned char)( blend * damage );
tShaderColourBroadcast envBlend( PDDI_SP_ENVBLEND, tColour( blend, blend, blend ) );
int count = mCompositeDrawable->GetNumDrawableElement ();
for (int i = 0; i < count; i++)
{
tCompositeDrawable::DrawableElement* pElement = mCompositeDrawable->GetDrawableElement (i);
tDrawable* pDrawable = pElement->GetDrawable ();
pDrawable->ProcessShaders( envBlend );
}
}
END_PROFILE("GeometryVehicle::Display SetUp")
BEGIN_PROFILE("GeometryVehicle::Display Render")
if( mUsingTrafficModel )
{
if( mTrafficBodyDrawable != NULL )
{
if( mFadeAlpha != 255 )
{
mTrafficBodyDrawable->mFading = true;
}
else
{
mTrafficBodyDrawable->mFading = false;
}
mTrafficBodyDrawable->mFadeAlpha = mFadeAlpha;
}
if( mTrafficDoorDrawable != NULL )
{
if( mFadeAlpha != 255 )
{
mTrafficDoorDrawable->mFading = true;
}
else
{
mTrafficDoorDrawable->mFading = false;
}
mTrafficDoorDrawable->mFadeAlpha = mFadeAlpha;
}
// NOTE:
// This is a big cause for major grievances. It will force the blend mode of
// all the shaders of the compositedrawable's elements to be BLEND_ALPHA...
// bad news for billboards that are BLEND_NONE or BLEND_ADD...
//
tShaderIntBroadcast blendModeAlpha( PDDI_SP_BLENDMODE, PDDI_BLEND_ALPHA );
mCompositeDrawable->ProcessShaders( blendModeAlpha );
tShaderIntBroadcast emissiveAlpha( PDDI_SP_EMISSIVEALPHA, mFadeAlpha );
mCompositeDrawable->ProcessShaders( emissiveAlpha );
}
#ifdef RAD_WIN32
const tName& name = mVehicleOwner->GetNameObject();
if( name == "frink_v" )
{
float topSpeed = mVehicleOwner->GetTopSpeed();
float percentOfTopSpeed = vehicleVelocity.Magnitude() / topSpeed;
float refraction = percentOfTopSpeed;
refraction = rmt::Clamp( refraction, 0.0f, 1.0f );
int emissiveAlpha = (int)( 255.0f * (1.0f - refraction) );
tShaderIntBroadcast blendMode( PDDI_SP_BLENDMODE, PDDI_BLEND_ALPHA );
tShaderIntBroadcast emissive( PDDI_SP_EMISSIVEALPHA, emissiveAlpha );
int count = mCompositeDrawable->GetNumDrawableElement ();
for (int j = 0; j < count; j++)
{
tCompositeDrawable::DrawableElement* pElement = mCompositeDrawable->GetDrawableElement( j );
tDrawable* pDrawable = pElement->GetDrawable();
pDrawable->ProcessShaders( blendMode );
pDrawable->ProcessShaders( emissive );
}
// so since we just made EVERY SHADER alpha blend, we need to take
// care of the BBQGs (that need to be additive blended)
if( mFrinkArc )
{
tColour arcColour;
for( int j=0; j< NUM_FRINKARC_BBQS; j++ )
{
tBillboardQuad* bbq = mFrinkArc->GetQuad(j);
rAssert( bbq );
arcColour.Set(
rmt::Clamp( (int)(mOriginalFrinkArcColour[j].Red()*(1.0f - refraction)), 0, 255 ),
rmt::Clamp( (int)(mOriginalFrinkArcColour[j].Green()*(1.0f - refraction)), 0, 255 ),
rmt::Clamp( (int)(mOriginalFrinkArcColour[j].Blue()*(1.0f - refraction)), 0, 255 ),
rmt::Clamp( (int)(mOriginalFrinkArcColour[j].Alpha()*(1.0f - refraction)), 0, 255 )
);
bbq->SetColour( arcColour );
}
mFrinkArc->GetShader()->SetInt( PDDI_SP_BLENDMODE, PDDI_BLEND_ADD );
}
}
#endif
tColour brakecolour;
// if not turning on brakelights, we need to take into account the daytime
// running lights settings
float dayReduce = 2.5f; // by default, if braking is on, we magnify this value
if( !mBrakeLightsOn )
{
dayReduce = mBrakeLightScale;
}
float fadeFactor = mFadeAlpha / 255.0f;
BEGIN_PROFILE("GeometryVehicle::Breaklights")
for( int i=0; i<NUM_BRAKELIGHT_BBQS; i++ )
{
if( mBrakeLights[i] != NULL )
{
brakecolour.Set(
rmt::Clamp( (int)(mOriginalBrakeLightColours[i].Red()*fadeFactor*dayReduce), 0, 255 ),
rmt::Clamp( (int)(mOriginalBrakeLightColours[i].Green()*fadeFactor*dayReduce), 0, 255 ),
rmt::Clamp( (int)(mOriginalBrakeLightColours[i].Blue()*fadeFactor*dayReduce), 0, 255 ),
rmt::Clamp( (int)(mOriginalBrakeLightColours[i].Alpha()*fadeFactor*dayReduce), 0, 255 )
);
for( int j=0; j<mBrakeLights[i]->GetNumQuads(); j++ )
{
tBillboardQuad* bbq = mBrakeLights[i]->GetQuad( j );
rAssert( bbq != NULL );
bbq->SetColour( brakecolour );
bbq->SetVisibility( mEnableLights );
}
// ProcessShaders screwed us by causing us to lose the additive blend for
// brakelights... We set it back.
mBrakeLights[i]->GetShader()->SetInt( PDDI_SP_BLENDMODE, PDDI_BLEND_ADD );
}
}
END_PROFILE("GeometryVehicle::Breaklights")
BEGIN_PROFILE("GeometryVehicle::Headlights")
tColour headlightcolour;
int count = 0;
for( int i=0; i<VehicleCentral::NUM_HEADLIGHT_BBQGS; i++ )
{
if( GetVehicleCentral()->mHeadLights[i] != NULL )
{
for( int j=0; j<GetVehicleCentral()->mHeadLights[i]->GetNumQuads(); j++ )
{
headlightcolour.Set(
rmt::Clamp( (int)(GetVehicleCentral()->mOriginalHeadLightColours[count].Red()*fadeFactor*mHeadLightScale), 0, 255 ),
rmt::Clamp( (int)(GetVehicleCentral()->mOriginalHeadLightColours[count].Green()*fadeFactor*mHeadLightScale), 0, 255 ),
rmt::Clamp( (int)(GetVehicleCentral()->mOriginalHeadLightColours[count].Blue()*fadeFactor*mHeadLightScale), 0, 255 ),
rmt::Clamp( (int)(GetVehicleCentral()->mOriginalHeadLightColours[count].Alpha()*fadeFactor*mHeadLightScale), 0, 255 )
);
tBillboardQuad* bbq = GetVehicleCentral()->mHeadLights[i]->GetQuad( j );
rAssert( bbq != NULL );
bbq->SetColour( headlightcolour );
bbq->SetVisibility( mEnableLights );
count++;
}
// ProcessShaders screwed us by causing us to lose the additive blend
// We set it back.
GetVehicleCentral()->mHeadLights[i]->GetShader()->SetInt( PDDI_SP_BLENDMODE, PDDI_BLEND_ADD );
}
}
END_PROFILE("GeometryVehicle::Headlights")
BEGIN_PROFILE("GeometryVehicle::Ghost")
// this means we're the ghost pirate ship... The glow must be ADDITIVE as well...
if( mHasGhostGlow )
{
count = 0;
tColour glowcolour;
for( int i=0; i<NUM_GHOSTGLOW_BBQGS; i++ )
{
if( mGhostGlows[i] != NULL )
{
for( int j=0; j<mGhostGlows[i]->GetNumQuads(); j++ )
{
glowcolour.Set(
rmt::Clamp( (int)(mOriginalGhostGlowColours[count].Red()*fadeFactor), 0, 255 ),
rmt::Clamp( (int)(mOriginalGhostGlowColours[count].Green()*fadeFactor), 0, 255 ),
rmt::Clamp( (int)(mOriginalGhostGlowColours[count].Blue()*fadeFactor), 0, 255 ),
rmt::Clamp( (int)(mOriginalGhostGlowColours[count].Alpha()*fadeFactor), 0, 255 )
);
tBillboardQuad* bbq = mGhostGlows[i]->GetQuad( j );
rAssert( bbq != NULL );
bbq->SetColour( glowcolour );
count++;
}
// ProcessShaders screwed us by causing us to lose the additive blend
// We set it back.
mGhostGlows[i]->GetShader()->SetInt( PDDI_SP_BLENDMODE, PDDI_BLEND_ADD );
}
}
}
END_PROFILE("GeometryVehicle::Ghost")
// this means we're the ghost pirate ship... The glow must be ADDITIVE as well...
if( mHasNukeGlow )
{
count = 0;
tColour glowcolour;
for( int i=0; i<NUM_NUKEGLOW_BBQGS; i++ )
{
if( mNukeGlows[i] != NULL )
{
for( int j=0; j<mNukeGlows[i]->GetNumQuads(); j++ )
{
glowcolour.Set(
rmt::Clamp( (int)(mOriginalNukeGlowColours[count].Red()*fadeFactor), 0, 255 ),
rmt::Clamp( (int)(mOriginalNukeGlowColours[count].Green()*fadeFactor), 0, 255 ),
rmt::Clamp( (int)(mOriginalNukeGlowColours[count].Blue()*fadeFactor), 0, 255 ),
rmt::Clamp( (int)(mOriginalNukeGlowColours[count].Alpha()*fadeFactor), 0, 255 )
);
tBillboardQuad* bbq = mNukeGlows[i]->GetQuad( j );
rAssert( bbq != NULL );
bbq->SetColour( glowcolour );
count++;
}
// ProcessShaders screwed us by causing us to lose the additive blend
// We set it back.
mNukeGlows[i]->GetShader()->SetInt( PDDI_SP_BLENDMODE, PDDI_BLEND_ADD );
}
}
}
// fade roof...
if( mRoofShader )
{
if( mRoofAlpha > mRoofTargetAlpha )
{
mRoofAlpha--;
}
else if( mRoofAlpha < mRoofTargetAlpha )
{
mRoofAlpha++;
}
//mRoofShader->SetInt( PDDI_SP_BLENDMODE, PDDI_BLEND_ALPHA );
mRoofShader->SetInt( PDDI_SP_EMISSIVEALPHA, mRoofAlpha );
if( mRoofOpacShape && mRoofAlphaShape )
{
if( mRoofAlpha == 255 )
{
mRoofOpacShape->SetVisibility( true );
mRoofAlphaShape->SetVisibility( false );
}
else
{
mRoofOpacShape->SetVisibility( false );
mRoofAlphaShape->SetVisibility( true );
}
}
}
BEGIN_PROFILE("GeometryVehicle::CompDraw->Disp")
if( smokeFirst )
{
GetSparkleManager()->Render( Sparkle::SRM_SortedOnly );
}
if( sbDrawVehicle )
{
mCompositeDrawable->Display();
}
if( !smokeFirst )
{
GetSparkleManager()->Render( Sparkle::SRM_SortedOnly );
}
if( m_Collectible )
{
rmt::Matrix transform = mVehicleOwner->GetTransform();
p3d::stack->PushMultiply( transform );
p3d::stack->PushMultiply( m_CollectibleTransform );
m_Collectible->Display();
p3d::stack->Pop();
p3d::stack->Pop();
}
END_PROFILE("GeometryVehicle::CompDraw->Disp")
END_PROFILE("GeometryVehicle::Display Render")
}
//=============================================================================
// GeometryVehicle::DisplaySkids
//=============================================================================
// Description: Comment
//
// Parameters: void GeometryVehicle::DisplaySkids(int wheel
//
// Return: void
//
//=============================================================================
void GeometryVehicle::SetSkidValues(int wheel, float intensity, rmt::Vector& groundPlaneNormal, eTerrainType terrainType )
{
// if this got called, intensity is > 0.0
if(mSkidMarkGenerator)// && mDrawSkids) // test here though this should only be getting called for vehicles that have it... ie. VT_USER
{
/*
struct SkidData
{
// Direction that the vehicle is moving
rmt::Vector velocityDirection;
// Orientation and position of the vehicle
rmt::Matrix transform;
// Other data?????
float intensity; // 1 most intense, 0 nonexistent skid
};
*/
rmt::Vector offset = mVehicleOwner->mSuspensionRestPoints[wheel];
offset.y -= mVehicleOwner->mWheels[wheel]->mRadius;
offset.y += mVehicleOwner->mWheels[wheel]->mYOffset; // hmmm....
//if(mVehicleOwner->mWheels[wheel]->mYOffset != 0.0f)
//{
// int stophere = 1;
//}
mSkidMarkGenerator->SetWheelOffset(wheel, offset); // need to do this everyframe
SkidMarkGenerator::SkidData sd;
sd.intensity = intensity;
sd.transform = mVehicleOwner->mTransform;
sd.terrainType = terrainType;
sd.groundPlaneNormal = groundPlaneNormal;
rmt::Vector velocityDir = mVehicleOwner->mVelocityCM;
velocityDir.NormalizeSafe();
// TODO
// Michael - would this blow up if I passed in 0,0,0 ?
sd.velocityDirection = velocityDir;
mSkidMarkGenerator->GenerateSkid(wheel, sd);
}
}
//=============================================================================
// GeometryVehicle::DisplaySkids
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void GeometryVehicle::UpdateSkids()
{
if(mSkidMarkGenerator)
{
mSkidMarkGenerator->Update();
}
}
//////////////////////////////////////////////////////////////////////////
int GeometryVehicle::CastsShadow()
{
return 2;
}
//------------------------------------------------------------------------
void GeometryVehicle::DisplayShadow( BlobShadowParams* BlobParams )
{
BEGIN_PROFILE("GeometryVehicle::DisplayShadow")
rAssert(BlobParams);
tColour OutsideColour, insideColour;
// Hack for brightly colored shadows for special game mode
rmt::Vector camPos;
tCamera* camera = p3d::context->GetView()->GetCamera();
rAssert(camera);
camera->GetWorldPosition( &camPos );
camPos.Sub( BlobParams->GroundPos );
float yOffset = 0.0f; // Move the shadow up a bit with distance to avoid Z chew.
if( ::GetGameplayManager()->GetGameType() == GameplayManager::GT_SUPERSPRINT )
{
rAssert( mVehicleOwner );
Avatar* avatar = ::GetAvatarManager()->GetAvatarForVehicle( mVehicleOwner );
OutsideColour.Set( 0, 0, 0, 0 ); // black outline
insideColour.Set( 0, 0, 0 ); // default black if no Avatar
if( avatar )
{
int id = avatar->GetPlayerId();
if ( this->mVehicleOwner->mNumTurbos > 0 )
{
insideColour = ::GetGameplayManager()->GetControllerColour( id );
}
else
{
insideColour = tColour( 0, 0, 0 );
}
}
}
else
{
// Camera culling.
float camDirDot = camPos.DotProduct( camera->GetCameraToWorldMatrix().Row( 2 ) );
// Note that the camPos vector is towards the camera so the camDirDot will be negative when the camera is facing
//the object. So if it's positive then we can assume it's behind the camera.
if( camDirDot > 0.0f )
{
END_PROFILE("GeometryVehicle::DisplayShadow")
return;
}
// Blobby shadow for vehicle.
OutsideColour.Set( 255, 255, 255, 255 );
const int Inside = 128;
float fadeFactor = 1.0f;
if( mVehicleOwner->mVehicleType == VT_TRAFFIC &&
mFadeAlpha != 255 )
{
fadeFactor = 1.0f - (mFadeAlpha/255.0f);
}
else
{
fadeFactor = 1.0f - BlobParams->ShadowAlpha;
}
// DistanceAlpha: over 30 is 1, under 10 is 0, linear between.
float distanceAlpha = rmt::Clamp((camPos.Magnitude() - 10.0f) * 0.05f, 0.0f, 1.0f);
fadeFactor *= 1.0f - distanceAlpha;
int c = rmt::Clamp( int( Inside + ( 255 - Inside ) * fadeFactor ), 0, 255 );
if( c == 255)
{
return;
}
insideColour.Set( c, c, c, c );
yOffset = MAX_Y_OFFSET * distanceAlpha;
}
const int NumPoints = 6;
const float BlobLength = 2.2f;
const float BlobWidth = 1.2f;
const float BlobCant = 0.2f;
const float BlobFade = 0.4f;
static float Points[ NumPoints ][ 2 ];
static float Fades[ NumPoints ][ 2 ];
static bool DoOnce = true;
if( DoOnce )
{
DoOnce = false;
/* Here are the points we'll use for the car:
....----0
. 1
. |
. |
. + 2
. 3
. |
. 4
....----5
We'll mirror the blob along the Z axis.
The shadow point adjusts work like this:
0 - affects points 0 and 1, the top corner.
1 - affects point 2, the position for the top division.
2 - affects point 3, the position for the bottom division.
3 - affects point 4 and 5, the bottom corner.
*/
Points[ 0 ][ 0 ] = BlobWidth - BlobCant;
Points[ 0 ][ 1 ] = BlobLength;
Points[ 1 ][ 0 ] = BlobWidth;
Points[ 1 ][ 1 ] = BlobLength - BlobCant;
Points[ 2 ][ 0 ] = BlobWidth;
Points[ 2 ][ 1 ] = BlobCant;
Points[ 3 ][ 0 ] = BlobWidth;
Points[ 3 ][ 1 ] = -BlobCant;
Points[ 4 ][ 0 ] = BlobWidth;
Points[ 4 ][ 1 ] = -BlobLength + BlobCant;
Points[ 5 ][ 0 ] = BlobWidth - BlobCant;
Points[ 5 ][ 1 ] = -BlobLength;
Fades[ 0 ][ 0 ] = 0.5f * BlobFade; // Sin( 30 )
Fades[ 0 ][ 1 ] = 0.866f * BlobFade; // Cos( 30 )
Fades[ 1 ][ 0 ] = 0.866f * BlobFade; // Sin( 60 )
Fades[ 1 ][ 1 ] = 0.5f * BlobFade; // Cos( 60 )
Fades[ 2 ][ 0 ] = 0.866f * BlobFade; // Sin( 60 )
Fades[ 2 ][ 1 ] = 0.5f * BlobFade; // Cos( 60 )
Fades[ 3 ][ 0 ] = 0.866f * BlobFade; // Sin( 60 )
Fades[ 3 ][ 1 ] = 0.5f * BlobFade; // Cos( 60 )
Fades[ 4 ][ 0 ] = 0.866f * BlobFade; // Sin( 120 )
Fades[ 4 ][ 1 ] = -0.5f * BlobFade; // Cos( 120 )
Fades[ 5 ][ 0 ] = 0.5f * BlobFade; // Sin( 150 )
Fades[ 5 ][ 1 ] = -0.866f * BlobFade; // Cos( 150 )
}
camPos.Normalize();
rmt::Matrix transform;
transform.Identity();
transform.FillTranslate( BlobParams->GroundPos );
transform.FillHeading( BlobParams->GroundNormal, BlobParams->ShadowFacing );
transform.Row( 3 ).Add( camPos );
transform.Row(3).y += yOffset;
p3d::stack->PushMultiply( transform );
pddiShader* blobShader = BootupContext::GetInstance()->GetSharedShader();
if( ::GetGameplayManager()->GetGameType() == GameplayManager::GT_SUPERSPRINT )
{
blobShader->SetInt( PDDI_SP_BLENDMODE, PDDI_BLEND_NONE );
}
else
{
blobShader->SetInt( PDDI_SP_BLENDMODE, PDDI_BLEND_MODULATE );
}
blobShader->SetInt( PDDI_SP_ISLIT, 0 );
blobShader->SetInt( PDDI_SP_ALPHATEST, 0 );
blobShader->SetInt( PDDI_SP_SHADEMODE, PDDI_SHADE_GOURAUD );
pddiPrimStream* blob = p3d::pddi->BeginPrims( blobShader, PDDI_PRIM_TRIANGLES, PDDI_V_C, 6 * NumPoints );
for( int i = 0; i < NumPoints * 2; ++i )
{
int index = i;
int nextIndex = ( i + 1 ) % ( NumPoints * 2 );
int mirrorX = int( ( index * ( 1.0f / NumPoints ) ) );
int nextMirrorX = int( ( nextIndex * ( 1.0f / NumPoints ) ) );
index %= NumPoints;
nextIndex %= NumPoints;
index = rmt::Abs( ( mirrorX * 5 ) - index );
nextIndex = rmt::Abs( ( nextMirrorX * 5 ) - nextIndex );
mirrorX = 1 - ( mirrorX * 2 );
nextMirrorX = 1 - ( nextMirrorX * 2 );
int adjust = rmt::Clamp( index - 1, 0, NumPoints - 3 );
int nextAdjust = rmt::Clamp( nextIndex - 1, 0, NumPoints - 3 );
float x, y;
blob->Colour( insideColour );
blob->Coord( 0.0f, 0.0f, 0.0f );
x = ( Points[ nextIndex ][ 0 ] + mShadowPointAdjustments[ nextAdjust ][ 0 ] ) * BlobParams->ShadowScale;
y = ( Points[ nextIndex ][ 1 ] + mShadowPointAdjustments[ nextAdjust ][ 1 ] ) * BlobParams->ShadowScale;
blob->Colour( insideColour );
blob->Coord( x * nextMirrorX, y, 0.0f );
x = ( Points[ index ][ 0 ] + mShadowPointAdjustments[ adjust ][ 0 ] ) * BlobParams->ShadowScale;
y = ( Points[ index ][ 1 ] + mShadowPointAdjustments[ adjust ][ 1 ] ) * BlobParams->ShadowScale;
blob->Colour( insideColour );
blob->Coord( x * mirrorX, y, 0.0f );
}
p3d::pddi->EndPrims( blob );
// How the soft edge.
blob = p3d::pddi->BeginPrims( blobShader, PDDI_PRIM_TRISTRIP, PDDI_V_C, ( ( 2 * NumPoints ) + 1 ) * 2 );
for( int i = 0; i <= NumPoints * 2; ++i )
{
int index = i;
int mirrorX = int( ( index * ( 1.0f / NumPoints ) ) ) % 2;
index %= NumPoints;
index = rmt::Abs( ( mirrorX * 5 ) - index );
mirrorX = 1 - ( mirrorX * 2 );
int adjust = rmt::Clamp( index - 1, 0, NumPoints - 3 );
float inX, inY;
float outX, outY;
inX = ( Points[ index ][ 0 ] + mShadowPointAdjustments[ adjust ][ 0 ] ) * BlobParams->ShadowScale;
inY = ( Points[ index ][ 1 ] + mShadowPointAdjustments[ adjust ][ 1 ] ) * BlobParams->ShadowScale;
inX *= mirrorX;
outX = inX + ( Fades[ index ][ 0 ] * mirrorX * BlobParams->ShadowScale );
outY = inY + ( Fades[ index ][ 1 ] * BlobParams->ShadowScale );
blob->Colour( OutsideColour );
blob->Coord( outX, outY, 0.0f );
blob->Colour( insideColour );
blob->Coord( inX, inY, 0.0f );
}
p3d::pddi->EndPrims( blob );
p3d::stack->Pop();
END_PROFILE("GeometryVehicle::DisplayShadow")
}
//=============================================================================
// GeometryVehicle::DisplayLights
//=============================================================================
// Description: Comment
//
// Parameters: rmt::Vector& GroundPos - Position of car.
// rmt::Vector& GroundNormal - Ground normal at car position.
// rmt::Vector& GroundUp - Up direction at ground position
//
// Return: void
//
//=============================================================================
void GeometryVehicle::DisplayLights( const HeadLightParams& LightParams )
{
BEGIN_PROFILE("GeometryVehicle::DisplayLights")
const int NumPoints = 20;
const float LightXSize = 1.0f;
const float LightZSize = 0.125f;
const float FadeSize = 0.3f;
const float LightLength = NumPoints * LightZSize;
static bool DoOnce = true;
static float PointsX[ NumPoints ];
static tColour Colours[ NumPoints ];
static float FadePoints[ NumPoints ][ 2 ];
const tColour Colour( 65, 70, 46 );
const tColour Black( 0, 0, 0 );
if( DoOnce )
{
DoOnce = false;
// The light cone is made of of two tri strips one is the inner bright parabula
// which fades out with distance, and the other is the soft edge around it.
for( int i = 0; i < NumPoints; ++i )
{
float z = ( i + 1 ) * LightZSize;
float x = rmt::Sqrt( ( i + 1 ) * 0.5f );
PointsX[ i ] = x;
z -= LightLength;
float mag = rmt::Sqrt( ( x * x ) + ( z * z ) );
mag = ( ( mag != 0.0f ) ? 1.0f / mag : 0.0f ) * FadeSize;
x *= mag;
z *= mag;
FadePoints[ i ][ 0 ] = x;
FadePoints[ i ][ 1 ] = z;
float colourScale = ( 1.0f - ( (float)i / (float)NumPoints ) );
int red = rmt::Clamp( int( Colour.Red() * colourScale ), 0, 255 );
int green = rmt::Clamp( int( Colour.Green() * colourScale ), 0, 255 );
int blue = rmt::Clamp( int( Colour.Blue() * colourScale ), 0, 255 );
Colours[ i ].Set( red, green, blue );
}
// Now calculate the offset for the fade points.
}
float xScale = 1.0f;
float zScale = 1.0f;
float scale = 1.0f;
scale = LightParams.LightReach;
float offset = ( 1.0f - LightParams.LightReach ) * LightLength;
rmt::Vector camPos;
rmt::Vector groundPos = LightParams.GroundPos;
groundPos.ScaleAdd( offset, LightParams.VehicleHeading );
tCamera* camera = p3d::context->GetView()->GetCamera();
rAssert( camera );
camera->GetWorldPosition( &camPos );
camPos.Sub( groundPos );
float cameraToLight = camPos.Magnitude();
camPos.Normalize();
rmt::Matrix toCamera;
toCamera.Identity();
toCamera.FillTranslate( camPos );
rmt::Matrix transform;
transform.Identity();
transform.FillTranslate( groundPos );
transform.FillHeading( LightParams.GroundNormal, LightParams.VehicleHeading );
transform.Mult( toCamera );
p3d::stack->PushMultiply( transform );
float dist = LightParams.VehicleHeading.Dot( LightParams.GroundNormal );
rmt::Vector groundByVehicle( LightParams.GroundNormal );
if( dist != 0.0f )
{
groundByVehicle.ScaleAdd( -dist, LightParams.VehicleHeading );
groundByVehicle.Normalize();
}
float vehicleRoll = groundByVehicle.Dot( LightParams.VehicleUp );
vehicleRoll *= vehicleRoll;
#ifdef RAD_DEBUG
if( this->mVehicleOwner->mVehicleType != VT_TRAFFIC )
{
char text[128];
sprintf( text, "Ground to vehicle ratio: %.4f", vehicleRoll );
DebugInfo::GetInstance()->Push( "Vehicle lights" );
DebugInfo::GetInstance()->AddScreenText( text );
DebugInfo::GetInstance()->Pop();
}
#endif
xScale *= scale * LightXSize * vehicleRoll;
zScale *= scale * LightZSize;
pddiShader* lightShader = BootupContext::GetInstance()->GetSharedShader();
lightShader->SetInt( PDDI_SP_BLENDMODE, PDDI_BLEND_ADD );
lightShader->SetInt( PDDI_SP_ISLIT, 0 );
lightShader->SetInt( PDDI_SP_ALPHATEST, 0 );
lightShader->SetInt( PDDI_SP_SHADEMODE, PDDI_SHADE_GOURAUD );
// Center light.
pddiPrimStream* light = p3d::pddi->BeginPrims( lightShader, PDDI_PRIM_TRISTRIP, PDDI_V_C, ( NumPoints << 1 ) + 1 );
light->Colour( Colour );
light->Coord( 0.0f, 0.0f, 0.0f );
for( int i = 0; i < NumPoints; ++i )
{
float inX = PointsX[ i ] * xScale;
float inZ = ( i + 1 ) * zScale;
light->Colour( Colours[ i ] );
light->Coord( inX, inZ, 0.0f );
light->Colour( Colours[ i ] );
light->Coord( -inX, inZ, 0.0f );
}
p3d::pddi->EndPrims( light );
// Fade on the negative side.
pddiPrimStream* nFade = p3d::pddi->BeginPrims( lightShader, PDDI_PRIM_TRISTRIP, PDDI_V_C, ( NumPoints + 1 ) << 1 );
nFade->Colour( Black );
nFade->Coord( 0.0f, -FadeSize, 0.0f );
nFade->Colour( Colour);
nFade->Coord( 0.0f, 0.0f, 0.0f );
for( int i = 0; i < NumPoints; ++i )
{
float inX = -PointsX[ i ] * xScale;
float inZ = ( i + 1 ) * zScale;
float outX = inX - FadePoints[ i ][ 0 ];
float outZ = inZ + FadePoints[ i ][ 1 ];
nFade->Colour( Black );
nFade->Coord( outX, outZ, 0.0f );
nFade->Colour( Colours[ i ] );
nFade->Coord( inX, inZ, 0.0f );
}
p3d::pddi->EndPrims( nFade );
// Fade on the positive side.
pddiPrimStream* pFade = p3d::pddi->BeginPrims( lightShader, PDDI_PRIM_TRISTRIP, PDDI_V_C, ( NumPoints + 1 ) << 1 );
pFade->Colour( Colour);
pFade->Coord( 0.0f, 0.0f, 0.0f );
pFade->Colour( Black );
pFade->Coord( 0.0f, -FadeSize, 0.0f );
for( int i = 0; i < NumPoints; ++i )
{
float inX = PointsX[ i ] * xScale;
float inZ = ( i + 1 ) * zScale;
float outX = inX + FadePoints[ i ][ 0 ];
float outZ = inZ + FadePoints[ i ][ 1 ];
pFade->Colour( Colours[ i ] );
pFade->Coord( inX, inZ, 0.0f );
pFade->Colour( Black );
pFade->Coord( outX, outZ, 0.0f );
}
p3d::pddi->EndPrims( pFade );
p3d::stack->Pop();
END_PROFILE("GeometryVehicle::DisplayLights")
}
//=============================================================================
// GeometryVehicle::FindAndTurnOffWheels
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void GeometryVehicle::FindAndTurnOffWheels()
{
int i;
for(i = 0; i < 4; i++)
{
tPose* p3dPose = mCompositeDrawable->GetPose();
char buffy[128];
sprintf(buffy, "w%d", i);
int jointIndex = p3dPose->FindJointIndex(buffy);
int j;
for(j = 0; j < mCompositeDrawable->GetNumDrawableElement(); j++)
{
tCompositeDrawable::DrawablePropElement* prop = (tCompositeDrawable::DrawablePropElement*)(mCompositeDrawable->GetDrawableElement(j));
if(prop && prop->GetPoseIndex() == jointIndex)
{
prop->SetVisibility(false);
}
}
}
}
//=============================================================================
// GeometryVehicle::FindAndTurnOffFrontWheelsOnly
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void GeometryVehicle::FindAndTurnOffFrontWheelsOnly()
{
int i;
for(i = 2; i < 4; i++)
{
tPose* p3dPose = mCompositeDrawable->GetPose();
char buffy[128];
sprintf(buffy, "w%d", i);
int jointIndex = p3dPose->FindJointIndex(buffy);
int j;
for(j = 0; j < mCompositeDrawable->GetNumDrawableElement(); j++)
{
tCompositeDrawable::DrawablePropElement* prop = (tCompositeDrawable::DrawablePropElement*)(mCompositeDrawable->GetDrawableElement(j));
if(prop && prop->GetPoseIndex() == jointIndex)
{
prop->SetVisibility(false);
}
}
}
}
//=============================================================================
// GeometryVehicle::FindHeadLightBillboardJoints
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void GeometryVehicle::FindHeadLightBillboardJoints()
{
// grab the pose
tPose* p3dPose = mCompositeDrawable->GetPose();
// grab the headlight bbqgs from common section
// put in left headlight
char buffy[128];
sprintf( buffy, "hll" );
int left = p3dPose->FindJointIndex( buffy );
if( left >= 0 )
{
for( int i=0; i<VehicleCentral::NUM_HEADLIGHT_BBQGS; i++ )
{
rAssert( GetVehicleCentral()->mHeadLights[i] );
mCompositeDrawable->AddProp( GetVehicleCentral()->mHeadLights[i], left );
}
}
// now the right side
sprintf( buffy, "hlr" );
int right = p3dPose->FindJointIndex( buffy );
if( right >= 0 )
{
for( int i=0; i<VehicleCentral::NUM_HEADLIGHT_BBQGS; i++ )
{
rAssert( GetVehicleCentral()->mHeadLights[i] );
mCompositeDrawable->AddProp( GetVehicleCentral()->mHeadLights[i], right );
}
}
}
//=============================================================================
// GeometryVehicle::FindBrakeLightBillboardJoints
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void GeometryVehicle::FindBrakeLightBillboardJoints()
{
int i;
for(i = 1; i < 5; i++) // 'cause Kevin starts counting at 1, not 0
{
tPose* p3dPose = mCompositeDrawable->GetPose();
char buffy[128];
sprintf(buffy, "brake%d", i);
int jointIndex = p3dPose->FindJointIndex(buffy);
int j;
for(j = 0; j < mCompositeDrawable->GetNumDrawableElement(); j++)
{
tCompositeDrawable::DrawablePropElement* prop = (tCompositeDrawable::DrawablePropElement*)(mCompositeDrawable->GetDrawableElement(j));
if(prop && prop->GetPoseIndex() == jointIndex)
{
//mBrakeLights[i - 1] = (tBillboardQuadGroup*) prop->GetDrawable();
tBillboardQuadGroup* bbqg = dynamic_cast<tBillboardQuadGroup*>( prop->GetDrawable() );
if( bbqg != NULL )
{
tRefCounted::Assign( mBrakeLights[i - 1], bbqg );
// the structure for storing the original colors only supports 1 quad per quadgroup
rAssert( mBrakeLights[i-1]->GetNumQuads() == 1 );
tBillboardQuad* quad = mBrakeLights[i-1]->GetQuad( 0 );
mOriginalBrakeLightColours[i-1] = quad->GetColour();
mBrakeLightJoints[i - 1] = jointIndex;
}
}
}
}
for(i = 1; i < 5; i++) // 'cause Kevin starts counting at 1, not 0
{
tPose* p3dPose = mCompositeDrawable->GetPose();
char buffy[128];
sprintf(buffy, "rev%d", i);
int jointIndex = p3dPose->FindJointIndex(buffy);
int j;
for(j = 0; j < mCompositeDrawable->GetNumDrawableElement(); j++)
{
tCompositeDrawable::DrawablePropElement* prop = (tCompositeDrawable::DrawablePropElement*)(mCompositeDrawable->GetDrawableElement(j));
if(prop && prop->GetPoseIndex() == jointIndex)
{
prop->SetVisibility(false);
mReverseLightJoints[i - 1] = jointIndex;
}
}
}
}
//=============================================================================
// GeometryVehicle::FindGhostGlowBillboards
//=============================================================================
// Description: Comment
//
// Parameters: ( const char* model )
//
// Return: void
//
//=============================================================================
void GeometryVehicle::FindGhostGlowBillboards( const char* model )
{
int count = 0;
for( int i = 0; i<NUM_GHOSTGLOW_BBQGS; i++ )
{
char name[64];
sprintf( name, "%sGlow%dShape", model, i+1 );
tUID test = tEntity::MakeUID( name );
for( int j=0; j<mCompositeDrawable->GetNumDrawableElement(); j++ )
{
tCompositeDrawable::DrawablePropElement* prop =
(tCompositeDrawable::DrawablePropElement*)(mCompositeDrawable->GetDrawableElement(j));
if( prop && prop->GetUID() == test )
{
tBillboardQuadGroup* bbqg = dynamic_cast<tBillboardQuadGroup*>( prop->GetDrawable() );
if( bbqg != NULL )
{
tRefCounted::Assign( mGhostGlows[i], bbqg );
for( int j=0; j<mGhostGlows[i]->GetNumQuads(); j++ )
{
tBillboardQuad* quad = mGhostGlows[i]->GetQuad( j );
rAssert( quad );
mOriginalGhostGlowColours[count] = quad->GetColour();
count++;
}
}
}
}
}
}
//=============================================================================
// GeometryVehicle::FindNukeGlowBillboards
//=============================================================================
// Description: Comment
//
// Parameters: ( const char* model )
//
// Return: void
//
//=============================================================================
void GeometryVehicle::FindNukeGlowBillboards( const char* model )
{
int count = 0;
for( int i = 0; i<NUM_NUKEGLOW_BBQGS; i++ )
{
char name[64];
sprintf( name, "nucGlowGroupShape" );
tUID test = tEntity::MakeUID( name );
for( int j=0; j<mCompositeDrawable->GetNumDrawableElement(); j++ )
{
tCompositeDrawable::DrawablePropElement* prop =
(tCompositeDrawable::DrawablePropElement*)(mCompositeDrawable->GetDrawableElement(j));
if( prop && prop->GetUID() == test )
{
tBillboardQuadGroup* bbqg = dynamic_cast<tBillboardQuadGroup*>( prop->GetDrawable() );
if( bbqg != NULL )
{
tRefCounted::Assign( mNukeGlows[i], bbqg );
for( int j=0; j<mNukeGlows[i]->GetNumQuads(); j++ )
{
tBillboardQuad* quad = mNukeGlows[i]->GetQuad( j );
rAssert( quad );
mOriginalNukeGlowColours[count] = quad->GetColour();
count++;
}
}
}
}
}
}
//=============================================================================
// GeometryVehicle::SetCollectibleHardpointPosition
//=============================================================================
// Description: Comment
//
// Parameters: ( const rmt::Vector& position )
//
// Return: void
//
//=============================================================================
void GeometryVehicle::SetCollectibleHardpointPosition( const rmt::Vector& position )
{
// Use the default orientation, but replace the translational compoonent
m_CollectibleTransform = DEFAULT_COLLECTIBLE_TRANSFORM;
m_CollectibleTransform.FillTranslate( position );
}
//=============================================================================
// GeometryVehicle::SetCollectibleHardpointTransform
//=============================================================================
// Description: Comment
//
// Parameters: ( float rotx ,float roty ,float rotz, const rmt::Vector& position )
//
// Return: void
//
//=============================================================================
void GeometryVehicle::SetCollectibleHardpointTransform( float rotx ,float roty ,float rotz,
const rmt::Vector& position )
{
m_CollectibleTransform.Identity();
m_CollectibleTransform.FillRotateXYZ( rotx, roty, rotz );
m_CollectibleTransform.FillTranslate( position );
}
//=============================================================================
// GeometryVehicle::ShowBrakeLights
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void GeometryVehicle::ShowBrakeLights()
{
mBrakeLightsOn = true;
/*
int i;
for(i = 0; i < 4; i++)
{
if(mBrakeLightJoints[i] != -1)
{
this->HideFlappingPiece(mBrakeLightJoints[i], false);
}
}
*/
}
//=============================================================================
// GeometryVehicle::HideBrakeLights
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void GeometryVehicle::HideBrakeLights()
{
mBrakeLightsOn = false;
/*
int i;
for(i = 0; i < 4; i++)
{
if(mBrakeLightJoints[i] != -1)
{
this->HideFlappingPiece(mBrakeLightJoints[i], true);
}
}
*/
}
//=============================================================================
// GeometryVehicle::ShowReverseLights
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void GeometryVehicle::ShowReverseLights()
{
int i;
for(i = 0; i < 4; i++)
{
if(mReverseLightJoints[i] != -1)
{
this->HideFlappingPiece(mReverseLightJoints[i], false);
}
}
}
//=============================================================================
// GeometryVehicle::HideReverseLights
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void GeometryVehicle::HideReverseLights()
{
int i;
for(i = 0; i < 4; i++)
{
if(mReverseLightJoints[i] != -1)
{
this->HideFlappingPiece(mReverseLightJoints[i], true);
}
}
}
//=============================================================================
// GeometryVehicle::GetArt
//=============================================================================
// Description: Comment
//
// Parameters: (char* name)
//
// Return: bool
//
//=============================================================================
bool GeometryVehicle::GetArt( const char* name)
{
// expect a composite drawable named "name" in the file.
tCompositeDrawable* master = p3d::find<tCompositeDrawable>(name);
rTuneAssert( master != NULL );
#ifndef FINAL
if (master == NULL)
{
char buffer [255];
sprintf(buffer,"Script ERROR: Can't Find Vehicle:%s Make sure you loaded it!\n",name);
rTuneAssertMsg(0,buffer);
}
#endif
mCompositeDrawable = master->Clone();
//mCompositeDrawable = p3d::find<tCompositeDrawable>(name);
rAssert(mCompositeDrawable);
mCompositeDrawable->AddRef();
{
char controllerName[255];
strcpy( controllerName, "EFX_" );
strcat( controllerName, name );
strcat( controllerName, "velocpartSystShape" );
tEffectController* particleSysController = p3d::find < tEffectController >( controllerName );
if ( particleSysController != NULL )
{
tEffect* effect = particleSysController->GetEffect();
rAssert( dynamic_cast< tParticleSystem* >( effect ) != NULL );
tParticleSystem* particleSystem = static_cast< tParticleSystem* > ( effect );
mVariableEmissionParticleSystem = particleSystem;
mVariableEmissionParticleSystem->AddRef();
}
}
/////////////////////////////////////////////////////////////////////////////////////
// Traffic "swatches" (in a sense)
// Any car using traffic model (regardless of whether they are in fact traffic cars)
// Must contain a trafficbodydrawable so that it will render correctly (due to fading
// and swatch tricks done for traffic models).
if( IsTrafficModel() )
{
mUsingTrafficModel = true;
// Grab the shader to be used for swatches
char shadername[64];
sprintf( shadername, "%s_m", name );
tShader* bodyShade = p3d::find<tShader>( shadername );
// Find the body prop in compositedrawable's list of elements by name
// e.g. compactAShape
char propname[64];
sprintf( propname, "%sShape", name );
tUID uid = tEntity::MakeUID(propname);
int poseIndex = -1;
tCompositeDrawable::DrawablePropElement* body = NULL;
for( int i=0; i<mCompositeDrawable->GetNumDrawableElement(); i++ )
{
body = (tCompositeDrawable::DrawablePropElement*) (mCompositeDrawable->GetDrawableElement(i));
if( body != NULL )
{
if( body->GetDrawable()->GetUID() == uid )
{
poseIndex = i;
break;
}
}
}
if( poseIndex > -1 && body != NULL )
{
// create a trafficbodydrawable
tRefCounted::Assign( mTrafficBodyDrawable, new TrafficBodyDrawable() );
rAssert( mTrafficBodyDrawable );
// store away the body prop's old drawable
rAssert( body->GetDrawable() != NULL );
mTrafficBodyDrawable->SetBodyPropDrawable( body->GetDrawable() );
// Grab the shader for the vehicle chassis and store it too
if( bodyShade == NULL )
{
rDebugPrintf( "Warning: Couldn't find shader \"%s\" for traffic vehicle %s. Chassis color randomization will not apply to this vehicle.\n",
shadername, name );
}
mTrafficBodyDrawable->SetBodyShader( bodyShade );
// make the new traffic body drawable the drawable for the body prop
body->SetDrawable( mTrafficBodyDrawable );
}
else
{
rDebugPrintf( "Warning: Couldn't find tCompositeDrawable prop \"%s\" for traffic vehicle %s. Chassis color randomization will not apply to this vehicle.\n",
propname, name );
}
// Find the door prop in compositedrawable's list of elements by name
// e.g. compactAShape
sprintf( propname, "doorPRotShape" );
uid = tEntity::MakeUID(propname);
poseIndex = -1;
body = NULL;
for( int i=0; i<mCompositeDrawable->GetNumDrawableElement(); i++ )
{
body = (tCompositeDrawable::DrawablePropElement*)
(mCompositeDrawable->GetDrawableElement(i));
if( body != NULL )
{
if( body->GetDrawable()->GetUID() == uid )
{
poseIndex = i;
break;
}
}
}
if( poseIndex > -1 && body != NULL )
{
// create a trafficbodydrawable
tRefCounted::Assign( mTrafficDoorDrawable, new TrafficBodyDrawable() );
rAssert( mTrafficDoorDrawable );
// store away the body prop's old drawable
rAssert( body->GetDrawable() != NULL );
mTrafficDoorDrawable->SetBodyPropDrawable( body->GetDrawable() );
// Grab the shader for the vehicle chassis and store it too
if( bodyShade == NULL )
{
rDebugPrintf( "Warning: Couldn't find shader \"%s\" for traffic vehicle %s. Chassis color randomization will not apply to this vehicle.\n",
shadername, name );
}
mTrafficDoorDrawable->SetBodyShader( bodyShade );
// make the new traffic body drawable the drawable for the body prop
body->SetDrawable( mTrafficDoorDrawable );
}
else
{
rDebugPrintf( "Warning: Couldn't find tCompositeDrawable prop \"%s\" for traffic vehicle %s. Chassis color randomization will not apply to this vehicle.\n",
propname, name );
}
}
// is this ok for release?
// I think so
// little hack just for frink
// no wheels
if( strcmp(name, "frink_v") == 0 || strcmp(name, "honor_v") == 0 || strcmp(name, "hbike_v") == 0 ||
strcmp(name, "witchcar") == 0 || strcmp(name, "ship") == 0 || strcmp(name, "mono_v") == 0 )
{
FindAndTurnOffWheels();
}
if( strcmp( name, "frink_v" ) == 0 )
{
int count = 0;
tRefCounted::Assign( mRefractionShader[ count++ ], p3d::find< tShader >( "special_m" ) ); //must be first
tRefCounted::Assign( mRefractionShader[ count++ ], p3d::find< tShader >( "frink_vInt_m" ) );
tRefCounted::Assign( mRefractionShader[ count++ ], p3d::find< tShader >( "frink_vTrim_m" ) );
tRefCounted::Assign( mRefractionShader[ count++ ], p3d::find< tShader >( "frink_vDoorPNorm_m" ) );
tRefCounted::Assign( mRefractionShader[ count++ ], p3d::find< tShader >( "frink_vExtras_m" ) );
tRefCounted::Assign( mRefractionShader[ count++ ], p3d::find< tShader >( "frink_vHoodNorm_m" ) );
tRefCounted::Assign( mRefractionShader[ count++ ], p3d::find< tShader >( "frink_vVent_m" ) );
tRefCounted::Assign( mRefractionShader[ count++ ], p3d::find< tShader >( "frink_vcoil_m" ) );
tRefCounted::Assign( mRefractionShader[ count++ ], p3d::find< tShader >( "BottomA_m" ) );
tRefCounted::Assign( mRefractionShader[ count++ ], p3d::find< tShader >( "frink_vDoorDNorm_m" ) );
tRefCounted::Assign( mRefractionShader[ count++ ], p3d::find< tShader >( "engine_m" ) );
tRefCounted::Assign( mRefractionShader[ count++ ], p3d::find< tShader >( "frink_vBackNorm_m" ) );
int size = count;
int i;
for( i = 0; i < size; ++i )
{
rAssert( mRefractionShader[ i ] != NULL );
}
#ifdef RAD_WIN32
tPose* p3dPose = mCompositeDrawable->GetPose();
char buffy[128];
sprintf(buffy, "frinkArcGroup", i);
int jointIndex = p3dPose->FindJointIndex(buffy);
for(int j = 0; j < mCompositeDrawable->GetNumDrawableElement(); j++)
{
tCompositeDrawable::DrawablePropElement* prop = (tCompositeDrawable::DrawablePropElement*)(mCompositeDrawable->GetDrawableElement(j));
if(prop && prop->GetPoseIndex() == jointIndex)
{
tBillboardQuadGroup* bbqg = dynamic_cast<tBillboardQuadGroup*>( prop->GetDrawable() );
if( bbqg )
{
tRefCounted::Assign( mFrinkArc, bbqg );
for( int k = 0; k < NUM_FRINKARC_BBQS; k++ )
{
tBillboardQuad* quad = mFrinkArc->GetQuad( k );
mOriginalFrinkArcColour[k] = quad->GetColour();
}
}
}
}
#endif
}
if(strcmp(name, "rocke_v") == 0)
{
this->FindAndTurnOffFrontWheelsOnly();
}
// store brake light joint indices
FindBrakeLightBillboardJoints();
FindHeadLightBillboardJoints();
if( GetGameplayManager()->GetGameType() == GameplayManager::GT_SUPERSPRINT )
{
mHeadLightScale = 1.0f;
mBrakeLightScale = 0.4f;
if( mVehicleOwner->mVehicleType == VT_USER || mVehicleOwner->mVehicleType == VT_AI )
{
EnableLights( true );
}
}
else
{
// if we are on a level other than 4 or 7, we want to turn the headlights off
if( GetGameplayManager()->GetCurrentLevelIndex() == RenderEnums::L1 || // BROAD DAYLIGHT
GetGameplayManager()->GetCurrentLevelIndex() == RenderEnums::L2 )
{
// Which values should we use for headlights and brakelights
// when we just have running lights (when not braking)
mHeadLightScale = 0.0f;
mBrakeLightScale = 0.0f;//0.4f;
}
else if( GetGameplayManager()->GetCurrentLevelIndex() == RenderEnums::L3 ) // SUNSET
{
mHeadLightScale = 0.2f;
mBrakeLightScale = 0.3f;
}
else if( GetGameplayManager()->GetCurrentLevelIndex() == RenderEnums::L5 ) // DUSK
{
mHeadLightScale = 0.4f;
mBrakeLightScale = 0.4f;
}
else if( GetGameplayManager()->GetCurrentLevelIndex() == RenderEnums::L6 ) // TWILIGHT
{
mHeadLightScale = 0.4f;
mBrakeLightScale = 0.4f;
}
else if( GetGameplayManager()->GetCurrentLevelIndex() == RenderEnums::L4 || // NIGHT
GetGameplayManager()->GetCurrentLevelIndex() == RenderEnums::L7 )
{
// full headlights on night levels
mHeadLightScale = 0.6f;
mBrakeLightScale = 0.4f;
}
if( mVehicleOwner->mVehicleType == VT_USER )
{
EnableLights( false );
}
}
// hack for ghost ship
if( strcmp(name, "ship") == 0 )
{
mHasGhostGlow = true;
FindGhostGlowBillboards( name );
}
if( strcmp( name, "nuctruck" ) == 0 )
{
mHasNukeGlow = true;
FindNukeGlowBillboards( name );
}
// TODO - might need to clone this too
// mAnimController = p3d::find<tPoseAnimationController>(buffy);
// We will advance the multicontroller, not just the posecontroller
FindAnimationControllers( name );
char buffy[128];
sprintf(buffy, "PTRN_%s", name);
tPoseAnimationController* poseController = p3d::find<tPoseAnimationController>(buffy);
// only play an anim if it's there:
if( poseController )
{
poseController->SetPose(mCompositeDrawable->GetPose());
// TODO
// cast here might be unsafe in the general case
//mAnim = (tPoseAnimation*)(poseController->GetAnimation());
mAnim = poseController->GetAnimation();
mAnim->AddRef(); // ? already addref'd by controller?
mAnim->SetCyclic(true);
float numFrames = mAnim->GetNumFrames();
float speed = mAnim->GetSpeed();
rAssert( numFrames != 0 );
mAnimRevPerSecondBase = speed / (float)numFrames;
}
char roofShaderName[64];
sprintf( roofShaderName, "%sRoof_m", name );
tRefCounted::Assign( mRoofShader, p3d::find<tShader>( tEntity::MakeUID( roofShaderName ) ) );
FindRoofGeometry( name );
if( mRoofOpacShape && mRoofAlphaShape )
{
mRoofOpacShape->SetVisibility( true );
mRoofAlphaShape->SetVisibility( false );
}
if ( mVehicleOwner->GetNameObject() == "gramR_v" )
{
SetCollectibleHardpointPosition( JEEP_COLLECTIBLE_POS );
}
else if ( mVehicleOwner->GetNameObject() == "homer_v" )
{
SetCollectibleHardpointPosition( BARRACUDA_COLLECTIBLE_POS );
}
else if ( mVehicleOwner->GetNameObject() == "dune_v" )
{
SetCollectibleHardpointTransform( DUNE_COLLECTIBLE_ROT.x,
DUNE_COLLECTIBLE_ROT.y,
DUNE_COLLECTIBLE_ROT.z,
DUNE_COLLECTIBLE_POS);
}
else if ( mVehicleOwner->GetNameObject() == "hallo" )
{
SetCollectibleHardpointPosition( HALLO_COLLECTIBLE_POS );
}
else if ( mVehicleOwner->GetNameObject() == "coffin" )
{
SetCollectibleHardpointPosition( COFFIN_COLLECTIBLE_POS );
}
else if ( mVehicleOwner->GetNameObject() == "witchcar" )
{
SetCollectibleHardpointPosition( WITCH_COLLECTIBLE_POS );
}
if(mVehicleOwner->mVehicleType == VT_USER)
{
tCompositeDrawable::DrawableElement* agnes = mCompositeDrawable->FindNode("agnusGeoShape");
if(agnes)
{
if(GetVehicleCentral()->IsDriverSuppressed("skinner"))
{
agnes->SetVisibility(false);
}
}
}
//THERE'S AN UNTRACKED ALLOCATION HERE!
HeapMgr()->PushHeap( GMA_LEVEL_OTHER );
HeapMgr()->PopHeap(GMA_LEVEL_OTHER);
return FindDamageShadersAndTextures(name);
//return true;
}
//=============================================================================
// GeometryVehicle::FindDamageShadersAndTextures
//=============================================================================
// Description: Comment
//
// Parameters: (char* name)
//
// Return: void
//
//=============================================================================
bool GeometryVehicle::FindDamageShadersAndTextures( const char* carname)
{
// names we expect to have:
//
// for shaders
// <carname>DoorDNorm_m
// <carname>DoorPNorm_m
// <carname>HoodNorm_m
// <carname>BackNorm_m
// for normal textures:
// <carname>DoorDNorm.bmp
// <carname>DoorPNorm.bmp
// <carname>HoodNorm.bmp
// <carname>BackNorm.bmp current: BarTrunk.bmp
// for damage textures:
// <carname>DoorPDam.bmp current: BarracudaDoorPDam.bmp
// <carname>HoodDam.bmp current: BarracudaHoodDam.bmp
// <carname>DoorDDam.bmp current: BarracudaDoorDDam.bmp
// <carname>BackDam.bmp current: BarracudaBackDam.bmp
// !!
// TODO - search a particular inventory section only?
char buffy[128];
// change logic here - if we find at least one set of shader, normal texture, damage texture
// return true.
bool result = false;
bool doorD = true;
bool doorP = true;
bool hood = true;
bool trunk = true;
//-------
//shaders
//-------
sprintf(buffy, "%sDoorDNorm_m", carname);
mDoorDShader = p3d::find<tShader>(buffy);
if(mDoorDShader)
{
mDoorDShader->AddRef();
}
else
{
rTunePrintf("vehicle damage: cant find %s\n", buffy);
//result = false;
doorD = false;
}
sprintf(buffy, "%sDoorPNorm_m", carname);
mDoorPShader = p3d::find<tShader>(buffy);
if(mDoorPShader)
{
mDoorPShader->AddRef();
}
else
{
rTunePrintf("vehicle damage: cant find %s\n", buffy);
//result = false;
doorP = false;
}
sprintf(buffy, "%sHoodNorm_m", carname);
mHoodShader = p3d::find<tShader>(buffy);
if(mHoodShader)
{
mHoodShader->AddRef();
}
else
{
rTunePrintf("vehicle damage: cant find %s\n", buffy);
//result = false;
hood = false;
}
sprintf(buffy, "%sBackNorm_m", carname);
mTrunkShader = p3d::find<tShader>(buffy);
if(mTrunkShader)
{
mTrunkShader->AddRef();
}
else
{
rTunePrintf("vehicle damage: cant find %s\n", buffy);
//result = false;
trunk = false;
}
//----------------
// normal textures
//----------------
sprintf(buffy, "%sDoorDNorm.bmp", carname);
mDoorDTextureNorm = p3d::find<tTexture>(buffy);
if(mDoorDTextureNorm)
{
mDoorDTextureNorm->AddRef();
}
else
{
rTunePrintf("vehicle damage: cant find %s\n", buffy);
//result = false;
doorD = false;
}
sprintf(buffy, "%sDoorPNorm.bmp", carname);
mDoorPTextureNorm = p3d::find<tTexture>(buffy);
if(mDoorPTextureNorm)
{
mDoorPTextureNorm->AddRef();
}
else
{
rTunePrintf("vehicle damage: cant find %s\n", buffy);
//result = false;
doorP = false;
}
sprintf(buffy, "%sHoodNorm.bmp", carname);
mHoodTextureNorm = p3d::find<tTexture>(buffy);
if(mHoodTextureNorm)
{
mHoodTextureNorm->AddRef();
}
else
{
rTunePrintf("vehicle damage: cant find %s\n", buffy);
//result = false;
hood = false;
}
sprintf(buffy, "%sBackNorm.bmp", carname);
mTrunkTextureNorm = p3d::find<tTexture>(buffy);
if(mTrunkTextureNorm)
{
mTrunkTextureNorm->AddRef();
}
else
{
rTunePrintf("vehicle damage: cant find %s\n", buffy);
//result = false;
trunk = false;
}
//----------------
// damage textures
//----------------
sprintf(buffy, "%sDoorDDam.bmp", carname);
mDoorDTextureDam = p3d::find<tTexture>(buffy);
if(mDoorDTextureDam)
{
mDoorDTextureDam->AddRef();
}
else
{
rTunePrintf("vehicle damage: cant find %s\n", buffy);
//result = false;
doorD = false;
}
sprintf(buffy, "%sDoorPDam.bmp", carname);
mDoorPTextureDam = p3d::find<tTexture>(buffy);
if(mDoorPTextureDam)
{
mDoorPTextureDam->AddRef();
}
else
{
rTunePrintf("vehicle damage: cant find %s\n", buffy);
//result = false;
doorP = false;
}
sprintf(buffy, "%sHoodDam.bmp", carname);
mHoodTextureDam = p3d::find<tTexture>(buffy);
if(mHoodTextureDam)
{
mHoodTextureDam->AddRef();
}
else
{
rTunePrintf("vehicle damage: cant find %s\n", buffy);
//result = false;
hood = false;
}
sprintf(buffy, "%sBackDam.bmp", carname);
mTrunkTextureDam = p3d::find<tTexture>(buffy);
if(mTrunkTextureDam)
{
mTrunkTextureDam->AddRef();
}
else
{
rTunePrintf("vehicle damage: cant find %s\n", buffy);
//result = false;
trunk = false;
}
// now if any of doorD, doorP, hood, or trunk are true - return true
result = doorD | doorP | hood | trunk;
//----------------------------------------------------
// all of the above was if we are a type 1 or 2 damage
//
// for type 3 we just expect the following:
//----------------------------------------------------
//-------
// shader
//-------
/*
// ancient fucking history
sprintf(buffy, "%sChassisNorm_m", carname);
mChassisShader = p3d::find<tShader>(buffy);
if(mChassisShader)
{
mChassisShader->AddRef();
}
//---------------
// normal texture
//---------------
sprintf(buffy, "%sChassisNorm.bmp", carname);
mChassisTextureNorm = p3d::find<tTexture>(buffy);
if(mChassisTextureNorm)
{
mChassisTextureNorm->AddRef();
}
//---------------
// damage texture
//---------------
sprintf(buffy, "%sChassisDam.bmp", carname);
mChassisTextureDam = p3d::find<tTexture>(buffy);
if(mChassisTextureDam)
{
mChassisTextureDam->AddRef();
}
*/
return result;
}
//=============================================================================
// GeometryVehicle::SetSmoke
//=============================================================================
// Description: Comment
//
// Parameters: (ParticleEnum::ParticleID pid)
//
// Return: void
//
//=============================================================================
void GeometryVehicle::SetEngineSmoke(ParticleEnum::ParticleID pid)
{
mEngineParticleAttr.mType = pid;
}
/*
ParticleEnum::ParticleID mType;
// only one bias so far, the emission bias
// other biases would be simple to put in
// NumParticles/Life/Speed/Weight/Gravity/Drag/Size/Spin
float mEmissionBias;
*/
//=============================================================================
// GeometryVehicle::SetWheelSmoke
//=============================================================================
// Description: Comment
//
// Parameters: (ParticleEnum::ParticleID pid, float bias)
//
// Return: void
//
//=============================================================================
void GeometryVehicle::SetWheelSmoke( int wheel, ParticleEnum::ParticleID pid, float bias)
{
switch( wheel )
{
case 0:
mRightWheelParticleAttr.mType = pid;
mRightWheelParticleAttr.mEmissionBias = bias;
break;
case 1:
mLeftWheelParticleAttr.mType = pid;
mLeftWheelParticleAttr.mEmissionBias = bias;
break;
default:
mRightWheelParticleAttr.mType = pid;
mRightWheelParticleAttr.mEmissionBias = bias;
mLeftWheelParticleAttr.mType = pid;
mLeftWheelParticleAttr.mEmissionBias = bias;
break;
};
}
//=============================================================================
// GeometryVehicle::DamageTextureChassis
//=============================================================================
// Description: Comment
//
// Parameters: (bool on)
//
// Return: void
//
//=============================================================================
void GeometryVehicle::DamageTextureChassis(bool on)
{
rAssert(0); // this is fucking history
if(mChassisShader)
{
if(on)
{
mChassisShader->SetTexture(PDDI_SP_BASETEX, mChassisTextureDam);
}
else
{
mChassisShader->SetTexture(PDDI_SP_BASETEX, mChassisTextureNorm);
}
}
}
//=============================================================================
// GeometryVehicle::DamageTextureTrunk
//=============================================================================
// Description: Comment
//
// Parameters: (bool on)
//
// Return: void
//
//=============================================================================
void GeometryVehicle::DamageTextureTrunk(bool on)
{
if(mTrunkShader && mTrunkTextureDam && mTrunkTextureNorm)
{
if(on)
{
mTrunkShader->SetTexture(PDDI_SP_BASETEX, mTrunkTextureDam);
}
else
{
mTrunkShader->SetTexture(PDDI_SP_BASETEX, mTrunkTextureNorm);
}
}
}
//=============================================================================
// GeometryVehicle::DamageTextureHood
//=============================================================================
// Description: Comment
//
// Parameters: (bool on)
//
// Return: void
//
//=============================================================================
void GeometryVehicle::DamageTextureHood(bool on)
{
if(mHoodShader && mHoodTextureDam && mHoodTextureNorm)
{
if(on)
{
mHoodShader->SetTexture(PDDI_SP_BASETEX, mHoodTextureDam);
}
else
{
mHoodShader->SetTexture(PDDI_SP_BASETEX, mHoodTextureNorm);
}
}
}
//=============================================================================
// GeometryVehicle::DamageTextureDoorP
//=============================================================================
// Description: Comment
//
// Parameters: (bool on)
//
// Return:
//
//=============================================================================
void GeometryVehicle::DamageTextureDoorP(bool on)
{
if(mDoorPShader && mDoorPTextureDam && mDoorPTextureNorm)
{
if(on)
{
mDoorPShader->SetTexture(PDDI_SP_BASETEX, mDoorPTextureDam);
}
else
{
mDoorPShader->SetTexture(PDDI_SP_BASETEX, mDoorPTextureNorm);
}
}
}
//=============================================================================
// GeometryVehicle::DamageTextureDoorD
//=============================================================================
// Description: Comment
//
// Parameters: (bool on)
//
// Return: void
//
//=============================================================================
void GeometryVehicle::DamageTextureDoorD(bool on)
{
if(mDoorDShader && mDoorDTextureDam && mDoorDTextureNorm)
{
if(on)
{
mDoorDShader->SetTexture(PDDI_SP_BASETEX, mDoorDTextureDam);
}
else
{
mDoorDShader->SetTexture(PDDI_SP_BASETEX, mDoorDTextureNorm);
}
}
}
//=============================================================================
// GeometryVehicle::HideFlappingPiece
//=============================================================================
// Description: Comment
//
// Parameters: (int jointindex)
//
// Return: void
//
//=============================================================================
void GeometryVehicle::HideFlappingPiece(int jointindex, bool doit)
{
//tCompositeDrawable::DrawablePropElement* prop = (tCompositeDrawable::DrawablePropElement*)(mCompositeDrawable->GetDrawableElement(jointindex));
int i;
for(i = 0; i < mCompositeDrawable->GetNumDrawableElement(); i++)
{
tCompositeDrawable::DrawablePropElement* prop = (tCompositeDrawable::DrawablePropElement*)(mCompositeDrawable->GetDrawableElement(i));
if(prop && prop->GetPoseIndex() == jointindex)
{
//prop->SetVisibility(false);
prop->SetVisibility(!doit);
}
}
}
//------------------------------------------------------------------------
void GeometryVehicle::Update(float dt)
{
AdvanceAnimationControllers( dt * 1000.0f );
rmt::Vector vehicleVelocity;
mVehicleOwner->GetVelocity( &vehicleVelocity );
// Certain animations and particle systems are scaled by the velocity
// Calculate what % the scalar should be
float animationSpeedBias = vehicleVelocity.Magnitude() / PARTICLE_SYSTEM_MAX_VELOCITY;
animationSpeedBias = animationSpeedBias > 1.0f ? 1.0f : animationSpeedBias;
animationSpeedBias = animationSpeedBias < 0.0f ? 0.0f : animationSpeedBias;
if ( mVariableEmissionParticleSystem != NULL )
{
mVariableEmissionParticleSystem->SetBias( p3dParticleSystemConstants::EmitterBias::EMISSION, animationSpeedBias );
}
//
// Vary prof frink's refraction shader every frame
//
const tName& name = mVehicleOwner->GetNameObject();
if( name == "frink_v" )
{
float topSpeed = mVehicleOwner->GetTopSpeed();
float percentOfTopSpeed = vehicleVelocity.Magnitude() / topSpeed;
float refraction = percentOfTopSpeed;
refraction = rmt::Clamp( refraction, 0.0f, 1.0f );
/*
//we adjust the refractive index based on distance from the camera
rmt::Vector pos = mVehicleOwner->GetPosition ();
rmt::Vector cameraPosition;
unsigned int index = GetSuperCamManager()->GetSCC( 0 )->GetActiveSuperCamIndex();
SuperCam* camera = GetSuperCamManager()->GetSCC( 0 )->GetSuperCam( index );
camera->GetPosition( &cameraPosition );
float distance = ( pos - cameraPosition ).Magnitude();
float refractionAmount = refractiveIndex;
//if( distance > 20 )
{
refractionAmount *= 5;
refractionAmount /= distance;
}
*/
//
// special case for the windshield shader
//
if( mRefractionShader[ 0 ] != NULL )
{
#ifdef RAD_GAMECUBE
float adjustedRefraction = refraction;
#else
float adjustedRefraction = 0.5f + (0.5f * refraction);
#endif
#ifndef RAD_WIN32
mRefractionShader[ 0 ]->SetFloat( PDDI_SP_REFRACTBLEND, adjustedRefraction );
mRefractionShader[ 0 ]->SetFloat( PDDI_SP_REFRACTINDEX, refractiveIndex );
#endif
}
//
// all other shaders
//
int i;
for( i = 1; i < MAX_REFRACTION_SHADERS; ++i )
{
if( mRefractionShader[ i ] != NULL )
{
#ifndef RAD_WIN32
mRefractionShader[ i ]->SetFloat( PDDI_SP_REFRACTBLEND, refraction );
mRefractionShader[ i ]->SetFloat( PDDI_SP_REFRACTINDEX, refractiveIndex );
#endif
}
}
}
// Update the collectible's position
if ( m_Collectible != NULL )
{
rmt::Matrix collectibleTransform;
collectibleTransform.Mult( m_CollectibleTransform, mVehicleOwner->mTransform );
m_Collectible->SetTransform( collectibleTransform );
}
}
//=============================================================================
// GeometryVehicle::SetTrafficBodyColour
//=============================================================================
// Description: Comment
//
// Parameters: ( pddiColour colour )
//
// Return: void
//
//=============================================================================
void GeometryVehicle::SetTrafficBodyColour( pddiColour colour )
{
if( mVehicleOwner->mVehicleType == VT_TRAFFIC || mVehicleOwner->mVehicleType == VT_USER )
{
if( mTrafficBodyDrawable != NULL )
{
mTrafficBodyDrawable->SetDesiredColour( colour );
}
if( mTrafficDoorDrawable != NULL )
{
mTrafficDoorDrawable->SetDesiredColour( colour );
}
}
}
//=============================================================================
// GeometryVehicle::GetP3DPose
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: tPose
//
//=============================================================================
tPose* GeometryVehicle::GetP3DPose()
{
if(mCompositeDrawable)
{
return mCompositeDrawable->GetPose();
}
else
{
return 0;
}
}
//=============================================================================
// GeometryVehicle::SetShadowAdjustments
//=============================================================================
// Description: Comment
//
// Parameters: ( float Adjustments[ 4 ][ 2 ] )
//
// Return: void
//
//=============================================================================
void GeometryVehicle::SetShadowAdjustments( float Adjustments[ 4 ][ 2 ] )
{
for( int i = 0; i < 4; ++i )
{
mShadowPointAdjustments[ i ][ 0 ] = Adjustments[ i ][ 0 ];
mShadowPointAdjustments[ i ][ 1 ] = Adjustments[ i ][ 1 ];
}
}
//=============================================================================
// GeometryVehicle::SetFadeAlpha
//=============================================================================
// Description: Comment
//
// Parameters: ( int fade )
//
// Return: void
//
//=============================================================================
void GeometryVehicle::SetFadeAlpha( int fade )
{
rAssert( 0 <= fade && fade <= 255 );
mFadeAlpha = fade;
}
// Hack:
// We hard code the traffic models so we can tell which vehicle
// needs special treatment in terms of fading... Be sure to add
// any new traffic models here or they won't fade properly.
//
// The problem is that the intbroadcast on all the shaders in
// this composite drawable is going to reset everyone's blend
// mode to BLEND_ALPHA... Brakelights, however, need BLEND_ADDITIVE
// and some cars (cCells, cPolice) have special light effects that
// have similar problems. Setting these all to BLEND_ALPHA will
// cause the billboards to not display properly, so we make sure
// we do an intbroadcast (using ProcessShaders()) only for cars
// that are using traffic models (including non-traffic cars such
// as mission AI cars).
//
// The alternative to this is to avoid using ProcessShaders() and
// set the appropriate shader for each composite drawable's element
// that need to fade independently... Could be messy...
// This hard-coded list is not so bad..
//
//=============================================================================
// GeometryVehicle::IsTrafficModel
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: bool
//
//=============================================================================
bool GeometryVehicle::IsTrafficModel()
{
rAssert( mVehicleOwner );
VehicleEnum::VehicleID ID = mVehicleOwner->mVehicleID;
if( ID == VehicleEnum::HUSKA ||
ID == VehicleEnum::COMPACTA ||
ID == VehicleEnum::PICKUPA ||
ID == VehicleEnum::MINIVANA ||
ID == VehicleEnum::SUVA ||
ID == VehicleEnum::SPORTSA ||
ID == VehicleEnum::SPORTSB ||
ID == VehicleEnum::SEDANA ||
ID == VehicleEnum::SEDANB ||
ID == VehicleEnum::TAXIA ||
ID == VehicleEnum::WAGONA ||
ID == VehicleEnum::COFFIN ||
ID == VehicleEnum::HALLO ||
ID == VehicleEnum::WITCHCAR ||
ID == VehicleEnum::SHIP ||
ID == VehicleEnum::AMBUL ||
ID == VehicleEnum::BURNSARM ||
ID == VehicleEnum::FISHTRUC ||
ID == VehicleEnum::GARBAGE ||
ID == VehicleEnum::ICECREAM ||
ID == VehicleEnum::ISTRUCK ||
ID == VehicleEnum::NUCTRUCK ||
ID == VehicleEnum::PIZZA ||
ID == VehicleEnum::SCHOOLBU ||
ID == VehicleEnum::VOTETRUC ||
ID == VehicleEnum::GLASTRUC )
{
return true;
}
return false;
}
//=============================================================================
// GeometryVehicle::FadeRoof
//=============================================================================
// Description: Comment
//
// Parameters: ( bool fade )
//
// Return: void
//
//=============================================================================
void GeometryVehicle::FadeRoof( bool fade )
{
rAssert( 0 <= INCAR_ROOF_ALPHA && INCAR_ROOF_ALPHA <= 255 );
mRoofTargetAlpha = (fade)? INCAR_ROOF_ALPHA : 255;
}
//=============================================================================
// GeometryVehicle::FindRoofGeometry
//=============================================================================
// Description: Comment
//
// Parameters: ( const char* model )
//
// Return: void
//
//=============================================================================
void GeometryVehicle::FindRoofGeometry( const char* model )
{
char opac[64];
sprintf(opac, "%sRoofOpacShape", model );
tUID opacID = tEntity::MakeUID( opac );
char alpha[64];
sprintf(alpha, "%sRoofAlphaShape", model );
tUID alphaID = tEntity::MakeUID( alpha );
for( int j = 0; j < mCompositeDrawable->GetNumDrawableElement(); j++)
{
tCompositeDrawable::DrawablePropElement* prop =
(tCompositeDrawable::DrawablePropElement*)
(mCompositeDrawable->GetDrawableElement(j));
if( prop )
{
tUID uid = prop->GetUID();
if( uid == opacID )
{
mRoofOpacShape = prop;
}
else if( uid == alphaID )
{
mRoofAlphaShape = prop;
}
}
}
}
//=============================================================================
// GeometryVehicle::EnableLights
//=============================================================================
// Description: Comment
//
// Parameters: ( bool enable )
//
// Return: void
//
//=============================================================================
void GeometryVehicle::EnableLights( bool enable )
{
mEnableLights = enable;
}
//=============================================================================
// GeometryVehicle::GetVehicleColour
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: tColour
//
//=============================================================================
tColour GeometryVehicle::GetVehicleColour()const
{
if ( mTrafficBodyDrawable != NULL )
{
return mTrafficBodyDrawable->GetDesiredColour();
}
else
{
const tColour DEFAULT_COLOUR( 128,128,128 );
return DEFAULT_COLOUR;
}
}
//=============================================================================
// GeometryVehicle::FindAnimationControllers
//=============================================================================
// Description: Comment
//
// Parameters: ( const char* multicontrollername )
//
// Return: void
//
//=============================================================================
void GeometryVehicle::FindAnimationControllers( const char* multicontrollername )
{
tMultiController* mc = p3d::find< tMultiController >( multicontrollername );
if( mc == NULL )
return;
HeapMgr()->PushHeap(GMA_LEVEL_OTHER);
// Iterate through the frame controllers and add them to our own list
for ( unsigned int i = 0 ; i < mc->GetNumTracks() ; i++ )
{
tFrameController* fc = mc->GetTrack( i )->Clone();
VehicleFrameController vfc;
vfc.trigger = eNone;
vfc.brakeBias = vfc.gasBias = vfc.speedBias = 0;
vfc.timeBias = 1.0f;
vfc.frameSetter = false;
GetSpecialController( fc->GetUID(), &vfc );
vfc.frameController = fc;
vfc.frameController->AddRef();
vfc.frameController->Reset();
vfc.frameController->SetCycleMode( FORCE_CYCLIC );
// What kind of animation controller are we dealing with?
// Possibly a pose controller?
tPoseAnimationController* poseController = dynamic_cast< tPoseAnimationController* >( vfc.frameController );
if ( poseController )
{
// The compositeDrawble::clone function allocates a brand new pose
// set the frame controller that this pose is the one to update upon
// Advance()
poseController->SetPose( mCompositeDrawable->GetPose() );
}
mFrameControllers.push_back( vfc );
}
HeapMgr()->PopHeap(GMA_LEVEL_OTHER);
}
//=============================================================================
// GeometryVehicle::GetSpecialController
//=============================================================================
// Description: Comment
//
// Parameters: ( tUID name, VehicleFrameController* outSpecialController )
//
// Return: bool
//
//=============================================================================
bool GeometryVehicle::GetSpecialController( tUID name, VehicleFrameController* outSpecialController )
{
bool wasFound = false;
// iterate through the preset "special" controllers and find any with the same name
for ( int i = 0 ; i < NUM_FRAME_CONTROLLERS ; i++ )
{
if ( name == tName::MakeUID( FRAME_CONTROLLER_DATA[i].name ) )
{
*outSpecialController = FRAME_CONTROLLER_DATA[i];
wasFound = true;
break;
}
}
return wasFound;
}
//=============================================================================
// GeometryVehicle::AdvanceAnimationControllers
//=============================================================================
// Description: Comment
//
// Parameters: ( float deltaTime )
//
// Return: void
//
//=============================================================================
void GeometryVehicle::AdvanceAnimationControllers( float deltaTime )
{
int numFCs = mFrameControllers.size();
float gas = mVehicleOwner->GetGas();
float speed = mVehicleOwner->GetSpeedKmh();
float brake = mVehicleOwner->GetBrake();
if ( mVehicleOwner->IsMovingBackward() )
speed *= -1;
FCTrigger trigger = eNone;
if ( mVehicleOwner->GetDeltaGas() > 0.001f )
{
trigger = eBackfire;
}
for ( int i = 0 ; i < numFCs ; i++ )
{
VehicleFrameController& vfc = mFrameControllers[i];
if ( vfc.frameSetter )
{
// This thing doesn't ever run linearly, it only sets the frame
// it uses specifically.
// Figure out which frame to set based upon vehicle attributes
float relativeframe;
float numFrames = vfc.frameController->GetNumFrames();
relativeframe = vfc.brakeBias * brake + vfc.gasBias * gas +
vfc.speedBias * speed;
vfc.frameController->SetFrame( relativeframe * numFrames );
vfc.frameController->Advance( 0.0f );
}
else
{
// Is the animation triggered by something?
// Check to see if it is or isn't
if ( trigger != eNone && trigger == vfc.trigger )
{
// Its a triggered animation thats been triggered
// If the animation isnt playing already then restart it
if ( vfc.frameController->GetRelativeSpeed() < 0.001f )
{
vfc.frameController->Reset();
vfc.frameController->SetRelativeSpeed( 1.0f );
}
if ( vfc.frameController->LastFrameReached() )
{
vfc.frameController->SetRelativeSpeed( 0 );
}
}
// Standard animation, apply biases and play
float advanceTime = vfc.timeBias * deltaTime;
if ( advanceTime < 0 ) advanceTime = 0;
float advanceGas = gas * vfc.gasBias * deltaTime;
if ( advanceGas < 0 ) advanceGas = 0;
float advanceBrake = brake * vfc.brakeBias * deltaTime;
if ( advanceBrake < 0 ) advanceBrake = 0;
float advanceSpeed = speed * vfc.speedBias * deltaTime;
if ( advanceSpeed < 0 ) advanceSpeed = 0;
float totalAdvanceTime = advanceTime + advanceGas - advanceBrake + advanceSpeed;
vfc.frameController->Advance( totalAdvanceTime );
}
}
}