The-Simpsons-Hit-and-Run/game/code/render/DSG/StaticPhysDSG.cpp

595 lines
17 KiB
C++

//========================================================================
// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
//
// File: StaticPhysDSG.cpp
//
// Description: Implementation for StaticPhysDSG class.
//
// History: Implemented --Devin [5/27/2002]
//========================================================================
//========================================
// System Includes
//========================================
#include <p3d/camera.hpp>
#include <p3d/matrixstack.hpp>
#include <p3d/utility.hpp>
#include <p3d/view.hpp>
#include <simcollision/collisionobject.hpp>
#include <simcollision/collisionvolume.hpp>
//========================================
// Project Includes
//========================================
#include <render/DSG/StaticPhysDSG.h>
#include <render/particles/particlemanager.h>
#include <render/breakables/breakablesmanager.h>
#include <render/IntersectManager/IntersectManager.h>
//************************************************************************
//
// Global Data, Local Data, Local Classes
//
//************************************************************************
// Bias that determines how much force is required to emit particles during a
// collision
const float STAT_PHYS_MASS_IMPULSE_PARTICLE_BIAS = 10.0f;
//************************************************************************
//
// Public Member Functions : StaticPhysDSG Interface
//
//************************************************************************
//========================================================================
// StaticPhysDSG::
//========================================================================
//
// Description:
//
// Parameters: None.
//
// Return: None.
//
// Constraints: None.
//
//========================================================================
StaticPhysDSG::StaticPhysDSG() :
mpShadow( NULL ),
mpShadowMatrix( NULL )
{
mpSimStateObj = NULL;
}
//========================================================================
// StaticPhysDSG::
//========================================================================
//
// Description:
//
// Parameters: None.
//
// Return: None.
//
// Constraints: None.
//
//========================================================================
StaticPhysDSG::~StaticPhysDSG()
{
BEGIN_PROFILE( "StaticPhysDSG Destroy" );
if(mpSimStateObj != NULL)
{
mpSimStateObj->Release();
}
if (mpShadow)
{
mpShadow->Release();
mpShadow = 0;
}
if (mpShadowMatrix != NULL )
{
delete mpShadowMatrix;
mpShadowMatrix = NULL;
}
END_PROFILE( "StaticPhysDSG Destroy" );
}
//========================================================================
// StaticPhysDSG::
//========================================================================
//
// Description:
//
// Parameters: None.
//
// Return: None.
//
// Constraints: None.
//
//========================================================================
void StaticPhysDSG::OnSetSimState( sim::SimState* ipSimState )
{
tRefCounted::Assign( mpSimStateObj, ipSimState );
//mpSimStateObj->mAIRefIndex = StaticPhysDSG::GetAIRef();
mpSimStateObj->mAIRefIndex = this->GetAIRef();
SetInternalState();
}
//========================================================================
// StaticPhysDSG::
//========================================================================
//
// Description:
//
// Parameters: None.
//
// Return: None.
//
// Constraints: None.
//
//========================================================================
sim::SimState* StaticPhysDSG::GetSimState() const
{
return mpSimStateObj;
}
///////////////////////////////////////////////////////////////////////
// Drawable
///////////////////////////////////////////////////////////////////////
//========================================================================
// StaticPhysDSG::
//========================================================================
//
// Description:
//
// Parameters: None.
//
// Return: None.
//
// Constraints: None.
//
//========================================================================
void StaticPhysDSG::Display()
{
if(IS_DRAW_LONG) return;
#ifdef PROFILER_ENABLED
char profileName[] = " StaticPhysDSG Display";
#endif
DSG_BEGIN_PROFILE(profileName)
//Currently unsupported. Contact Devin.
//rAssert(false);
//Do nothing, but allow inst stat phys to render their pGeo's
DSG_END_PROFILE(profileName)
}
//========================================================================
// StaticPhysDSG::
//========================================================================
//
// Description:
//
// Parameters: None.
//
// Return: None.
//
// Constraints: None.
//
//========================================================================
void StaticPhysDSG::DisplayBoundingBox(tColour colour)
{
#ifndef RAD_RELEASE
//Currently unsupported. Contact Devin.
//rAssert(false);
pddiPrimStream* stream = p3d::pddi->BeginPrims(NULL, PDDI_PRIM_LINESTRIP, PDDI_V_C, 5);
stream->Colour(colour);
stream->Coord(mBBox.low.x, mBBox.low.y, mBBox.low.z);
stream->Colour(colour);
stream->Coord(mBBox.high.x, mBBox.low.y, mBBox.low.z);
stream->Colour(colour);
stream->Coord(mBBox.high.x, mBBox.high.y, mBBox.low.z);
stream->Colour(colour);
stream->Coord(mBBox.low.x, mBBox.high.y, mBBox.low.z);
stream->Colour(colour);
stream->Coord(mBBox.low.x, mBBox.low.y, mBBox.low.z);
p3d::pddi->EndPrims(stream);
stream = p3d::pddi->BeginPrims(NULL, PDDI_PRIM_LINESTRIP, PDDI_V_C, 5);
stream->Colour(colour);
stream->Coord(mBBox.high.x, mBBox.high.y, mBBox.high.z);
stream->Colour(colour);
stream->Coord(mBBox.low.x, mBBox.high.y, mBBox.high.z);
stream->Colour(colour);
stream->Coord(mBBox.low.x, mBBox.low.y, mBBox.high.z);
stream->Colour(colour);
stream->Coord(mBBox.high.x, mBBox.low.y, mBBox.high.z);
stream->Colour(colour);
stream->Coord(mBBox.high.x, mBBox.high.y, mBBox.high.z);
p3d::pddi->EndPrims(stream);
stream = p3d::pddi->BeginPrims(NULL, PDDI_PRIM_LINESTRIP, PDDI_V_C, 5);
stream->Colour(colour);
stream->Coord(mBBox.high.x, mBBox.high.y, mBBox.high.z);
stream->Colour(colour);
stream->Coord(mBBox.high.x, mBBox.low.y, mBBox.high.z);
stream->Colour(colour);
stream->Coord(mBBox.high.x, mBBox.low.y, mBBox.low.z);
stream->Colour(colour);
stream->Coord(mBBox.high.x, mBBox.high.y, mBBox.low.z);
stream->Colour(colour);
stream->Coord(mBBox.high.x, mBBox.high.y, mBBox.high.z);
p3d::pddi->EndPrims(stream);
stream = p3d::pddi->BeginPrims(NULL, PDDI_PRIM_LINESTRIP, PDDI_V_C, 5);
stream->Colour(colour);
stream->Coord(mBBox.low.x, mBBox.high.y, mBBox.high.z);
stream->Colour(colour);
stream->Coord(mBBox.low.x, mBBox.low.y, mBBox.high.z);
stream->Colour(colour);
stream->Coord(mBBox.low.x, mBBox.low.y, mBBox.low.z);
stream->Colour(colour);
stream->Coord(mBBox.low.x, mBBox.high.y, mBBox.low.z);
stream->Colour(colour);
stream->Coord(mBBox.low.x, mBBox.high.y, mBBox.high.z);
p3d::pddi->EndPrims(stream);
#endif
}
//========================================================================
// StaticPhysDSG::
//========================================================================
//
// Description:
//
// Parameters: None.
//
// Return: None.
//
// Constraints: None.
//
//========================================================================
void StaticPhysDSG::DisplayBoundingSphere(tColour colour)
{
//Currently unsupported. Contact Devin.
rAssert(false);
}
//========================================================================
// StaticPhysDSG::
//========================================================================
//
// Description:
//
// Parameters: None.
//
// Return: None.
//
// Constraints: None.
//
//========================================================================
void StaticPhysDSG::GetBoundingBox(rmt::Box3D* box)
{
(*box) = mBBox;
}
//========================================================================
// StaticPhysDSG::
//========================================================================
//
// Description:
//
// Parameters: None.
//
// Return: None.
//
// Constraints: None.
//
//========================================================================
void StaticPhysDSG::GetBoundingSphere(rmt::Sphere* sphere)
{
(*sphere) = mSphere;
}
///////////////////////////////////////////////////////////////////////
// IEntityDSG
///////////////////////////////////////////////////////////////////////
//========================================================================
// StaticPhysDSG::
//========================================================================
//
// Description:
//
// Parameters: None.
//
// Return: None.
//
// Constraints: None.
//
//========================================================================
rmt::Vector* StaticPhysDSG::pPosition()
{
return &mPosn;
}
//========================================================================
// StaticPhysDSG::
//========================================================================
//
// Description:
//
// Parameters: None.
//
// Return: None.
//
// Constraints: None.
//
//========================================================================
const rmt::Vector& StaticPhysDSG::rPosition()
{
return mPosn;
}
//========================================================================
// StaticPhysDSG::
//========================================================================
//
// Description:
//
// Parameters: None.
//
// Return: None.
//
// Constraints: None.
//
//========================================================================
void StaticPhysDSG::GetPosition( rmt::Vector* ipPosn )
{
*ipPosn = mPosn;
}
//========================================================================
// StaticPhysDSG::
//========================================================================
//
// Description:
//
// Parameters: None.
//
// Return: None.
//
// Constraints: None.
//
//========================================================================
void StaticPhysDSG::RenderUpdate()
{
//do Nothing
}
//************************************************************************
//
// Protected Member Functions : StaticPhysDSG
//
//************************************************************************
void StaticPhysDSG::SetInternalState()
{
mPosn = mpSimStateObj->GetCollisionObject()->GetCollisionVolume()->mPosition;
mBBox.low = mPosn;
mBBox.high = mPosn;
mBBox.high += mpSimStateObj->GetCollisionObject()->GetCollisionVolume()->mBoxSize;
mBBox.low -= mpSimStateObj->GetCollisionObject()->GetCollisionVolume()->mBoxSize;
mSphere.centre.Sub(mBBox.high,mBBox.low);
mSphere.centre *= 0.5f;
mSphere.centre.Add(mBBox.low);
mSphere.radius = mpSimStateObj->GetCollisionObject()->GetCollisionVolume()->mSphereRadius;
}
//=============================================================================
// StaticPhysDSG::PreReactToCollision
//=============================================================================
// Description: Comment
//
// Parameters: ( sim::SimState* pCollidedObj, sim::Collision& inCollision )
//
// Return: sim
//
//=============================================================================
sim::Solving_Answer StaticPhysDSG::PreReactToCollision( sim::SimState* pCollidedObj, sim::Collision& inCollision )
{
return sim::Solving_Continue;
}
//=============================================================================
// StaticPhysDSG::PostReactToCollision
//=============================================================================
// Description: Comment
//
// Parameters: ( sim::SimState* pCollidedObj, sim::Collision& inCollision )
//
// Return: sim
//
//=============================================================================
sim::Solving_Answer StaticPhysDSG::PostReactToCollision(rmt::Vector& impulse, sim::Collision& inCollision)
{
// subclass-specific shit here
// If it is a breakable object and has an assicated particle animation with it (it should)
// play the associated particle effect, if the impulse magnitude is greater than a certain threshold
if ( mpCollisionAttributes != NULL )
{
float threshold = STAT_PHYS_MASS_IMPULSE_PARTICLE_BIAS * mpCollisionAttributes->GetMass();
if( impulse.MagnitudeSqr() > (threshold*threshold) )
{
if (mpCollisionAttributes->GetParticle() != ParticleEnum::eNull )
{
ParticleAttributes attr;
attr.mType = mpCollisionAttributes->GetParticle();
GetParticleManager()->Add( attr, inCollision.GetPositionA() );
}
}
}
return CollisionEntityDSG::PostReactToCollision(impulse, inCollision);
}
void StaticPhysDSG::SetShadow( tDrawable* ipShadow )
{
tRefCounted::Assign( mpShadow, ipShadow );
if ( ipShadow != NULL )
{
// Hang onto the shadow drawable
rAssert( mpShadowMatrix == NULL );
mpShadowMatrix = CreateShadowMatrix( rPosition() );
}
}
rmt::Matrix* StaticPhysDSG::CreateShadowMatrix( const rmt::Vector& objectPosition )
{
rmt::Matrix* pResult;
rmt::Matrix shadowMat;
if ( ComputeShadowMatrix( objectPosition, &shadowMat ) )
{
HeapMgr()->PushHeap( GMA_LEVEL_OTHER );
pResult = new rmt::Matrix();
HeapMgr()->PopHeap( GMA_LEVEL_OTHER);
*pResult = shadowMat;
}
else
{
pResult = NULL ;
}
return pResult;
}
void StaticPhysDSG::RecomputeShadowPosition( float height_radius_bias )
{
if ( mpShadowMatrix )
{
rmt::Vector position;
GetPosition( &position );
ComputeShadowMatrix( position, mpShadowMatrix );
}
}
void StaticPhysDSG::RecomputeShadowPositionNoIntersect( float height, const rmt::Vector& normal, float height_radius_bias, float scale )
{
if ( mpShadowMatrix )
{
rmt::Vector position;
GetPosition( &position );
rmt::Vector shadowPosition( position.x, height, position.z );
mpShadowMatrix->Identity();
mpShadowMatrix->FillTranslate( shadowPosition );
rmt::Vector worldRight( 1,0,0 );
rmt::Vector forward;
forward.CrossProduct( worldRight, normal );
mpShadowMatrix->FillHeading( forward, normal );
/*
if ( height_radius_bias != 1.0f )
{
// scale = (objheight - groundY) * bias
float matrixScale = 1.0f - ( position.y - shadowPosition.y ) * height_radius_bias;
matrixScale *= scale;
if ( matrixScale < 0.0f )
{
matrixScale = 0.0f;
}
mpShadowMatrix->FillScale( matrixScale );
}*/
}
}
void StaticPhysDSG::DisplaySimpleShadow()
{
p3d::pddi->SetZWrite(false);
BEGIN_PROFILE("DisplaySimpleShadow")
rAssert( mpShadow != NULL );
// Translate the shadow towards the camera slightly, instead of moving it off the
//ground in the direction of the the ground normal. Hopefully this will cause less distortion of the shadow.
if ( mpShadow != NULL && mpShadowMatrix != NULL )
{
// Create a camera that pushes the shadow a meter towards
// the camera
rmt::Vector camPos;
p3d::context->GetView()->GetCamera()->GetWorldPosition( &camPos );
camPos.Sub( mpShadowMatrix->Row(3) );
camPos.Normalize();
// Distance to raise the object
const float Z_FIGHTING_OFFSET = 1.0f;
camPos.Scale( Z_FIGHTING_OFFSET );
// Final shadow transform = position/orientation * tocamera translation
rmt::Matrix shadowTransform( *mpShadowMatrix );
shadowTransform.Row( 3 ).Add( camPos );
// Display
p3d::stack->PushMultiply( shadowTransform );
mpShadow->Display();
p3d::stack->Pop();
}
else
{
mpShadowMatrix = CreateShadowMatrix( rPosition() );
}
END_PROFILE("DisplaySimpleShadow")
p3d::pddi->SetZWrite(true);
}
//************************************************************************
//
// Private Member Functions : StaticPhysDSG
//
//************************************************************************
bool
StaticPhysDSG::ComputeShadowMatrix( const rmt::Vector& in_position, rmt::Matrix* out_pMatrix )
{
// Determine where our shadow casting object intersects the ground plane
rmt::Vector groundNormal(0,1,0);
rmt::Vector groundPlaneIntersectionPoint;
const float INTERSECT_TEST_RADIUS = 10.0f;
bool foundPlane;
rmt::Vector deepestIntersectPos, deepestIntersectNormal;
// Get rid of the fact that FindIntersection doesn't want a const value
// and I'm above casting away constness
rmt::Vector searchPosition = in_position;
searchPosition.y += 10.0f;
GetIntersectManager()->FindIntersection( searchPosition,
foundPlane,
groundNormal,
groundPlaneIntersectionPoint );
if ( foundPlane )
{
out_pMatrix->Identity();
out_pMatrix->FillTranslate( groundPlaneIntersectionPoint );
rmt::Vector worldRight( 1,0,0 );
rmt::Vector forward;
forward.CrossProduct( worldRight, groundNormal );
out_pMatrix->FillHeading( forward, groundNormal );
}
return foundPlane;
}