Torque3D/Engine/source/T3D/shapeBase.h
AzaezelX f07c8745b2 inspector cleanups
clustering work for datablocks for both consistent scanning for object parameters, as well as an eye towards orgainizing things to make reviewing what variations of components we'll be needing down the line clearer
2023-01-24 17:12:23 -06:00

1965 lines
74 KiB
C++

//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
// Copyright (C) 2015 Faust Logic, Inc.
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
#ifndef _SHAPEBASE_H_
#define _SHAPEBASE_H_
#ifndef __RESOURCE_H__
#include "core/resource.h"
#endif
#ifndef _GAMEBASE_H_
#include "T3D/gameBase/gameBase.h"
#endif
#ifndef _MOVEMANAGER_H_
#include "T3D/gameBase/moveManager.h"
#endif
#ifndef _COLOR_H_
#include "core/color.h"
#endif
#ifndef _CONVEX_H_
#include "collision/convex.h"
#endif
#ifndef _SCENERENDERSTATE_H_
#include "scene/sceneRenderState.h"
#endif
#ifndef _NETSTRINGTABLE_H_
#include "sim/netStringTable.h"
#endif
#ifndef _RENDERPASSMANAGER_H_
#include "renderInstance/renderPassManager.h"
#endif
#ifndef _TSSHAPE_H_
#include "ts/tsShape.h"
#endif
#ifndef _BITVECTOR_H_
#include "core/bitVector.h"
#endif
#ifndef _LIGHTINFO_H_
#include "lighting/lightInfo.h"
#endif
#ifndef _REFLECTOR_H_
#include "scene/reflector.h"
#endif
#ifndef _DYNAMIC_CONSOLETYPES_H_
#include "console/dynamicTypes.h"
#endif
#ifndef SHAPEASSET_H
#include "T3D/assets/ShapeAsset.h"
#endif
// Need full definition visible for SimObjectPtr<ParticleEmitter>
#include "T3D/fx/particleEmitter.h"
#include "T3D/assets/SoundAsset.h"
class GFXCubemap;
class TSShapeInstance;
class SceneRenderState;
class TSThread;
class GameConnection;
struct CameraScopeQuery;
class ProjectileData;
class ExplosionData;
struct DebrisData;
class ShapeBase;
class SFXSource;
class SFXTrack;
class SFXProfile;
typedef void* Light;
const F32 gGravity = -20;
//--------------------------------------------------------------------------
extern void collisionFilter(SceneObject* object,S32 key);
extern void defaultFilter(SceneObject* object,S32 key);
//--------------------------------------------------------------------------
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() :pShapeBase(NULL), transform(NULL), hullId(0), nodeTransform(0) { mType = ShapeBaseConvexType; }
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.
MaxShapes = 2, ///< The number of allowed shapes per image. Only
/// the first shape is required.
MaxGenericTriggers = 4, ///< The number of generic triggers for the image.
StandardImageShape = 0, ///< Shape index used for the standard image shape
FirstPersonImageShape = 1, ///< Shape index used for the optional first person image shape
NumStateBits = 5,
};
enum LightType {
NoLight = 0,
ConstantLight,
SpotLight,
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 altTrigger[2]; ///< Second trigger up/down
S32 wet[2]; ///< wet/notWet
S32 motion[2]; ///< NoMotion/Motion
S32 timeout; ///< Transition after delay
S32 genericTrigger[ShapeBaseImageData::MaxGenericTriggers][2]; ///< Generic trigger Out/In
} transition;
bool ignoreLoadedForReady;
/// @}
/// @name State attributes
/// @{
bool fire; ///< Can only have one fire state
bool altFire; ///< Can only have one alternate fire state
bool reload; ///< Can only have one reload 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 <i>while</i> 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 scaleAnimationFP; ///< Scale animation to fit the state timeout while in first person
bool direction; ///< Animation direction
bool sequenceTransitionIn; ///< Do we transition to the state's sequence when we enter the state?
bool sequenceTransitionOut; ///< Do we transition to the new state's sequence when we leave the state?
bool sequenceNeverTransition; ///< Never allow a transition to this sequence. Often used for a fire sequence.
F32 sequenceTransitionTime; ///< The time to transition in or out of a sequence.
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[MaxShapes];///< 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[MaxShapes]; ///< Main thread sequence ID.
///
///
S32 sequenceVis[MaxShapes]; ///< Visibility thread sequence.
StringTableEntry shapeSequence; ///< Sequence that is played on mounting shape
bool shapeSequenceScale; ///< Should the mounting shape's sequence playback be scaled
/// to the length of the state.
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.
//SFXTrack* sound;
F32 emitterTime; ///<
S32 emitterNode[MaxShapes]; ///< Node ID on the shape to emit from
SoundAsset* sound;
SFXTrack* soundTrack; ///<Holdover for special, non-asset cases like SFXPlaylists
};
/// @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* stateTransitionMotion [MaxStates];
const char* stateTransitionNoMotion [MaxStates];
const char* stateTransitionTriggerUp [MaxStates];
const char* stateTransitionTriggerDown [MaxStates];
const char* stateTransitionAltTriggerUp[MaxStates];
const char* stateTransitionAltTriggerDown[MaxStates];
const char* stateTransitionGeneric0In [MaxStates];
const char* stateTransitionGeneric0Out [MaxStates];
const char* stateTransitionGeneric1In [MaxStates];
const char* stateTransitionGeneric1Out [MaxStates];
const char* stateTransitionGeneric2In [MaxStates];
const char* stateTransitionGeneric2Out [MaxStates];
const char* stateTransitionGeneric3In [MaxStates];
const char* stateTransitionGeneric3Out [MaxStates];
const char* stateTransitionTimeout [MaxStates];
F32 stateTimeoutValue [MaxStates];
bool stateWaitForTimeout [MaxStates];
bool stateFire [MaxStates];
bool stateAlternateFire [MaxStates];
bool stateReload [MaxStates];
bool stateEjectShell [MaxStates];
F32 stateEnergyDrain [MaxStates];
bool stateAllowImageChange [MaxStates];
bool stateScaleAnimation [MaxStates];
bool stateScaleAnimationFP [MaxStates];
bool stateSequenceTransitionIn [MaxStates];
bool stateSequenceTransitionOut [MaxStates];
bool stateSequenceNeverTransition [MaxStates];
F32 stateSequenceTransitionTime [MaxStates];
bool stateDirection [MaxStates];
StateData::LoadedState stateLoaded [MaxStates];
StateData::SpinState stateSpin [MaxStates];
StateData::RecoilState stateRecoil [MaxStates];
const char* stateSequence [MaxStates];
bool stateSequenceRandomFlash [MaxStates];
const char* stateShapeSequence [MaxStates];
bool stateScaleShapeSequence [MaxStates];
bool stateIgnoreLoadedForReady [MaxStates];
DECLARE_SOUNDASSET_ARRAY(ShapeBaseImageData, stateSound, MaxStates);
DECLARE_ASSET_ARRAY_SETGET(ShapeBaseImageData, stateSound);
//SFXTrack* stateSound [MaxStates];
const char* stateScript [MaxStates];
ParticleEmitterData* stateEmitter [MaxStates];
F32 stateEmitterTime [MaxStates];
const char* stateEmitterNode [MaxStates];
/// @}
/// @name Camera Shake ( while firing )
/// @{
bool shakeCamera;
VectorF camShakeFreq;
VectorF camShakeAmp;
F32 camShakeDuration;
F32 camShakeRadius;
F32 camShakeFalloff;
/// @}
/// Maximum number of sounds this image can play at a time.
/// Any value <= 0 indicates that it can play an infinite number of sounds.
S32 maxConcurrentSounds;
/// If true it we will allow multiple timeout transitions to occur within
/// a single tick ( eg. they have a very small timeout ).
bool useRemainderDT;
//
bool correctMuzzleVector; ///< Adjust 1st person firing vector to eye's LOS point?
bool correctMuzzleVectorTP; ///< Adjust 3rd person firing vector to camera's LOS point?
bool firstPerson; ///< Render the image when in first person?
bool useFirstPersonShape; ///< Indicates the special first person shape should be used (true when shapeNameFP and useEyeOffset are defined)
bool useEyeOffset; ///< In first person, should we use the eyeTransform?
bool useEyeNode; ///< In first person, should we attach the camera to the image's eye node? Player still ultimately decides on what to do,
/// especially for multiple mounted images.
bool animateAllShapes; ///< Indicates that all shapes should be animated in sync.
bool animateOnServer; ///< Indicates that the image should be animated on the server. In most cases
/// you'll want this set if you're using useEyeNode. You may also want to
/// set this if the muzzlePoint is animated while it shoots. You can set this
/// to false even if these previous cases are true if the image's shape is set
/// up in the correct position and orientation in the 'root' pose and none of
/// the nodes are animated at key times, such as the muzzlePoint essentially
/// remaining at the same position at the start of the fire state (it could
/// animate just fine after the projectile is away as the muzzle vector is only
/// calculated at the start of the state). You'll also want to set this to true
/// if you're animating the camera using an image's 'eye' node -- unless the movement
/// is very subtle and doesn't need to be reflected on the server.
F32 scriptAnimTransitionTime; ///< The amount of time to transition between the previous sequence and new sequence
///< when the script prefix has changed.
DECLARE_SHAPEASSET_ARRAY(ShapeBaseImageData, Shape, MaxShapes); ///< Name of shape to render.
DECLARE_ASSET_ARRAY_SETGET(ShapeBaseImageData, Shape);
//DECLARE_SHAPEASSET(ShapeBaseImageData, ShapeFP); ///< Name of shape to render in first person (optional).
//DECLARE_ASSET_SETGET(ShapeBaseImageData, ShapeFP);
StringTableEntry imageAnimPrefix; ///< Passed along to the mounting shape to modify
/// animation sequences played in 3rd person. [optional]
StringTableEntry imageAnimPrefixFP; ///< Passed along to the mounting shape to modify
/// animation sequences played in first person. [optional]
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.
LinearColorF lightColor;
S32 lightDuration; ///< The duration in SimTime of Pulsing or WeaponFire type lights.
F32 lightRadius; ///< Extent of light.
F32 lightBrightness; ///< Brightness of the light ( if it is WeaponFireLight ).
/// @}
/// @name Shape Data
/// @{
bool shapeIsValid[MaxShapes]; ///< Indicates that the shape has been loaded and is valid
U32 mCRC[MaxShapes]; ///< Checksum of shape.
///
/// Calculated by the ResourceManager, see
/// ResourceManager::load().
bool computeCRC; ///< Should the shape's CRC be checked?
MatrixF mountTransform[MaxShapes]; ///< Transformation to get to the mountNode.
/// @}
/// @name Nodes
/// @{
S32 retractNode[MaxShapes]; ///< 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[MaxShapes]; ///< Muzzle node ID.
///
///
S32 ejectNode[MaxShapes]; ///< Ejection node ID.
///
/// The eject node is the node on the image from which shells are ejected.
S32 emitterNode[MaxShapes]; ///< Emitter node ID.
///
/// The emitter node is the node from which particles are emitted.
S32 eyeMountNode[MaxShapes]; ///< eyeMount node ID. Optionally used to mount an image to the player's
/// eye node for first person.
S32 eyeNode[MaxShapes]; ///< Eye node ID. Optionally used to attach the camera to for camera motion
/// control from the image.
/// @}
/// @name Animation
/// @{
S32 spinSequence[MaxShapes]; ///< ID of the spin animation sequence.
S32 ambientSequence[MaxShapes]; ///< ID of the ambient animation sequence.
bool isAnimated[MaxShapes]; ///< This image contains at least one animated states
bool hasFlash[MaxShapes]; ///< This image contains at least one muzzle flash animation state
S32 fireState; ///< The ID of the fire state.
S32 altFireState; ///< The ID of the alternate fire state.
S32 reloadState; ///< The ID of the reload 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, String &errorStr);
S32 lookupState(const char* name); ///< Get a state by name.
static void initPersistFields();
virtual void packData(BitStream* stream);
virtual void unpackData(BitStream* stream);
void inspectPostApply();
void handleStateSoundTrack(const U32& stateId);
/// @}
/// @name Callbacks
/// @{
DECLARE_CALLBACK( void, onMount, ( SceneObject* obj, S32 slot, F32 dt ) );
DECLARE_CALLBACK( void, onUnmount, ( SceneObject* obj, S32 slot, F32 dt ) );
/// @}
};
typedef ShapeBaseImageData::LightType ShapeBaseImageLightType;
typedef ShapeBaseImageData::StateData::LoadedState ShapeBaseImageLoadedState;
typedef ShapeBaseImageData::StateData::SpinState ShapeBaseImageSpinState;
typedef ShapeBaseImageData::StateData::RecoilState ShapeBaseImageRecoilState;
DefineEnumType( ShapeBaseImageLightType );
DefineEnumType( ShapeBaseImageLoadedState );
DefineEnumType( ShapeBaseImageSpinState );
DefineEnumType( ShapeBaseImageRecoilState );
//--------------------------------------------------------------------------
/// @nosubgrouping
struct ShapeBaseData : public GameBaseData {
private:
typedef GameBaseData Parent;
static bool _setMass( void* object, const char* index, const char* data );
public:
/// Various constants relating to the ShapeBaseData
enum Constants {
MaxCollisionShapes = 8,
AIRepairNode = 31
};
// TODO: These are only really used in Basic Lighting
// mode... we should probably move them somewhere else.
U32 shadowSize;
F32 shadowMaxVisibleDistance;
F32 shadowProjectionDistance;
F32 shadowSphereAdjust;
DECLARE_SHAPEASSET(ShapeBaseData, Shape, onShapeChanged);
DECLARE_ASSET_SETGET(ShapeBaseData, Shape);
StringTableEntry cloakTexName;
String cubeDescName;
U32 cubeDescId;
ReflectorDesc *reflectorDesc;
/// @name Destruction
///
/// Everyone likes to blow things up!
/// @{
DebrisData * debris;
S32 debrisID;
DECLARE_SHAPEASSET(ShapeBaseData, DebrisShape, onDebrisChanged);
DECLARE_ASSET_SETGET(ShapeBaseData, 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;
/// @}
/// @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 vertical FOV in degrees.
F32 cameraMinFov; ///< Min vertical FOV allowed in degrees.
F32 cameraMaxFov; ///< Max vertical FOV allowed in degrees.
/// @}
/// @name Camera Misc
/// @{
bool cameraCanBank; ///< If the derrived class supports it, allow the camera to bank
bool mountedImagesBank; ///< Do mounted images bank along with the camera?
/// @}
/// @name Data initialized on preload
/// @{
U32 mCRC;
bool computeCRC;
S32 eyeNode; ///< Shape's eye node index
S32 earNode; ///< Shape's ear node index
S32 cameraNode; ///< Shape's camera node index
S32 mountPointNode[SceneObject::NumMountPoints]; ///< Node index of mountPoint
S32 debrisDetail; ///< Detail level used to generate debris
S32 damageSequence; ///< Damage level decals
S32 hulkSequence; ///< Destroyed hulk
bool observeThroughObject; // observe this object through its camera transform and default fov
/// @name Collision Data
/// @{
Vector<S32> collisionDetails; ///< Detail level used to collide with.
///
/// These are detail IDs, see TSShape::findDetail()
Vector<Box3F> collisionBounds; ///< Detail level bounding boxes.
Vector<S32> LOSDetails; ///< Detail level used to perform line-of-sight queries against.
///
/// These are detail IDs, see TSShape::findDetail()
/// @}
/// @name Misc. Settings
/// @{
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 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;
/// @}
virtual bool preload(bool server, String &errorStr);
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);
/// @}
/// @name Callbacks
/// @{
DECLARE_CALLBACK( void, onEnabled, ( ShapeBase* obj, const char* lastState ) );
DECLARE_CALLBACK( void, onDisabled, ( ShapeBase* obj, const char* lastState ) );
DECLARE_CALLBACK( void, onDestroyed, ( ShapeBase* obj, const char* lastState ) );
DECLARE_CALLBACK( void, onImpact, ( ShapeBase* obj, SceneObject* collObj, VectorF vec, F32 len ) );
DECLARE_CALLBACK( void, onCollision, ( ShapeBase* obj, SceneObject* collObj, VectorF vec, F32 len ) );
DECLARE_CALLBACK( void, onDamage, ( ShapeBase* obj, F32 delta ) );
DECLARE_CALLBACK( void, onTrigger, ( ShapeBase* obj, S32 index, bool state ) );
DECLARE_CALLBACK( void, onEndSequence, (ShapeBase* obj, S32 slot, const char* name));
DECLARE_CALLBACK( void, onForceUncloak, ( ShapeBase* obj, const char* reason ) );
/// @}
struct TextureTagRemapping
{
char* old_tag;
char* new_tag;
};
StringTableEntry remap_txr_tags;
char* remap_buffer;
Vector<TextureTagRemapping> txr_tag_remappings;
bool silent_bbox_check;
void onShapeChanged() {}
void onDebrisChanged() {}
public:
ShapeBaseData(const ShapeBaseData&, bool = false);
};
//----------------------------------------------------------------------------
class WaterObject;
class CameraShake;
/// 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, public ISceneLight
{
friend class ShapeBaseConvex;
friend struct ShapeBaseImageData;
friend void waterFind(SceneObject*, void*);
friend void physicalZoneFind(SceneObject*, void*);
public:
typedef GameBase Parent;
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,
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.
};
protected:
ShapeBaseData* mDataBlock; ///< Datablock
bool mIsAiControlled; ///< Is this object AI controlled?
//GameConnection* mControllingClient; ///< Controlling client
ShapeBase* mControllingObject; ///< Controlling object
bool mTrigger[MaxTriggerKeys]; ///< What triggers are set, if any.
/// @name Scripted Sound
/// @{
struct SoundThread {
bool play; ///< Are we playing this sound?
SimTime timeout; ///< Time until we stop playing this sound.
AssetPtr<SoundAsset> asset; ///< Asset on server
SFXSource* sound; ///< Sound on client
};
SoundThread mSoundThread[MaxSoundThreads];
/// @}
/// @name Scripted Animation Threads
/// @{
struct Thread {
/// State of the animation thread.
enum State {
Play, Stop, Pause, Destroy
};
TSThread* thread; ///< Pointer to 3space data.
State state; ///< State of the thread
S32 sequence; ///< The animation sequence which is running in this thread.
F32 timescale; ///< Timescale
bool atEnd; ///< Are we at the end of this thread?
F32 position;
};
Thread mScriptThread[MaxScriptThreads];
/// @}
/// @name Motion
/// @{
bool mMoveMotion; ///< Indicates that a Move has come in requesting x, y or z motion
/// @}
protected:
// ShapeBase pointer to our mount object if it is ShapeBase, else it is NULL.
ShapeBase *mShapeBaseMount;
/// @name Mounted Images
/// @{
/// An image mounted on a shapebase.
struct MountedImage {
ShapeBaseImageData* dataBlock;
ShapeBaseImageData::StateData *state;
ShapeBaseImageData* nextImage;
NetStringHandle skinNameHandle;
NetStringHandle nextSkinNameHandle;
String appliedSkinName;
NetStringHandle scriptAnimPrefix; ///< The script based anim prefix
/// @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.
F32 rDT; ///< Remainder delta time. Used internally.
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()
U32 altFireCount; ///< Alternate fire skip count.
///< @see fireCount
U32 reloadCount; ///< Reload skip count.
///< @see fireCount
bool triggerDown; ///< Is the trigger down?
bool altTriggerDown; ///< Is the second 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?
bool motion; ///< Is the player in motion?
bool genericTrigger[ShapeBaseImageData::MaxGenericTriggers]; ///< Generic triggers not assigned to anything in particular. These
/// may be used to indicate some transition should occur.
/// @}
/// @name 3space
///
/// Handles to threads and shapeinstances in the 3space system.
/// @{
TSShapeInstance* shapeInstance[ShapeBaseImageData::MaxShapes];
TSThread *ambientThread[ShapeBaseImageData::MaxShapes];
TSThread *visThread[ShapeBaseImageData::MaxShapes];
TSThread *animThread[ShapeBaseImageData::MaxShapes];
TSThread *flashThread[ShapeBaseImageData::MaxShapes];
TSThread *spinThread[ShapeBaseImageData::MaxShapes];
bool doAnimateAllShapes; ///< Should all threads animate across all shapes to keep them in sync?
bool forceAnimateAllShapes; ///< If the mounted image's owner is being controlled by the client
/// and the image's datablock animateAllShapes field is true
/// then set this to true and pass along to the client. This will help
/// in the cases where the client's control object is ghosted but does
/// not yet have its controlling client set correctly due to networking
/// order of operations. All this for the MountedImage::updateDoAnimateAllShapes()
/// optimization.
U32 lastShapeIndex; ///< Tracks the last shape index.
/// @}
/// @name Effects
///
/// Variables relating to lights, sounds, and particles.
/// @{
SimTime lightStart; ///< Starting time for light flashes.
LightInfo* lightInfo; ///< The real light (if any) associated with this weapon image.
Vector<SFXSource*> mSoundSources; ///< Vector of currently playing sounds
void updateSoundSources(const MatrixF& renderTransform);
void addSoundSource(SFXSource* source);
/// Represent the state of a specific particle emitter on the image.
struct ImageEmitter {
S32 node;
F32 time;
SimObjectPtr<ParticleEmitter> emitter;
};
ImageEmitter emitter[MaxImageEmitters];
/// @}
//
MountedImage();
~MountedImage();
void updateDoAnimateAllShapes(const ShapeBase* owner);
};
MountedImage mMountedImageList[MaxMountedImages];
/// @}
/// @name Render settings
/// @{
TSShapeInstance* mShapeInstance;
Convex * mConvexList;
NetStringHandle mSkinNameHandle;
String mAppliedSkinName;
NetStringHandle mShapeNameHandle; ///< Name sent to client
/// @}
/// @name Physical Properties
/// @{
S32 mAiPose; ///< Current pose.
F32 mEnergy; ///< Current enery level.
F32 mRechargeRate; ///< Energy recharge rate (in units/tick).
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.
String 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 mNetGravity;
/// @}
F32 mDamageFlash;
F32 mWhiteOut;
bool mFlipFadeVal;
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;
SceneObject* 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();
/// 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( SceneObject *object, const VectorF &vec);
/// @see SceneObject
virtual void onCollision( SceneObject *object, const VectorF &vec );
/// @}
protected:
/// @name Damage
/// @{
F32 mDamage;
F32 mRepairRate;
F32 mRepairReserve;
DamageState mDamageState;
TSThread *mDamageThread;
TSThread *mHulkThread;
VectorF damageDir;
/// @}
/// @name Cloaking
/// @{
bool mCloaked;
F32 mCloakLevel;
// TextureHandle mCloakTexture;
/// @}
/// @name Fading
/// @{
bool mFadeOut;
bool mFading;
F32 mFadeVal;
F32 mFadeElapsedTime;
F32 mFadeTime;
F32 mFadeDelay;
public:
F32 getFadeVal() { return mFadeVal; }
/// @}
protected:
/// @name Control info
/// @{
F32 mCameraFov; ///< The camera vertical FOV in degrees.
bool mIsControlled; ///< Client side controlled flag
/// @}
public:
static U32 sLastRenderFrame;
protected:
U32 mLastRenderFrame;
F32 mLastRenderDistance;
/// Do a reskin if necessary.
virtual void reSkin();
/// 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 altTriggerDown Is the second trigger on this image down?
/// @param target Does the image have a target?
virtual void setImage( U32 imageSlot,
ShapeBaseImageData* imageData,
NetStringHandle &skinNameHandle,
bool loaded = true, bool ammo = false,
bool triggerDown = false,
bool altTriggerDown = false,
bool motion = false,
bool genericTrigger0 = false,
bool genericTrigger1 = false,
bool genericTrigger2 = false,
bool genericTrigger3 = 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);
/// Get the alternate firing action state of the image
/// @param imageSlot Image slot id
U32 getImageAltFireState(U32 imageSlot);
/// Get the reload action state of the image
/// @param imageSlot Image slot id
U32 getImageReloadState(U32 imageSlot);
/// Sets the state of the image by state index
/// @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);
void updateAnimThread(U32 imageSlot, S32 imageShapeIndex, ShapeBaseImageData::StateData* lastState=NULL);
/// Get the animation prefix for the image
/// @param imageSlot Image slot id
/// @param imageShapeIndex Shape index (1st person, etc.) used to look up the prefix text
virtual const char* getImageAnimPrefix(U32 imageSlot, S32 imageShapeIndex) { return ""; }
/// 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);
/// Get the shape index to use for a mounted image
/// @param image Mounted image
U32 getImageShapeIndex(const MountedImage& image) const;
/// @}
/// 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(SoundThread& 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 onImage(U32 imageSlot, bool unmount);
virtual void onImageRecoil(U32 imageSlot,ShapeBaseImageData::StateData::RecoilState);
virtual void onImageStateAnimation(U32 imageSlot, const char* seqName, bool direction, bool scaleToState, F32 stateTimeOutValue);
virtual void onImageAnimThreadChange(U32 imageSlot, S32 imageShapeIndex, ShapeBaseImageData::StateData* lastState, const char* anim, F32 pos, F32 timeScale, bool reset=false);
virtual void onImageAnimThreadUpdate(U32 imageSlot, S32 imageShapeIndex, F32 dt);
virtual void ejectShellCasing( U32 imageSlot );
virtual void shakeCamera( U32 imageSlot );
virtual void updateDamageLevel();
virtual void updateDamageState();
virtual void onImpact(SceneObject* obj, const VectorF& vec);
virtual void onImpact(const VectorF& vec);
/// @}
/// The inner prep render function that does the
/// standard work to render the shapes.
void _prepRenderImage( SceneRenderState* state,
bool renderSelf,
bool renderMountedImages );
/// Renders the shape bounds as well as the
/// bounds of all mounted shape images.
void _renderBoundingBox( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance* );
void emitDust( ParticleEmitter* emitter, F32 triggerHeight, const Point3F& offset, U32 numMilliseconds, const Point3F& axis = Point3F::Zero );
public:
ShapeBase();
~ShapeBase();
TSShapeInstance* getShapeInstance() { return mShapeInstance; }
static void initPersistFields();
static bool _setFieldSkin( void *object, const char *index, const char *data );
static const char *_getFieldSkin( void *object, const char *data );
/// @name Network state masks
/// @{
///
enum ShapeBaseMasks {
NameMask = Parent::NextFreeMask,
DamageMask = Parent::NextFreeMask << 1,
NoWarpMask = Parent::NextFreeMask << 2,
CloakMask = Parent::NextFreeMask << 3,
SkinMask = Parent::NextFreeMask << 4,
MeshHiddenMask = Parent::NextFreeMask << 5,
SoundMaskN = Parent::NextFreeMask << 6, ///< 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 F32 sWhiteoutDec;
static F32 sDamageFlashDec;
static F32 sFullCorrectionDistance;
static F32 sCloakSpeed; // Time to cloak, in seconds
CubeReflector mCubeReflector;
/// @name Initialization
/// @{
bool onAdd();
void onRemove();
void onSceneRemove();
static void consoleInit();
bool onNewDataBlock( GameBaseData *dptr, bool reload );
/// @}
/// @name Name & Skin tags
/// @{
void setShapeName(const char*);
const char* getShapeName();
void setSkinName(const char*);
const char* getSkinName();
/// @}
/// @name Mesh Visibility
/// @{
protected:
/// A bit vector of the meshes forced to be hidden.
BitVector mMeshHidden;
/// Sync the shape instance with the hidden mesh bit vector.
void _updateHiddenMeshes();
public:
/// Change the hidden state on all the meshes.
void setAllMeshesHidden( bool forceHidden );
/// Set the force hidden state on a mesh.
void setMeshHidden( S32 meshIndex, bool forceHidden );
/// Set the force hidden state on a named mesh.
void setMeshHidden( const char *meshName, bool forceHidden );
#ifndef TORQUE_SHIPPING
/// Prints the list of meshes and their visibility state
/// to the console for debugging purposes.
void dumpMeshVisibility();
#endif
/// @}
public:
/// @name Basic attributes
/// @{
/// Sets the amount 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 datablock.maxDamage value
F32 getMaxDamage();
/// 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; }
/// Makes the shape explode.
virtual void blowUp();
/// @}
/// @name Script sounds
/// @{
/// Plays an audio sound from a mounted object
/// @param slot Mount slot ID
void playAudio(U32 slot, StringTableEntry assetId);
/// Stops audio from a mounted object
/// @param slot Mount slot ID
void stopAudio(U32 slot);
/// @}
/// @name Script animation
/// @{
const char *getThreadSequenceName( U32 slot );
/// Sets the animation thread for a mounted object
/// @param slot Mount slot ID
/// @param seq Sequence 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);
/// Destroys the given animation thread
/// @param slot Mount slot ID
bool destroyThread(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);
/// Set the thread position
/// @param slot Mount slot ID
/// @param pos Position
bool setThreadPosition( U32 slot, F32 pos );
/// 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);
/// Set the thread time scale
/// @param slot Mount slot ID
/// @param timescale Timescale
bool setThreadTimeScale( U32 slot, F32 timeScale );
/// 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
/// @{
virtual void onMount( SceneObject *obj, S32 node );
virtual void onUnmount( SceneObject *obj,S32 node );
virtual void getMountTransform( S32 index, const MatrixF &xfm, MatrixF *outMat );
virtual void getRenderMountTransform( F32 delta, S32 index, const MatrixF &xfm, MatrixF *outMat );
/// @}
/// 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, NetStringHandle &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];
U32 imageShapeIndex = getImageShapeIndex(image);
if(image.dataBlock && image.shapeInstance[imageShapeIndex])
return image.shapeInstance[imageShapeIndex];
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);
/// Returns true if the mounted image is alternate firing
/// @param imageSlot Mountpoint
bool isImageAltFiring(U32 imageSlot);
/// Returns true if the mounted image is reloading
/// @param imageSlot Mountpoint
bool isImageReloading(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
NetStringHandle getImageSkinTag(U32 imageSlot);
/// Check if the given state exists on the mounted Image
/// @param imageSlot Image slot id
/// @param state Image state to check for
bool hasImageState(U32 imageSlot, const char* state);
/// Returns the image state as a string
/// @param imageSlot Image slot to check state
const char* getImageState(U32 imageSlot);
/// Sets the generic trigger state of the image
/// @param imageSlot Image slot
/// @param trigger Generic trigger number 0-3
/// @param state True if generic trigger is down
void setImageGenericTriggerState(U32 imageSlot, U32 trigger, bool state);
/// Returns the generic trigger state of the image
/// @param imageSlot Image slot
/// @param trigger Generic trigger number 0-3
bool getImageGenericTriggerState(U32 imageSlot, U32 trigger);
/// 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 alt trigger state of the image (Ie trigger pulled down on gun)
/// @param imageSlot Image slot
/// @param trigger True if trigger is down
void setImageAltTriggerState( U32 imageSlot, bool trigger );
/// Returns the alt trigger state of the image
/// @param imageSlot Image slot
bool getImageAltTriggerState( 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 image as in motion or not, IE if you wanted a gun not to sway while the player is in motion
/// @param imageSlot Image slot
/// @param motion True if image is in motion
void setImageMotionState(U32 imageSlot,bool motion);
/// Returns true if image is in motion
/// @param imageSlot image slot
bool getImageMotionState(U32 imageSlot);
/// Sets the flag if the image has a target
/// @param imageSlot Image slot
/// @param ammo True if the weapon has a target
void setImageTargetState(U32 imageSlot,bool ammo);
/// Returns true if the image has a target
/// @param imageSlot Image slot
bool getImageTargetState(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);
/// Set the script animation prefix for the image
/// @param imageSlot Image slot id
/// @param prefix The prefix applied to the image
void setImageScriptAnimPrefix(U32 imageSlot, NetStringHandle prefix);
/// Get the script animation prefix for the image
/// @param imageSlot Image slot id
/// @param imageShapeIndex Shape index (1st person, etc.) used to look up the prefix text
NetStringHandle getImageScriptAnimPrefix(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 to world space transform matrix
/// @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 view transform for a particular eye, taking into account the current absolute
/// orient and position values of the display device.
virtual void getEyeCameraTransform( IDisplayDevice *display, U32 eyeId, MatrixF *outMat );
/// 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);
/// Returns the eye transform of this shape without including mounted images, IE the eyes of a player
/// @param mat Eye transform (out)
virtual void getEyeBaseTransform(MatrixF* mat, bool includeBank);
/// 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);
/// 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 getRenderMuzzleTransform(U32 index,MatrixF* mat);
virtual void getRenderImageTransform(U32 imageSlot,MatrixF* mat,bool noEyeOffset=false);
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);
virtual void getRenderEyeBaseTransform(MatrixF* mat, bool includeBank);
/// @}
/// @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 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
/// @{
/// Returns the object controlling this object
ShapeBase* getControllingObject() { return mControllingObject; }
/// Sets the controlling object
/// @param obj New controlling object
virtual void setControllingObject(ShapeBase* obj);
///
virtual void setControllingClient( GameConnection* connection );
/// Returns the object this is controlling
virtual ShapeBase* getControlObject();
/// sets the object this is controlling
/// @param obj New controlled object
virtual void setControlObject(ShapeBase *obj);
/// Returns true if this object is controlling by something
bool isControlled() { return(mIsControlled); }
/// Returns true if this object is being used as a camera in first person
bool isFirstPerson() const;
/// 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 vertical field of view in degrees for
/// this object if used as a camera.
virtual F32 getCameraFov() { return mCameraFov; }
/// Returns the default vertical field of view in degrees
/// if this object is used as a camera.
virtual F32 getDefaultCameraFov() { return mDataBlock->cameraDefaultFov; }
/// Sets the vertical field of view in degrees for this
/// object if used as a camera.
/// @param yfov The vertical FOV in degrees to test.
virtual void setCameraFov(F32 fov);
/// Returns true if the vertical FOV in degrees is within
/// allowable parameters of the datablock.
/// @param yfov The vertical FOV in degrees to test.
/// @see ShapeBaseData::cameraMinFov
/// @see ShapeBaseData::cameraMaxFov
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();
/// @see SceneObject
virtual void prepRenderImage( SceneRenderState* state );
/// Used from ShapeBase::_prepRenderImage() to submit render
/// instances for the main shape or its mounted elements.
virtual void prepBatchRender( SceneRenderState *state, S32 mountedImageIndex );
/// Preprender logic
virtual void calcClassRenderData() { }
/// Virtualize this so other classes may override it for custom reasons.
virtual void renderMountedImage( U32 imageSlot, TSRenderState &rstate, SceneRenderState *state );
/// @}
/// Control object scoping
void onCameraScopeQuery(NetConnection *cr, CameraScopeQuery *camInfo);
bool castRay(const Point3F &start, const Point3F &end, RayInfo* info);
bool castRayRendered(const Point3F &start, const Point3F &end, RayInfo* info);
bool buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F &box, const SphereF& sphere);
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 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);
// ISceneLight
virtual void submitLights( LightManager *lm, bool staticLighting );
virtual LightInfo* getLight() { return NULL; }
/// @}
/// 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; }
virtual WaterObject* getCurrentWaterObject();
void setCurrentWaterObject( WaterObject *obj );
void setTransform(const MatrixF & mat);
virtual F32 getMass() const { return mMass; }
/// @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);
/// @}
DECLARE_CONOBJECT(ShapeBase);
protected:
DECLARE_CALLBACK( F32, validateCameraFov, (F32 fov) );
public:
class CollisionEventCallback
{
public:
virtual void collisionNotify(SceneObject* shape0, SceneObject* shape1, const VectorF& vel)=0;
};
private:
Vector<CollisionEventCallback*> collision_callbacks;
void notifyCollisionCallbacks(SceneObject*, const VectorF& vel);
public:
void registerCollisionCallback(CollisionEventCallback*);
void unregisterCollisionCallback(CollisionEventCallback*);
protected:
enum {
ANIM_OVERRIDDEN = BIT(0),
BLOCK_USER_CONTROL = BIT(1),
IS_DEATH_ANIM = BIT(2),
BAD_ANIM_ID = 999999999,
BLENDED_CLIP = 0x80000000,
};
struct BlendThread
{
TSThread* thread;
U32 tag;
};
Vector<BlendThread> blend_clips;
static U32 unique_anim_tag_counter;
U8 anim_clip_flags;
S32 last_anim_id;
U32 last_anim_tag;
U32 last_anim_lock_tag;
S32 saved_seq_id;
F32 saved_pos;
F32 saved_rate;
U32 playBlendAnimation(S32 seq_id, F32 pos, F32 rate);
void restoreBlendAnimation(U32 tag);
public:
U32 playAnimation(const char* name, F32 pos, F32 rate, F32 trans, bool hold, bool wait, bool is_death_anim);
F32 getAnimationDuration(const char* name);
virtual void restoreAnimation(U32 tag);
virtual U32 getAnimationID(const char* name);
virtual U32 playAnimationByID(U32 anim_id, F32 pos, F32 rate, F32 trans, bool hold, bool wait, bool is_death_anim);
virtual F32 getAnimationDurationByID(U32 anim_id);
virtual bool isBlendAnimation(const char* name);
virtual const char* getLastClipName(U32 clip_tag);
virtual void unlockAnimation(U32 tag, bool force=false) { }
virtual U32 lockAnimation() { return 0; }
virtual bool isAnimationLocked() const { return false; }
virtual void setSelectionFlags(U8 flags);
};
//------------------------------------------------------------------------------
// 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();
}
inline WaterObject* ShapeBase::getCurrentWaterObject()
{
if ( isMounted() && mShapeBaseMount )
return mShapeBaseMount->getCurrentWaterObject();
return mCurrentWaterObject;
}
#endif // _H_SHAPEBASE_