//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _SHAPEBASE_H_
#define _SHAPEBASE_H_
#ifndef _GAMEBASE_H_
#include "game/gameBase.h"
#endif
#ifndef _MATERIALLIST_H_
#include "dgl/materialList.h"
#endif
#ifndef _PLATFORMAUDIO_H_
#include "platform/platformAudio.h"
#endif
#ifndef _MOVEMANAGER_H_
#include "game/moveManager.h"
#endif
#ifndef _COLOR_H_
#include "core/color.h"
#endif
#ifndef _CONVEX_H_
#include "collision/convex.h"
#endif
#ifndef _SCENESTATE_H_
#include "sceneGraph/sceneState.h"
#endif
#ifndef _NETSTRINGTABLE_H_
#include "sim/netStringTable.h"
#endif
#include "lightingSystem/sgLightManager.h"
#include "lightingSystem/sgObjectShadows.h"
class TSShapeInstance;
//class Shadow;
class SceneState;
class TSShape;
class TSThread;
class GameConnection;
struct CameraScopeQuery;
class ParticleEmitter;
class ParticleEmitterData;
class ProjectileData;
class ExplosionData;
struct DebrisData;
class ShapeBase;
typedef void* Light;
//--------------------------------------------------------------------------
extern void collisionFilter(SceneObject* object,S32 key);
extern void defaultFilter(SceneObject* object,S32 key);
class ShapeImageRenderImage : public SceneRenderImage
{
public:
ShapeBase* mSBase;
U32 mIndex;
};
//--------------------------------------------------------------------------
class ShapeBaseConvex : public Convex
{
typedef Convex Parent;
friend class ShapeBase;
friend class Vehicle;
friend class RigidShape;
protected:
ShapeBase* pShapeBase;
MatrixF* nodeTransform;
public:
MatrixF* transform;
U32 hullId;
Box3F box;
public:
ShapeBaseConvex() { mType = ShapeBaseConvexType; nodeTransform = 0; }
ShapeBaseConvex(const ShapeBaseConvex& cv) {
mObject = cv.mObject;
pShapeBase = cv.pShapeBase;
hullId = cv.hullId;
nodeTransform = cv.nodeTransform;
box = cv.box;
transform = 0;
}
void findNodeTransform();
const MatrixF& getTransform() const;
Box3F getBoundingBox() const;
Box3F getBoundingBox(const MatrixF& mat, const Point3F& scale) const;
Point3F support(const VectorF& v) const;
void getFeatures(const MatrixF& mat,const VectorF& n, ConvexFeature* cf);
void getPolyList(AbstractPolyList* list);
};
//--------------------------------------------------------------------------
struct ShapeBaseImageData: public GameBaseData {
private:
typedef GameBaseData Parent;
public:
enum Constants {
MaxStates = 31, ///< We get one less than state bits because of
/// the way data is packed.
NumStateBits = 5,
};
enum LightType {
NoLight = 0,
ConstantLight,
PulsingLight,
WeaponFireLight,
NumLightTypes
};
struct StateData {
StateData();
const char* name; ///< State name
/// @name Transition states
///
/// @{
///
struct Transition {
S32 loaded[2]; ///< NotLoaded/Loaded
S32 ammo[2]; ///< Noammo/ammo
S32 target[2]; ///< target/noTarget
S32 trigger[2]; ///< Trigger up/down
S32 wet[2]; ///< wet/notWet
S32 timeout; ///< Transition after delay
} transition;
bool ignoreLoadedForReady;
/// @}
/// @name State attributes
/// @{
bool fire; ///< Can only have one fire state
bool ejectShell; ///< Should we eject a shell casing in this state?
bool allowImageChange; ///< Can we switch to another image while in this state?
///
/// For instance, if we have a rocket launcher, the player
/// shouldn't be able to switch out while firing. So,
/// you'd set allowImageChange to false in firing states, and
/// true the rest of the time.
bool scaleAnimation; ///< Scale animation to fit the state timeout
bool direction; ///< Animation direction
bool waitForTimeout; ///< Require the timeout to pass before advancing to the next
/// state.
F32 timeoutValue; ///< A timeout value; the effect of this value is determined
/// by the flags scaleAnimation and waitForTimeout
F32 energyDrain; ///< Sets the energy drain rate per second of this state.
///
/// Energy is drained at energyDrain units/sec as long as
/// we are in this state.
enum LoadedState {
IgnoreLoaded, ///< Don't change loaded state.
Loaded, ///< Set us as loaded.
NotLoaded, ///< Set us as not loaded.
NumLoadedBits = 3 ///< How many bits to allocate to representing this state. (3 states needs 2 bits)
} loaded; ///< Is the image considered loaded?
enum SpinState {
IgnoreSpin, ///< Don't change spin state.
NoSpin, ///< Mark us as having no spin (ie, stop spinning).
SpinUp, ///< Mark us as spinning up.
SpinDown, ///< Mark us as spinning down.
FullSpin, ///< Mark us as being at full spin.
NumSpinBits = 3 ///< How many bits to allocate to representing this state. (5 states needs 3 bits)
} spin; ///< Spin thread state. (Used to control spinning weapons, e.g. chainguns)
enum RecoilState {
NoRecoil,
LightRecoil,
MediumRecoil,
HeavyRecoil,
NumRecoilBits = 3
} recoil; ///< Recoil thread state.
///
/// @note At this point, the only check being done is to see if we're in a
/// state which isn't NoRecoil; ie, no differentiation is made between
/// Light/Medium/Heavy recoils. Player::onImageRecoil() is the place
/// where this is handled.
bool flashSequence; ///< Is this a muzzle flash sequence?
///
/// A muzzle flash sequence is used as a source to randomly display frames from,
/// so if this is a flashSequence, we'll display a random piece each frame.
S32 sequence; ///< Main thread sequence ID.
///
///
S32 sequenceVis; ///< Visibility thread sequence.
const char* script; ///< Function on datablock to call when we enter this state; passed the id of
/// the imageSlot.
ParticleEmitterData* emitter; ///< A particle emitter; this emitter will emit as long as the gun is in this
/// this state.
AudioProfile* sound;
F32 emitterTime; ///<
S32 emitterNode;
};
/// @name State Data
/// Individual state data used to initialize struct array
/// @{
const char* fireStateName;
const char* stateName [MaxStates];
const char* stateTransitionLoaded [MaxStates];
const char* stateTransitionNotLoaded [MaxStates];
const char* stateTransitionAmmo [MaxStates];
const char* stateTransitionNoAmmo [MaxStates];
const char* stateTransitionTarget [MaxStates];
const char* stateTransitionNoTarget [MaxStates];
const char* stateTransitionWet [MaxStates];
const char* stateTransitionNotWet [MaxStates];
const char* stateTransitionTriggerUp [MaxStates];
const char* stateTransitionTriggerDown [MaxStates];
const char* stateTransitionTimeout [MaxStates];
F32 stateTimeoutValue [MaxStates];
bool stateWaitForTimeout [MaxStates];
bool stateFire [MaxStates];
bool stateEjectShell [MaxStates];
F32 stateEnergyDrain [MaxStates];
bool stateAllowImageChange [MaxStates];
bool stateScaleAnimation [MaxStates];
bool stateDirection [MaxStates];
StateData::LoadedState stateLoaded [MaxStates];
StateData::SpinState stateSpin [MaxStates];
StateData::RecoilState stateRecoil [MaxStates];
const char* stateSequence [MaxStates];
bool stateSequenceRandomFlash [MaxStates];
bool stateIgnoreLoadedForReady [MaxStates];
AudioProfile* stateSound [MaxStates];
const char* stateScript [MaxStates];
ParticleEmitterData* stateEmitter [MaxStates];
F32 stateEmitterTime [MaxStates];
const char* stateEmitterNode [MaxStates];
/// @}
//
bool emap; ///< Environment mapping on?
bool correctMuzzleVector; ///< Adjust firing vector to eye's LOS point?
bool firstPerson; ///< Render the image when in first person?
bool useEyeOffset; ///< In first person, should we use the eyeTransform?
StringTableEntry shapeName; ///< Name of shape to render.
U32 mountPoint; ///< Mount point for the image.
MatrixF mountOffset; ///< Mount point offset, so we know where the image is.
MatrixF eyeOffset; ///< Offset from eye for first person.
ProjectileData* projectile; ///< Information about what projectile this
/// image fires.
F32 mass; ///< Mass!
bool usesEnergy; ///< Does this use energy instead of ammo?
F32 minEnergy; ///< Minimum energy for the weapon to be operable.
bool accuFire; ///< Should we automatically make image's aim converge with the crosshair?
bool cloakable; ///< Is this image cloakable when mounted?
/// @name Lighting
/// @{
S32 lightType; ///< Indicates the type of the light.
///
/// One of: ConstantLight, PulsingLight, WeaponFireLight.
ColorF lightColor;
S32 lightTime; ///< Indicates the time when the light effect started.
///
/// Used by WeaponFireLight to produce a short-duration flash.
F32 lightRadius; ///< Extent of light.
/// @}
/// @name Shape Data
/// @{
Resource shape; ///< Shape handle
U32 mCRC; ///< Checksum of shape.
///
/// Calculated by the ResourceManager, see
/// ResourceManager::load().
bool computeCRC; ///< Should the shape's CRC be checked?
MatrixF mountTransform; ///< Transformation to get to the mountNode.
/// @}
/// @name Nodes
/// @{
S32 retractNode; ///< Retraction node ID.
///
/// When the player bumps against an object and the image is retracted to
/// avoid having it interpenetrating the object, it is retracted towards
/// this node.
S32 muzzleNode; ///< Muzzle node ID.
///
///
S32 ejectNode; ///< Ejection node ID.
///
/// The eject node is the node on the image from which shells are ejected.
S32 emitterNode; ///< Emitter node ID.
///
/// The emitter node is the node from which particles are emitted.
/// @}
/// @name Animation
/// @{
S32 spinSequence; ///< ID of the spin animation sequence.
S32 ambientSequence; ///< ID of the ambient animation sequence.
bool isAnimated; ///< This image contains at least one animated states
bool hasFlash; ///< This image contains at least one muzzle flash animation state
S32 fireState; ///< The ID of the fire state.
/// @}
/// @name Shell casing data
/// @{
DebrisData * casing; ///< Information about shell casings.
S32 casingID; ///< ID of casing datablock.
///
/// When the network tells the client about the casing, it
/// it transmits the ID of the datablock. The datablocks
/// having previously been transmitted, all the client
/// needs to do is call Sim::findObject() and look up the
/// the datablock.
Point3F shellExitDir; ///< Vector along which to eject shells from the image.
F32 shellExitVariance; ///< Variance from this vector in degrees.
F32 shellVelocity; ///< Velocity with which to eject shell casings.
/// @}
/// @name State Array
///
/// State array is initialized onAdd from the individual state
/// struct array elements.
///
/// @{
StateData state[MaxStates]; ///< Array of states.
bool statesLoaded; ///< Are the states loaded yet?
/// @}
/// @name Infrastructure
///
/// Miscellaneous inherited methods.
/// @{
DECLARE_CONOBJECT(ShapeBaseImageData);
ShapeBaseImageData();
~ShapeBaseImageData();
bool onAdd();
bool preload(bool server, char errorBuffer[256]);
S32 lookupState(const char* name); ///< Get a state by name.
static void initPersistFields();
virtual void packData(BitStream* stream);
virtual void unpackData(BitStream* stream);
/// @}
};
//--------------------------------------------------------------------------
/// @nosubgrouping
struct ShapeBaseData : public GameBaseData {
private:
typedef GameBaseData Parent;
public:
/// Various constants relating to the ShapeBaseData
enum Constants {
NumMountPoints = 32,
NumMountPointBits = 5,
MaxCollisionShapes = 8,
AIRepairNode = 31
};
bool shadowEnable;
bool shadowCanMove;
bool shadowCanAnimate;
StringTableEntry shapeName;
StringTableEntry cloakTexName;
/// @name Destruction
///
/// Everyone likes to blow things up!
/// @{
DebrisData * debris;
S32 debrisID;
StringTableEntry debrisShapeName;
Resource debrisShape;
ExplosionData* explosion;
S32 explosionID;
ExplosionData* underwaterExplosion;
S32 underwaterExplosionID;
/// @}
/// @name Physical Properties
/// @{
F32 mass;
F32 drag;
F32 density;
F32 maxEnergy;
F32 maxDamage;
F32 repairRate; ///< Rate per tick.
F32 disabledLevel;
F32 destroyedLevel;
S32 shieldEffectLifetimeMS;
/// @}
/// @name 3rd Person Camera
/// @{
F32 cameraMaxDist; ///< Maximum distance from eye
F32 cameraMinDist; ///< Minumumistance from eye
/// @}
/// @name Camera FOV
///
/// These are specified in degrees.
/// @{
F32 cameraDefaultFov; ///< Default FOV.
F32 cameraMinFov; ///< Min FOV allowed.
F32 cameraMaxFov; ///< Max FOV allowed.
/// @}
/// @name Data initialized on preload
/// @{
Resource shape; ///< Shape handle
U32 mCRC;
bool computeCRC;
S32 eyeNode; ///< Shape's eye node index
S32 cameraNode; ///< Shape's camera node index
S32 shadowNode; ///< Move shadow center as this node moves
S32 mountPointNode[NumMountPoints]; ///< Node index of mountPoint
S32 debrisDetail; ///< Detail level used to generate debris
S32 damageSequence; ///< Damage level decals
S32 hulkSequence; ///< Destroyed hulk
bool canControl; // can this object be controlled?
bool canObserve; // may look at object in commander map?
bool observeThroughObject; // observe this object through its camera transform and default fov
/// @name HUD
///
/// @note This may be only semi-functional.
/// @{
enum {
NumHudRenderImages = 8,
};
StringTableEntry hudImageNameFriendly[NumHudRenderImages];
StringTableEntry hudImageNameEnemy[NumHudRenderImages];
TextureHandle hudImageFriendly[NumHudRenderImages];
TextureHandle hudImageEnemy[NumHudRenderImages];
bool hudRenderCenter[NumHudRenderImages];
bool hudRenderModulated[NumHudRenderImages];
bool hudRenderAlways[NumHudRenderImages];
bool hudRenderDistance[NumHudRenderImages];
bool hudRenderName[NumHudRenderImages];
/// @}
/// @name Collision Data
/// @{
Vector collisionDetails; ///< Detail level used to collide with.
///
/// These are detail IDs, see TSShape::findDetail()
Vector collisionBounds; ///< Detail level bounding boxes.
Vector LOSDetails; ///< Detail level used to perform line-of-sight queries against.
///
/// These are detail IDs, see TSShape::findDetail()
/// @}
/// @name Shadow Settings
///
/// These are set by derived classes, not by script file.
/// They control when shadows are rendered (and when generic shadows are substituted)
///
/// @{
F32 genericShadowLevel;
F32 noShadowLevel;
/// @}
/// @name Misc. Settings
/// @{
bool emap; ///< Enable environment mapping?
bool firstPersonOnly; ///< Do we allow only first person view of this image?
bool useEyePoint; ///< Do we use this object's eye point to view from?
bool aiAvoidThis; ///< If set, the AI's will try to walk around this object...
///
/// @note There isn't really any AI code that can take advantage of this.
bool isInvincible; ///< If set, object cannot take damage (won't show up with damage bar either)
bool renderWhenDestroyed; ///< If set, will not render this object when destroyed.
bool inheritEnergyFromMount;
/// @}
bool preload(bool server, char errorBuffer[256]);
void computeAccelerator(U32 i);
S32 findMountPoint(U32 n);
/// @name Infrastructure
/// The derived class should provide the following:
/// @{
DECLARE_CONOBJECT(ShapeBaseData);
ShapeBaseData();
~ShapeBaseData();
static void initPersistFields();
virtual void packData(BitStream* stream);
virtual void unpackData(BitStream* stream);
/// @}
};
//----------------------------------------------------------------------------
/// ShapeBase is the renderable shape from which most of the scriptable objects
/// are derived, including the player, vehicle and items classes. ShapeBase
/// provides basic shape loading, audio channels, and animation as well as damage
/// (and damage states), energy, and the ability to mount images and objects.
///
/// @nosubgrouping
class ShapeBase : public GameBase
{
typedef GameBase Parent;
friend class ShapeBaseConvex;
friend class ShapeBaseImageData;
friend void physicalZoneFind(SceneObject*, void *);
public:
enum PublicConstants {
ThreadSequenceBits = 6,
MaxSequenceIndex = (1 << ThreadSequenceBits) - 1,
EnergyLevelBits = 5,
DamageLevelBits = 6,
DamageStateBits = 2,
// The thread and image limits should not be changed without
// also changing the ShapeBaseMasks enum values declared
// further down.
MaxSoundThreads = 4, ///< Should be a power of 2
MaxScriptThreads = 4, ///< Should be a power of 2
MaxMountedImages = 4, ///< Should be a power of 2
MaxImageEmitters = 3,
NumImageBits = 3,
ShieldNormalBits = 8,
CollisionTimeoutValue = 250 ///< Timeout in ms.
};
/// This enum indexes into the sDamageStateName array
enum DamageState {
Enabled,
Disabled,
Destroyed,
NumDamageStates,
NumDamageStateBits = 2, ///< Should be log2 of the number of states.
};
private:
ShapeBaseData* mDataBlock; ///< Datablock
//GameConnection* mControllingClient; ///< Controlling client
ShapeBase* mControllingObject; ///< Controlling object
bool mTrigger[MaxTriggerKeys]; ///< What triggers are set, if any.
/// @name Scripted Sound
/// @{
struct Sound {
bool play; ///< Are we playing this sound?
SimTime timeout; ///< Time until we stop playing this sound.
AudioProfile* profile; ///< Profile on server
AUDIOHANDLE sound; ///< Handle on client
};
Sound mSoundThread[MaxSoundThreads];
/// @}
/// @name Scripted Animation Threads
/// @{
struct Thread {
/// State of the animation thread.
enum State {
Play, Stop, Pause
};
TSThread* thread; ///< Pointer to 3space data.
U32 state; ///< State of the thread
///
/// @see Thread::State
S32 sequence; ///< The animation sequence which is running in this thread.
U32 sound; ///< Handle to sound.
bool atEnd; ///< Are we at the end of this thread?
bool forward; ///< Are we playing the thread forward? (else backwards)
};
Thread mScriptThread[MaxScriptThreads];
/// @}
/// @name Invincibility
/// @{
F32 mInvincibleCount;
F32 mInvincibleTime;
F32 mInvincibleSpeed;
F32 mInvincibleDelta;
F32 mInvincibleEffect;
F32 mInvincibleFade;
bool mInvincibleOn;
/// @}
protected:
sgObjectShadows shadows;
/// @name Mounted Images
/// @{
/// An image mounted on a shapebase.
struct MountedImage {
ShapeBaseImageData* dataBlock;
ShapeBaseImageData::StateData *state;
ShapeBaseImageData* nextImage;
StringHandle skinNameHandle;
StringHandle nextSkinNameHandle;
/// @name State
///
/// Variables tracking the state machine
/// representing this specific mounted image.
/// @{
bool loaded; ///< Is the image loaded?
bool nextLoaded; ///< Is the next state going to result in the image being loaded?
F32 delayTime; ///< Time till next state.
U32 fireCount; ///< Fire skip count.
///
/// This is incremented every time the triggerDown bit is changed,
/// so that the engine won't be too confused if the player toggles the
/// trigger a bunch of times in a short period.
///
/// @note The network deals with this variable at 3-bit precision, so it
/// can only range 0-7.
///
/// @see ShapeBase::setImageState()
bool triggerDown; ///< Is the trigger down?
bool ammo; ///< Do we have ammo?
///
/// May be true based on either energy OR ammo.
bool target; ///< Have we acquired a targer?
bool wet; ///< Is the weapon wet?
/// @}
/// @name 3space
///
/// Handles to threads and shapeinstances in the 3space system.
/// @{
///
TSShapeInstance* shapeInstance;
TSThread *ambientThread;
TSThread *visThread;
TSThread *animThread;
TSThread *flashThread;
TSThread *spinThread;
/// @}
/// @name Effects
///
/// Variables relating to lights, sounds, and particles.
/// @{
SimTime lightStart; ///< Starting time for light flashes.
LightInfo mLight; ///< Passed to the LightManager; filled out with the above information.
///
/// registerLights() is responsible for performing
/// the calculations that prepare mLight.
bool animLoopingSound; ///< Are we playing a looping sound?
AUDIOHANDLE animSound; ///< Handle to the current image sound.
/// Represent the state of a specific particle emitter on the image.
struct ImageEmitter {
S32 node;
F32 time;
SimObjectPtr emitter;
};
ImageEmitter emitter[MaxImageEmitters];
/// @}
void registerImageLights(LightManager * lightManager, bool lightingScene, const Point3F &objectPosition, U32 startTime);
//
MountedImage();
~MountedImage();
};
MountedImage mMountedImageList[MaxMountedImages];
/// @}
/// @name Render settings
/// @{
TSShapeInstance* mShapeInstance;
Convex * mConvexList;
StringHandle mSkinNameHandle;
StringHandle mShapeNameHandle; ///< Name sent to client
/// @}
/// @name Physical Properties
/// @{
F32 mEnergy; ///< Current enery level.
F32 mRechargeRate; ///< Energy recharge rate (in units/tick).
bool mChargeEnergy; ///< Are we currently charging?
/// @note Currently unused.
F32 mMass; ///< Mass.
F32 mOneOverMass; ///< Inverse of mass.
/// @note This is used to optimize certain physics calculations.
/// @}
/// @name Physical Properties
///
/// Properties for the current object, which are calculated
/// based on the container we are in.
///
/// @see ShapeBase::updateContainer()
/// @see ShapeBase::mContainer
/// @{
F32 mDrag; ///< Drag.
F32 mBuoyancy; ///< Buoyancy factor.
U32 mLiquidType; ///< Type of liquid (if any) we are in.
F32 mLiquidHeight; ///< Height of liquid around us (from 0..1).
F32 mWaterCoverage; ///< Percent of this object covered by water
Point3F mAppliedForce;
F32 mGravityMod;
/// @}
F32 mDamageFlash;
F32 mWhiteOut;
bool mFlipFadeVal;
U32 mLightTime;
/// Last shield direction (cur. unused)
Point3F mShieldNormal;
/// Mounted objects
struct MountInfo {
ShapeBase* list; ///< Objects mounted on this object
ShapeBase* object; ///< Object this object is mounted on.
ShapeBase* link; ///< Link to next object mounted to this object's mount
U32 node; ///< Node point we are mounted to.
} mMount;
public:
/// @name Collision Notification
/// This is used to keep us from spamming collision notifications. When
/// a collision occurs, we add to this list; then we don't notify anyone
/// of the collision until the CollisionTimeout expires (which by default
/// occurs in 1/10 of a second).
///
/// @see notifyCollision(), queueCollision()
/// @{
struct CollisionTimeout {
CollisionTimeout* next;
ShapeBase* object;
U32 objectNumber;
SimTime expireTime;
VectorF vector;
};
CollisionTimeout* mTimeoutList;
static CollisionTimeout* sFreeTimeoutList;
/// Go through all the items in the collision queue and call onCollision on them all
/// @see onCollision
void notifyCollision();
/// This gets called when an object collides with this object
/// @param object Object colliding with this object
/// @param vec Vector along which collision occured
virtual void onCollision(ShapeBase* object, VectorF vec);
/// Add a collision to the queue of collisions waiting to be handled @see onCollision
/// @param object Object collision occurs with
/// @param vec Vector along which collision occurs
void queueCollision(ShapeBase* object, const VectorF& vec);
/// @}
protected:
/// @name Damage
/// @{
F32 mDamage;
F32 mRepairRate;
F32 mRepairReserve;
bool mRepairDamage;
DamageState mDamageState;
TSThread *mDamageThread;
TSThread *mHulkThread;
VectorF damageDir;
bool blowApart;
/// @}
/// @name Cloaking
/// @{
bool mCloaked;
F32 mCloakLevel;
TextureHandle mCloakTexture;
bool mHidden; ///< in/out of world
/// @}
/// @name Fading
/// @{
bool mFadeOut;
bool mFading;
F32 mFadeVal;
F32 mFadeElapsedTime;
F32 mFadeTime;
F32 mFadeDelay;
/// @}
/// @name Control info
/// @{
F32 mCameraFov; ///< Camera FOV(in degrees)
bool mIsControlled; ///< Client side controlled flag
/// @}
static U32 sLastRenderFrame;
U32 mLastRenderFrame;
F32 mLastRenderDistance;
U32 mSkinHash;
/// This recalculates the total mass of the object, and all mounted objects
void updateMass();
/// @name Image Manipulation
/// @{
/// Utility function to call script functions which have to do with ShapeBase
/// objects.
/// @param imageSlot Image Slot id
/// @param function Function
void scriptCallback(U32 imageSlot,const char* function);
/// Assign a ShapeBaseImage to an image slot
/// @param imageSlot Image Slot ID
/// @param imageData ShapeBaseImageData to assign
/// @param skinNameHandle Skin texture name
/// @param loaded Is the image loaded?
/// @param ammo Does the image have ammo?
/// @param triggerDown Is the trigger on this image down?
/// @param target Does the image have a target?
virtual void setImage(U32 imageSlot, ShapeBaseImageData* imageData, StringHandle &skinNameHandle,
bool loaded = true, bool ammo = false, bool triggerDown = false,
bool target = false);
/// Clear out an image slot
/// @param imageSlot Image slot id
void resetImageSlot(U32 imageSlot);
/// Get the firing action state of the image
/// @param imageSlot Image slot id
U32 getImageFireState(U32 imageSlot);
/// Sets the state of the image
/// @param imageSlot Image slot id
/// @param state State id
/// @param force Force image to state or let it finish then change
void setImageState(U32 imageSlot, U32 state, bool force = false);
/// Advance animation on a image
/// @param imageSlot Image slot id
/// @param dt Change in time since last animation update
void updateImageAnimation(U32 imageSlot, F32 dt);
/// Advance state of image
/// @param imageSlot Image slot id
/// @param dt Change in time since last state update
void updateImageState(U32 imageSlot,F32 dt);
/// Start up the particle emitter for the this shapebase
/// @param image Mounted image
/// @param state State of shape base image
void startImageEmitter(MountedImage &image,ShapeBaseImageData::StateData &state);
/// Get light information for a mounted image
/// @param imageSlot Image slot id
Light* getImageLight(U32 imageSlot);
/// @}
/// Prune out non looping sounds from the sound manager which have expired
void updateServerAudio();
/// Updates the audio state of the supplied sound
/// @param st Sound
void updateAudioState(Sound& st);
/// Recalculates the spacial sound based on the current position of the object
/// emitting the sound.
void updateAudioPos();
/// Update bouyency and drag properties
void updateContainer();
/// @name Events
/// @{
virtual void onDeleteNotify(SimObject*);
virtual void onImageRecoil(U32 imageSlot,ShapeBaseImageData::StateData::RecoilState);
virtual void ejectShellCasing( U32 imageSlot );
virtual void updateDamageLevel();
virtual void updateDamageState();
virtual void blowUp();
virtual void onMount(ShapeBase* obj,S32 node);
virtual void onUnmount(ShapeBase* obj,S32 node);
virtual void onImpact(SceneObject* obj, VectorF vec);
virtual void onImpact(VectorF vec);
/// @}
public:
ShapeBase();
~ShapeBase();
TSShapeInstance* getShapeInstance() { return mShapeInstance; }
/// @name Network state masks
/// @{
///
enum ShapeBaseMasks {
NameMask = Parent::NextFreeMask,
DamageMask = Parent::NextFreeMask << 1,
NoWarpMask = Parent::NextFreeMask << 2,
MountedMask = Parent::NextFreeMask << 3,
CloakMask = Parent::NextFreeMask << 4,
ShieldMask = Parent::NextFreeMask << 5,
InvincibleMask = Parent::NextFreeMask << 6,
SkinMask = Parent::NextFreeMask << 7,
SoundMaskN = Parent::NextFreeMask << 8, ///< Extends + MaxSoundThreads bits
ThreadMaskN = SoundMaskN << MaxSoundThreads, ///< Extends + MaxScriptThreads bits
ImageMaskN = ThreadMaskN << MaxScriptThreads, ///< Extends + MaxMountedImage bits
NextFreeMask = ImageMaskN << MaxMountedImages
};
enum BaseMaskConstants {
SoundMask = (SoundMaskN << MaxSoundThreads) - SoundMaskN,
ThreadMask = (ThreadMaskN << MaxScriptThreads) - ThreadMaskN,
ImageMask = (ImageMaskN << MaxMountedImages) - ImageMaskN
};
/// @}
static bool gRenderEnvMaps; ///< Global flag which turns on or off all environment maps
static F32 sWhiteoutDec;
static F32 sDamageFlashDec;
/// @name Initialization
/// @{
bool onAdd();
void onRemove();
void onSceneRemove();
static void consoleInit();
bool onNewDataBlock(GameBaseData* dptr);
/// @}
/// @name Name & Skin tags
/// @{
void setShapeName(const char*);
const char* getShapeName();
void setSkinName(const char*);
const char* getSkinName();
/// @}
/// @name Basic attributes
/// @{
/// Sets the ammount of damage on this object.
void setDamageLevel(F32 damage);
/// Changes the object's damage state.
/// @param state New state of the object
void setDamageState(DamageState state);
/// Changes the object's damage state, based on a named state.
/// @see setDamageState
/// @param state New state of the object as a string.
bool setDamageState(const char* state);
/// Returns the name of the current damage state as a string.
const char* getDamageStateName();
/// Returns the current damage state.
DamageState getDamageState() { return mDamageState; }
/// Returns true if the object is destroyed.
bool isDestroyed() { return mDamageState == Destroyed; }
/// Sets the rate at which the object regenerates damage.
///
/// @param rate Repair rate in units/second.
void setRepairRate(F32 rate) { mRepairRate = rate; }
/// Returns damage amount.
F32 getDamageLevel() { return mDamage; }
/// Returns the damage percentage.
///
/// @return Damage factor, between 0.0 - 1.0
F32 getDamageValue();
/// Returns the rate at which the object regenerates damage
F32 getRepairRate() { return mRepairRate; }
/// Adds damage to an object
/// @param amount Amount of of damage to add
void applyDamage(F32 amount);
/// Removes damage to an object
/// @param amount Amount to repair object by
void applyRepair(F32 amount);
/// Sets the direction from which the damage is coming
/// @param vec Vector indicating the direction of the damage
void setDamageDir(const VectorF& vec) { damageDir = vec; }
/// Sets the level of energy for this object
/// @param energy Level of energy to assign to this object
virtual void setEnergyLevel(F32 energy);
/// Sets the rate at which the energy replentishes itself
/// @param rate Rate at which energy restores
void setRechargeRate(F32 rate) { mRechargeRate = rate; }
/// Returns the amount of energy in the object
F32 getEnergyLevel();
/// Returns the percentage of energy, 0.0 - 1.0
F32 getEnergyValue();
/// Returns the recharge rate
F32 getRechargeRate() { return mRechargeRate; }
/// @}
/// @name Script sounds
/// @{
/// Plays an audio sound from a mounted object
/// @param slot Mount slot ID
/// @param profile Audio profile to play
void playAudio(U32 slot,AudioProfile* profile);
/// Stops audio from a mounted object
/// @param slot Mount slot ID
void stopAudio(U32 slot);
/// @}
/// @name Script animation
/// @{
/// Sets the animation thread for a mounted object
/// @param slot Mount slot ID
/// @param seq Sequance id
/// @param reset Reset the sequence
bool setThreadSequence(U32 slot, S32 seq, bool reset = true);
/// Update the animation thread
/// @param st Thread to update
void updateThread(Thread& st);
/// Stop the current thread from playing on a mounted object
/// @param slot Mount slot ID
bool stopThread(U32 slot);
/// Pause the running animation thread
/// @param slot Mount slot ID
bool pauseThread(U32 slot);
/// Start playing the running animation thread again
/// @param slot Mount slot ID
bool playThread(U32 slot);
/// Toggle the thread as reversed or normal (For example, sidestep-right reversed is sidestep-left)
/// @param slot Mount slot ID
/// @param forward True if the animation is to be played normally
bool setThreadDir(U32 slot,bool forward);
/// Start the sound associated with an animation thread
/// @param thread Thread
void startSequenceSound(Thread& thread);
/// Stop the sound associated with an animation thread
/// @param thread Thread
void stopThreadSound(Thread& thread);
/// Advance all animation threads attached to this shapebase
/// @param dt Change in time from last call to this function
void advanceThreads(F32 dt);
/// @}
/// @name Cloaking
/// @{
/// Force uncloaking of object
/// @param reason Reason this is being forced to uncloak, this is passed directly to script control
void forceUncloak(const char *reason);
/// Set cloaked state of object
/// @param cloaked True if object is cloaked
void setCloakedState(bool cloaked);
/// Returns true if object is cloaked
bool getCloakedState();
/// Returns level of cloaking, as it's not an instant "now you see it, now you don't"
F32 getCloakLevel();
/// @}
/// @name Mounted objects
/// @{
/// Mount an object to a mount point
/// @param obj Object to mount
/// @param node Mount node ID
virtual void mountObject(ShapeBase* obj,U32 node);
/// Remove an object mounting
/// @param obj Object to unmount
void unmountObject(ShapeBase *obj);
/// Unmount this object from it's mount
void unmount();
/// Return the object that this object is mounted to
ShapeBase* getObjectMount() { return mMount.object; }
/// Return object link of next object mounted to this object's mount
ShapeBase* getMountLink() { return mMount.link; }
/// Returns the list of things mounted along with this object
ShapeBase* getMountList() { return mMount.list; }
/// Returns the mount id that this is mounted to
U32 getMountNode() { return mMount.node; }
/// Returns true if this object is mounted to anything at all
bool isMounted() { return mMount.object != 0; }
/// Returns the number of object mounted along with this
S32 getMountedObjectCount();
/// Returns the object mounted at a position in the mount list
/// @param idx Position on the mount list
ShapeBase* getMountedObject(S32 idx);
/// Returns the node the object at idx is mounted to
/// @param idx Index
S32 getMountedObjectNode(S32 idx);
/// Returns the object a object on the mount list is mounted to
/// @param node
ShapeBase* getMountNodeObject(S32 node);
/// Returns where the AI should be to repair this object
///
/// @note Legacy code from Tribes 2, but still works
Point3F getAIRepairPoint();
/// @}
/// @name Mounted Images
/// @{
/// Mount an image (ShapeBaseImage) onto an image slot
/// @param image ShapeBaseImage to mount
/// @param imageSlot Image mount point
/// @param loaded True if weapon is loaded (it assumes it's a weapon)
/// @param skinNameHandle Skin name for object
virtual bool mountImage(ShapeBaseImageData* image,U32 imageSlot,bool loaded, StringHandle &skinNameHandle);
/// Unmount an image from a slot
/// @param imageSlot Mount point
virtual bool unmountImage(U32 imageSlot);
/// Gets the information on the image mounted in a slot
/// @param imageSlot Mount point
ShapeBaseImageData* getMountedImage(U32 imageSlot);
/// Gets the mounted image on on a slot
/// @param imageSlot Mount Point
MountedImage* getImageStruct(U32 imageSlot);
TSShapeInstance* getImageShapeInstance(U32 imageSlot)
{
const MountedImage &image = mMountedImageList[imageSlot];
if(image.dataBlock && image.shapeInstance)
return image.shapeInstance;
return NULL;
}
/// Gets the next image which will be put in an image slot
/// @see setImageState
/// @param imageSlot mount Point
ShapeBaseImageData* getPendingImage(U32 imageSlot);
/// Returns true if the mounted image is firing
/// @param imageSlot Mountpoint
bool isImageFiring(U32 imageSlot);
/// This will return true if, when triggered, the object will fire.
/// @param imageSlot mount point
/// @param ns Used internally for recursion, do not mess with
/// @param depth Used internally for recursion, do not mess with
bool isImageReady(U32 imageSlot,U32 ns = (U32)-1,U32 depth = 0);
/// Returns true if the specified image is mounted
/// @param image ShapeBase image
bool isImageMounted(ShapeBaseImageData* image);
/// Returns the slot which the image specified is mounted on
/// @param image Image to test for
S32 getMountSlot(ShapeBaseImageData* image);
/// Returns the skin for the image in a slot
/// @param imageSlot Image slot to get the skin from
StringHandle getImageSkinTag(U32 imageSlot);
/// Returns the image state as a string
/// @param imageSlot Image slot to check state
const char* getImageState(U32 imageSlot);
/// Sets the trigger state of the image (Ie trigger pulled down on gun)
/// @param imageSlot Image slot
/// @param trigger True if trigger is down
void setImageTriggerState(U32 imageSlot,bool trigger);
/// Returns the trigger state of the image
/// @param imageSlot Image slot
bool getImageTriggerState(U32 imageSlot);
/// Sets the flag if the image uses ammo or energy
/// @param imageSlot Image slot
/// @param ammo True if the weapon uses ammo, not energy
void setImageAmmoState(U32 imageSlot,bool ammo);
/// Returns true if the image uses ammo, not energy
/// @param imageSlot Image slot
bool getImageAmmoState(U32 imageSlot);
/// Sets the image as wet or not, IE if you wanted a gun not to function underwater
/// @param imageSlot Image slot
/// @param wet True if image is wet
void setImageWetState(U32 imageSlot,bool wet);
/// Returns true if image is wet
/// @param imageSlot image slot
bool getImageWetState(U32 imageSlot);
/// Sets the flag of if the image is loaded with ammo
/// @param imageSlot Image slot
/// @param loaded True if object is loaded with ammo
void setImageLoadedState(U32 imageSlot,bool loaded);
/// Returns true if object is loaded with ammo
/// @param imageSlot Image slot
bool getImageLoadedState(U32 imageSlot);
/// Modify muzzle, if needed, to aim at whatever is straight in front of eye.
/// Returns true if result is actually modified.
/// @param muzMat Muzzle transform (in/out)
/// @param result Corrected muzzle vector (out)
bool getCorrectedAim(const MatrixF& muzMat, VectorF* result);
/// Gets the muzzle vector of a specified slot
/// @param imageSlot Image slot to check transform for
/// @param vec Muzzle vector (out)
virtual void getMuzzleVector(U32 imageSlot,VectorF* vec);
/// Gets the point of the muzzle of the image
/// @param imageSlot Image slot
/// @param pos Muzzle point (out)
void getMuzzlePoint(U32 imageSlot,Point3F* pos);
/// @}
/// @name Transforms
/// @{
/// Gets the minimum viewing distance, maximum viewing distance, camera offsetand rotation
/// for this object, if the world were to be viewed through its eyes
/// @param min Minimum viewing distance
/// @param max Maximum viewing distance
/// @param offset Offset of the camera from the origin in local space
/// @param rot Rotation matrix
virtual void getCameraParameters(F32 *min,F32* max,Point3F* offset,MatrixF* rot);
/// Gets the camera transform
/// @todo Find out what pos does
/// @param pos TODO: Find out what this does
/// @param mat Camera transform (out)
virtual void getCameraTransform(F32* pos,MatrixF* mat);
/// Gets the index of a node inside a mounted image given the name
/// @param imageSlot Image slot
/// @param nodeName Node name
S32 getNodeIndex(U32 imageSlot,StringTableEntry nodeName);
/// @}
/// @name Object Transforms
/// @{
/// Returns the eye transform of this shape, IE the eyes of a player
/// @param mat Eye transform (out)
virtual void getEyeTransform(MatrixF* mat);
/// The retraction transform is the muzzle transform in world space.
///
/// If the gun is pushed back, for instance, if the player ran against something,
/// the muzzle of the gun gets pushed back towards the player, towards this location.
/// @param imageSlot Image slot
/// @param mat Transform (out)
virtual void getRetractionTransform(U32 imageSlot,MatrixF* mat);
/// Mount point to world space transform
/// @param mountPoint Mount point
/// @param mat mount point transform (out)
virtual void getMountTransform(U32 mountPoint,MatrixF* mat);
/// Muzzle transform of mounted object in world space
/// @param imageSlot Image slot
/// @param mat Muzzle transform (out)
virtual void getMuzzleTransform(U32 imageSlot,MatrixF* mat);
/// Gets the transform of a mounted image in world space
/// @param imageSlot Image slot
/// @param mat Transform (out)
virtual void getImageTransform(U32 imageSlot,MatrixF* mat);
/// Gets the transform of a node on a mounted image in world space
/// @param imageSlot Image Slot
/// @param node node on image
/// @param mat Transform (out)
virtual void getImageTransform(U32 imageSlot,S32 node, MatrixF* mat);
/// Gets the transform of a node on a mounted image in world space
/// @param imageSlot Image Slot
/// @param nodeName Name of node on image
/// @param mat Transform (out)
virtual void getImageTransform(U32 imageSlot, StringTableEntry nodeName, MatrixF* mat);
///@}
/// @name Render transforms
/// Render transforms are different from object transforms in that the render transform of an object
/// is where, in world space, the object is actually rendered. The object transform is the
/// absolute position of the object, as in where it should be.
///
/// The render transforms typically vary from object transforms due to client side prediction.
///
/// Other than that, these functions are identical to their object-transform counterparts
///
/// @note These are meaningless on the server.
/// @{
virtual void getRenderRetractionTransform(U32 index,MatrixF* mat);
virtual void getRenderMountTransform(U32 index,MatrixF* mat);
virtual void getRenderMuzzleTransform(U32 index,MatrixF* mat);
virtual void getRenderImageTransform(U32 imageSlot,MatrixF* mat);
virtual void getRenderImageTransform(U32 index,S32 node, MatrixF* mat);
virtual void getRenderImageTransform(U32 index, StringTableEntry nodeName, MatrixF* mat);
virtual void getRenderMuzzleVector(U32 imageSlot,VectorF* vec);
virtual void getRenderMuzzlePoint(U32 imageSlot,Point3F* pos);
virtual void getRenderEyeTransform(MatrixF* mat);
/// @}
/// @name Screen Flashing
/// @{
/// Returns the level of screenflash that should be used
virtual F32 getDamageFlash() const;
/// Sets the flash level
/// @param amt Level of flash
virtual void setDamageFlash(const F32 amt);
/// White out is the flash-grenade blindness effect
/// This returns the level of flash to create
virtual F32 getWhiteOut() const;
/// Set the level of flash blindness
virtual void setWhiteOut(const F32);
/// @}
/// @name Invincibility effect
/// This is the screen effect when invincible in the HUD
/// @see GameRenderFilters()
/// @{
/// Returns the level of invincibility effect
virtual F32 getInvincibleEffect() const;
/// Initializes invincibility effect and interpolation parameters
///
/// @param time Time it takes to become invincible
/// @param speed Speed at which invincibility effects progress
virtual void setupInvincibleEffect(F32 time, F32 speed);
/// Advance invincibility effect animation
/// @param dt Time since last call of this function
virtual void updateInvincibleEffect(F32 dt);
/// @}
/// @name Movement & velocity
/// @{
/// Sets the velocity of this object
/// @param vel Velocity vector
virtual void setVelocity(const VectorF& vel);
/// Applies an impulse force to this object
/// @param pos Position where impulse came from in world space
/// @param vec Velocity vector (Impulse force F = m * v)
virtual void applyImpulse(const Point3F& pos,const VectorF& vec);
/// @}
/// @name Cameras and Control
/// @{
/// Assigns this object a controling client
/// @param client New controling client
//virtual void setControllingClient(GameConnection* client);
/// Returns the client controling this object
//GameConnection* getControllingClient() { return mControllingClient; }
/// Returns the object controling this object
ShapeBase* getControllingObject() { return mControllingObject; }
/// Sets the controling object
/// @param obj New controling object
virtual void setControllingObject(ShapeBase* obj);
/// Returns the object this is controling
virtual ShapeBase* getControlObject();
/// sets the object this is controling
/// @param obj New controlled object
virtual void setControlObject(ShapeBase *obj);
/// Returns true if this object is controled by something
bool isControlled() { return(mIsControlled); }
/// Returns true if this object is being used as a camera in first person
bool isFirstPerson();
/// Returns true if the camera uses this objects eye point (defined by modeler)
bool useObjsEyePoint() const;
/// Returns true if this object can only be used as a first person camera
bool onlyFirstPerson() const;
/// Returns the Field of Vision for this object if used as a camera
virtual F32 getCameraFov();
/// Returns the default FOV if this object is used as a camera
virtual F32 getDefaultCameraFov();
/// Sets the FOV for this object if used as a camera
virtual void setCameraFov(F32 fov);
/// Returns true if the FOV supplied is within allowable parameters
/// @param fov FOV to test
virtual bool isValidCameraFov(F32 fov);
/// @}
void processTick(const Move *move);
void advanceTime(F32 dt);
/// @name Rendering
/// @{
/// Returns the renderable shape of this object
TSShape const* getShape();
bool prepRenderImage(SceneState* state, const U32 stateKey, const U32 startZone, const bool modifyBaseZoneState);
void renderObject(SceneState *state, SceneRenderImage *image);
/// Renders a mounted object
/// @param state State of scene
/// @param image ShapeImage to render
virtual void renderMountedImage(SceneState* state, ShapeImageRenderImage* image);
virtual void renderImage(SceneState* state, SceneRenderImage *image);
/// Renders the shadow for this object
/// @param dist Distance away from object shadow is rendering on
/// @param fogAmount Amount of fog present
virtual void renderShadow(F32 dist, F32 fogAmount);
/// Draws a wire cube at any point in space with specified parameters
/// @param size Length, width, depth
/// @param pos xyz position in world space
static void wireCube(const Point3F& size, const Point3F& pos);
/// Preprender logic
virtual void calcClassRenderData();
/// @}
/// Control object scoping
void onCameraScopeQuery(NetConnection *cr, CameraScopeQuery *camInfo);
/// @name Collision
/// @{
/// Casts a ray from start to end, stores gathered information in 'info' returns true if successful
/// @param start Start point for ray
/// @param end End point for ray
/// @param info Information from raycast (out)
bool castRay(const Point3F &start, const Point3F &end, RayInfo* info);
/// Builds a polylist of the polygons in this object returns true if successful
/// @param polyList Returned polylist (out)
/// @param box Not used
/// @param sphere Not used
bool buildPolyList(AbstractPolyList* polyList, const Box3F &box, const SphereF& sphere);
/// Builds a convex hull for this object @see Convex
/// @param box Bounding box
/// @param convex New convex hull (out)
void buildConvex(const Box3F& box, Convex* convex);
/// @}
/// @name Rendering
/// @{
/// Increments the last rendered frame number
static void incRenderFrame() { sLastRenderFrame++; }
/// Returns true if the last frame calculated rendered
bool didRenderLastRender() { return mLastRenderFrame == sLastRenderFrame; }
/// Sets the state of this object as hidden or not. If an object is hidden
/// it is removed entirely from collisions, it is not ghosted and is
/// essentially "non existant" as far as simulation is concerned.
/// @param hidden True if object is to be hidden
virtual void setHidden(bool hidden);
/// Returns true if this object is hidden
/// @see setHidden
bool isHidden() { return mHidden; }
/// Returns true if this object can be damaged
bool isInvincible();
/// Start fade of object in/out
/// @param fadeTime Time fade should take
/// @param fadeDelay Delay before starting fade
/// @param fadeOut True if object is fading out, false if fading in.
void startFade( F32 fadeTime, F32 fadeDelay = 0.0, bool fadeOut = true );
/// Traverses mounted objects and registers light sources with the light manager
/// @param lightManager Light manager to register with
/// @param lightingScene Set to true if the scene is being lit, in which case these lights will not be used
void registerLights(LightManager * lightManager, bool lightingScene);
/// @}
/// Returns true if the point specified is in the water
/// @param point Point to test in world space
bool pointInWater( Point3F &point );
/// Returns the percentage of this object covered by water
F32 getWaterCoverage() { return mWaterCoverage; }
/// Returns the height of the liquid on this object
F32 getLiquidHeight() { return mLiquidHeight; }
/// @name Network
/// @{
F32 getUpdatePriority(CameraScopeQuery *focusObject, U32 updateMask, S32 updateSkips);
U32 packUpdate(NetConnection *conn, U32 mask, BitStream *stream);
void unpackUpdate(NetConnection *conn, BitStream *stream);
void writePacketData(GameConnection *conn, BitStream *stream);
void readPacketData(GameConnection *conn, BitStream *stream);
virtual U32 getPacketDataChecksum(GameConnection *conn);
/// @}
DECLARE_CONOBJECT(ShapeBase);
};
//------------------------------------------------------------------------------
// inlines
//------------------------------------------------------------------------------
inline bool ShapeBase::getCloakedState()
{
return(mCloaked);
}
inline F32 ShapeBase::getCloakLevel()
{
return(mCloakLevel);
}
inline const char* ShapeBase::getShapeName()
{
return mShapeNameHandle.getString();
}
inline const char* ShapeBase::getSkinName()
{
return mSkinNameHandle.getString();
}
/// @name Shadow Detail Constants
///
/// The generic shadow level is the shadow detail at which
/// a generic shadow is drawn (a disk) rather than a generated
/// shadow. The no shadow level is the shadow level at which
/// no shadow is drawn. (Shadow level goes from 0 to 1,
/// higher numbers result in more detailed shadows).
///
/// @{
#define Player_GenericShadowLevel 0.4f
#define Player_NoShadowLevel 0.01f
#define Vehicle_GenericShadowLevel 0.7f
#define Vehicle_NoShadowLevel 0.2f
#define Item_GenericShadowLevel 0.4f
#define Item_NoShadowLevel 0.01f
#define StaticShape_GenericShadowLevel 0.7f
#define StaticShape_NoShadowLevel 0.2f
#define RigidShape_GenericShadowLevel 0.7f
#define RigidShape_NoShadowLevel 0.2f
/// @}
#endif // _H_SHAPEBASE_