Commit cda70972 authored by Daniel Buckmaster's avatar Daniel Buckmaster

Merge pull request #1087 from GarageGames/development-3.6

Version 3.6.3
parents d01b48c9 cae70a9c
...@@ -438,7 +438,7 @@ bool AIPlayer::getAIMove(Move *movePtr) ...@@ -438,7 +438,7 @@ bool AIPlayer::getAIMove(Move *movePtr)
// Replicate the trigger state into the move so that // Replicate the trigger state into the move so that
// triggers can be controlled from scripts. // triggers can be controlled from scripts.
for( S32 i = 0; i < MaxTriggerKeys; i++ ) for( U32 i = 0; i < MaxMountedImages; i++ )
movePtr->trigger[i] = getImageTriggerState(i); movePtr->trigger[i] = getImageTriggerState(i);
mLastLocation = location; mLastLocation = location;
...@@ -703,7 +703,7 @@ bool AIPlayer::checkInFoV(GameBase* target, F32 camFov, bool _checkEnabled) ...@@ -703,7 +703,7 @@ bool AIPlayer::checkInFoV(GameBase* target, F32 camFov, bool _checkEnabled)
// projection and box test. // projection and box test.
shapeDir.normalize(); shapeDir.normalize();
F32 dot = mDot(shapeDir, camDir); F32 dot = mDot(shapeDir, camDir);
return (dot > camFov); return (dot > mCos(camFov));
} }
DefineEngineMethod(AIPlayer, checkInFoV, bool, (ShapeBase* obj, F32 fov, bool checkEnabled), (NULL, 45.0f, false), DefineEngineMethod(AIPlayer, checkInFoV, bool, (ShapeBase* obj, F32 fov, bool checkEnabled), (NULL, 45.0f, false),
......
...@@ -182,9 +182,9 @@ void GuiShapeNameHud::onRender( Point2I, const RectI &updateRect) ...@@ -182,9 +182,9 @@ void GuiShapeNameHud::onRender( Point2I, const RectI &updateRect)
cam.getColumn(3, &camPos); cam.getColumn(3, &camPos);
cam.getColumn(1, &camDir); cam.getColumn(1, &camDir);
F32 camFov; F32 camFovCos;
conn->getControlCameraFov(&camFov); conn->getControlCameraFov(&camFovCos);
camFov = mDegToRad(camFov) / 2; camFovCos = mCos(mDegToRad(camFovCos) / 2);
// Visible distance info & name fading // Visible distance info & name fading
F32 visDistance = gClientSceneGraph->getVisibleDistance(); F32 visDistance = gClientSceneGraph->getVisibleDistance();
...@@ -236,7 +236,7 @@ void GuiShapeNameHud::onRender( Point2I, const RectI &updateRect) ...@@ -236,7 +236,7 @@ void GuiShapeNameHud::onRender( Point2I, const RectI &updateRect)
// projection and box test. // projection and box test.
shapeDir.normalize(); shapeDir.normalize();
F32 dot = mDot(shapeDir, camDir); F32 dot = mDot(shapeDir, camDir);
if (dot < camFov) if (dot < camFovCos)
continue; continue;
// Test to see if it's behind something, and we want to // Test to see if it's behind something, and we want to
......
...@@ -606,7 +606,7 @@ void ExplosionData::packData(BitStream* stream) ...@@ -606,7 +606,7 @@ void ExplosionData::packData(BitStream* stream)
} }
U32 count; U32 count;
for(count = 0; count < EC_NUM_TIME_KEYS; count++) for(count = 0; count < EC_NUM_TIME_KEYS; count++)
if(times[i] >= 1) if(times[count] >= 1)
break; break;
count++; count++;
if(count > EC_NUM_TIME_KEYS) if(count > EC_NUM_TIME_KEYS)
......
...@@ -355,7 +355,7 @@ bool ParticleData::protectedSetSizes( void *object, const char *index, const cha ...@@ -355,7 +355,7 @@ bool ParticleData::protectedSetSizes( void *object, const char *index, const cha
U32 i; U32 i;
if (!index) if (!index)
i = 0; return (val >= 0.f && val <= MaxParticleSize);
else else
i = dAtoui(index); i = dAtoui(index);
...@@ -371,7 +371,7 @@ bool ParticleData::protectedSetTimes( void *object, const char *index, const cha ...@@ -371,7 +371,7 @@ bool ParticleData::protectedSetTimes( void *object, const char *index, const cha
U32 i; U32 i;
if (!index) if (!index)
i = 0; return (val >= 0.f && val <= 1.f);
else else
i = dAtoui(index); i = dAtoui(index);
......
...@@ -1825,22 +1825,22 @@ void ParticleEmitter::setupOriented( Particle *part, ...@@ -1825,22 +1825,22 @@ void ParticleEmitter::setupOriented( Particle *part,
lVerts->point = start + crossDir; lVerts->point = start + crossDir;
lVerts->color = partCol; lVerts->color = partCol;
// Here and below, we copy UVs from particle datablock's texCoords (oriented) // Here and below, we copy UVs from particle datablock's texCoords (oriented)
lVerts->texCoord = part->dataBlock->texCoords[0]; lVerts->texCoord = part->dataBlock->texCoords[1];
++lVerts; ++lVerts;
lVerts->point = start - crossDir; lVerts->point = start - crossDir;
lVerts->color = partCol; lVerts->color = partCol;
lVerts->texCoord = part->dataBlock->texCoords[1]; lVerts->texCoord = part->dataBlock->texCoords[2];
++lVerts; ++lVerts;
lVerts->point = end - crossDir; lVerts->point = end - crossDir;
lVerts->color = partCol; lVerts->color = partCol;
lVerts->texCoord = part->dataBlock->texCoords[2]; lVerts->texCoord = part->dataBlock->texCoords[3];
++lVerts; ++lVerts;
lVerts->point = end + crossDir; lVerts->point = end + crossDir;
lVerts->color = partCol; lVerts->color = partCol;
lVerts->texCoord = part->dataBlock->texCoords[3]; lVerts->texCoord = part->dataBlock->texCoords[0];
++lVerts; ++lVerts;
} }
......
...@@ -239,7 +239,7 @@ void GameUpdateCameraFov() ...@@ -239,7 +239,7 @@ void GameUpdateCameraFov()
F32 delta = time - sLastCameraUpdateTime; F32 delta = time - sLastCameraUpdateTime;
// snap zoom? // snap zoom?
if((sZoomSpeed == 0) || (delta <= 0.f)) if((sZoomSpeed == 0) || (delta <= 0.0f))
sCameraFov = sTargetFov; sCameraFov = sTargetFov;
else else
{ {
......
...@@ -26,16 +26,18 @@ ...@@ -26,16 +26,18 @@
#include "core/stream/bitStream.h" #include "core/stream/bitStream.h"
#include "console/engineAPI.h" #include "console/engineAPI.h"
#include "lighting/lightInfo.h" #include "lighting/lightInfo.h"
#include "lighting/lightQuery.h"
#include "math/mathUtils.h" #include "math/mathUtils.h"
#include "math/mathIO.h" #include "math/mathIO.h"
#include "scene/sceneRenderState.h" #include "scene/sceneRenderState.h"
#include "gfx/gfxOcclusionQuery.h" #include "gfx/gfxOcclusionQuery.h"
#include "gfx/gfxDrawUtil.h" #include "gfx/gfxDrawUtil.h"
#include "gfx/gfxTextureManager.h"
#include "renderInstance/renderPassManager.h" #include "renderInstance/renderPassManager.h"
#include "T3D/gameBase/gameConnection.h" #include "T3D/gameBase/gameConnection.h"
#include "T3D/gameBase/processList.h" #include "T3D/gameBase/processList.h"
#include "collision/collision.h" #include "collision/collision.h"
#include "lighting/lightManager.h"
const U32 LightFlareData::LosMask = STATIC_COLLISION_TYPEMASK | const U32 LightFlareData::LosMask = STATIC_COLLISION_TYPEMASK |
ShapeBaseObjectType | ShapeBaseObjectType |
...@@ -45,8 +47,6 @@ const U32 LightFlareData::LosMask = STATIC_COLLISION_TYPEMASK | ...@@ -45,8 +47,6 @@ const U32 LightFlareData::LosMask = STATIC_COLLISION_TYPEMASK |
LightFlareState::~LightFlareState() LightFlareState::~LightFlareState()
{ {
delete occlusionQuery;
delete fullPixelQuery;
} }
void LightFlareState::clear() void LightFlareState::clear()
...@@ -59,8 +59,6 @@ void LightFlareState::clear() ...@@ -59,8 +59,6 @@ void LightFlareState::clear()
lightInfo = NULL; lightInfo = NULL;
worldRadius = -1.0f; worldRadius = -1.0f;
occlusion = -1.0f; occlusion = -1.0f;
occlusionQuery = NULL;
fullPixelQuery = NULL;
} }
Point3F LightFlareData::sBasePoints[] = Point3F LightFlareData::sBasePoints[] =
...@@ -296,47 +294,39 @@ bool LightFlareData::_testVisibility(const SceneRenderState *state, LightFlareSt ...@@ -296,47 +294,39 @@ bool LightFlareData::_testVisibility(const SceneRenderState *state, LightFlareSt
// for one-shot initialization of LightFlareState // for one-shot initialization of LightFlareState
if ( useOcclusionQuery ) if ( useOcclusionQuery )
{ {
if ( flareState->occlusionQuery == NULL )
flareState->occlusionQuery = GFX->createOcclusionQuery();
if ( flareState->fullPixelQuery == NULL )
flareState->fullPixelQuery = GFX->createOcclusionQuery();
// Always treat light as onscreen if using HOQ // Always treat light as onscreen if using HOQ
// it will be faded out if offscreen anyway. // it will be faded out if offscreen anyway.
onScreen = true; onScreen = true;
needsRaycast = false;
// NOTE: These queries frame lock us as we block to get the
// results. This is ok as long as long as we're not too GPU
// bound... else we waste CPU time here waiting for it when
// we could have been doing other CPU work instead.
// Test the hardware queries for rendered pixels. // Test the hardware queries for rendered pixels.
U32 pixels = 0, fullPixels = 0; U32 pixels = 0, fullPixels = 0;
GFXOcclusionQuery::OcclusionQueryStatus status = flareState->occlusionQuery->getStatus( true, &pixels ); GFXOcclusionQuery::OcclusionQueryStatus status;
flareState->fullPixelQuery->getStatus( true, &fullPixels ); flareState->occlusionQuery.getLastStatus( false, &status, &pixels );
if ( status != GFXOcclusionQuery::Occluded && fullPixels != 0 ) flareState->fullPixelQuery.getLastStatus( false, NULL, &fullPixels );
if ( status == GFXOcclusionQuery::NotOccluded && fullPixels != 0 )
*outOcclusionFade = mClampF( (F32)pixels / (F32)fullPixels, 0.0f, 1.0f ); *outOcclusionFade = mClampF( (F32)pixels / (F32)fullPixels, 0.0f, 1.0f );
// If we got a result then we don't need to fallback to the raycast. if( !flareState->occlusionQuery.isWaiting() )
if ( status != GFXOcclusionQuery::Unset ) {
needsRaycast = false; // Setup the new queries.
RenderPassManager *rpm = state->getRenderPass();
// Setup the new queries. OccluderRenderInst *ri = rpm->allocInst<OccluderRenderInst>();
RenderPassManager *rpm = state->getRenderPass(); ri->type = RenderPassManager::RIT_Occluder;
OccluderRenderInst *ri = rpm->allocInst<OccluderRenderInst>(); ri->query = flareState->occlusionQuery.getQuery();
ri->type = RenderPassManager::RIT_Occluder; ri->query2 = flareState->fullPixelQuery.getQuery();
ri->query = flareState->occlusionQuery; ri->isSphere = true;
ri->query2 = flareState->fullPixelQuery; ri->position = lightPos;
ri->isSphere = true; if ( isVectorLight && flareState->worldRadius > 0.0f )
ri->position = lightPos; ri->scale.set( flareState->worldRadius );
if ( isVectorLight && flareState->worldRadius > 0.0f ) else
ri->scale.set( flareState->worldRadius ); ri->scale.set( mOcclusionRadius );
else ri->orientation = rpm->allocUniqueXform( lightInfo->getTransform() );
ri->scale.set( mOcclusionRadius );
ri->orientation = rpm->allocUniqueXform( lightInfo->getTransform() );
// Submit the queries. // Submit the queries.
state->getRenderPass()->addInst( ri ); state->getRenderPass()->addInst( ri );
}
} }
const Point3F &camPos = state->getCameraPosition(); const Point3F &camPos = state->getCameraPosition();
......
...@@ -41,12 +41,14 @@ ...@@ -41,12 +41,14 @@
#ifndef _GFXSTATEBLOCK_H_ #ifndef _GFXSTATEBLOCK_H_
#include "gfx/gfxStateBlock.h" #include "gfx/gfxStateBlock.h"
#endif #endif
#ifndef _GFXOCCLUSIONQUERY_H_
#include "gfx/gfxOcclusionQuery.h"
#endif
class LightInfo; class LightInfo;
struct ObjectRenderInst; struct ObjectRenderInst;
class SceneRenderState; class SceneRenderState;
class BaseMatInstance; class BaseMatInstance;
class GFXOcclusionQuery;
struct LightFlareState struct LightFlareState
{ {
...@@ -65,8 +67,8 @@ struct LightFlareState ...@@ -65,8 +67,8 @@ struct LightFlareState
bool visible; bool visible;
F32 occlusion; F32 occlusion;
GFXVertexBufferHandle<GFXVertexPCT> vertBuffer; GFXVertexBufferHandle<GFXVertexPCT> vertBuffer;
GFXOcclusionQuery *occlusionQuery; GFXOcclusionQueryHandle occlusionQuery;
GFXOcclusionQuery *fullPixelQuery; GFXOcclusionQueryHandle fullPixelQuery;
}; };
class LightFlareData : public SimDataBlock class LightFlareData : public SimDataBlock
......
...@@ -6152,13 +6152,16 @@ U32 Player::packUpdate(NetConnection *con, U32 mask, BitStream *stream) ...@@ -6152,13 +6152,16 @@ U32 Player::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
stream->writeInt((S32)len, 13); stream->writeInt((S32)len, 13);
} }
stream->writeFloat(mRot.z / M_2PI_F, 7); stream->writeFloat(mRot.z / M_2PI_F, 7);
stream->writeSignedFloat(mHead.x / mDataBlock->maxLookAngle, 6); stream->writeSignedFloat(mHead.x / (mDataBlock->maxLookAngle - mDataBlock->minLookAngle), 6);
stream->writeSignedFloat(mHead.z / mDataBlock->maxFreelookAngle, 6); stream->writeSignedFloat(mHead.z / mDataBlock->maxFreelookAngle, 6);
delta.move.pack(stream); delta.move.pack(stream);
stream->writeFlag(!(mask & NoWarpMask)); stream->writeFlag(!(mask & NoWarpMask));
} }
// Ghost need energy to predict reliably // Ghost need energy to predict reliably
stream->writeFloat(getEnergyLevel() / mDataBlock->maxEnergy,EnergyLevelBits); if (mDataBlock->maxEnergy > 0.f)
stream->writeFloat(getEnergyLevel() / mDataBlock->maxEnergy, EnergyLevelBits);
else
stream->writeFloat(0.f, EnergyLevelBits);
return retMask; return retMask;
} }
...@@ -6250,7 +6253,7 @@ void Player::unpackUpdate(NetConnection *con, BitStream *stream) ...@@ -6250,7 +6253,7 @@ void Player::unpackUpdate(NetConnection *con, BitStream *stream)
rot.y = rot.x = 0.0f; rot.y = rot.x = 0.0f;
rot.z = stream->readFloat(7) * M_2PI_F; rot.z = stream->readFloat(7) * M_2PI_F;
mHead.x = stream->readSignedFloat(6) * mDataBlock->maxLookAngle; mHead.x = stream->readSignedFloat(6) * (mDataBlock->maxLookAngle - mDataBlock->minLookAngle);
mHead.z = stream->readSignedFloat(6) * mDataBlock->maxFreelookAngle; mHead.z = stream->readSignedFloat(6) * mDataBlock->maxFreelookAngle;
delta.move.unpack(stream); delta.move.unpack(stream);
......
...@@ -940,8 +940,6 @@ ShapeBase::ShapeBase() ...@@ -940,8 +940,6 @@ ShapeBase::ShapeBase()
for (i = 0; i < MaxTriggerKeys; i++) for (i = 0; i < MaxTriggerKeys; i++)
mTrigger[i] = false; mTrigger[i] = false;
mWeaponCamShake = NULL;
} }
...@@ -1063,15 +1061,7 @@ void ShapeBase::onRemove() ...@@ -1063,15 +1061,7 @@ void ShapeBase::onRemove()
if ( isClientObject() ) if ( isClientObject() )
{ {
mCubeReflector.unregisterReflector(); mCubeReflector.unregisterReflector();
if ( mWeaponCamShake )
{
if ( mWeaponCamShake->isAdded )
gCamFXMgr.removeFX( mWeaponCamShake );
SAFE_DELETE( mWeaponCamShake );
}
} }
} }
...@@ -3161,40 +3151,9 @@ void ShapeBase::unpackUpdate(NetConnection *con, BitStream *stream) ...@@ -3161,40 +3151,9 @@ void ShapeBase::unpackUpdate(NetConnection *con, BitStream *stream)
{ {
if ( imageData->lightType == ShapeBaseImageData::WeaponFireLight ) if ( imageData->lightType == ShapeBaseImageData::WeaponFireLight )
image.lightStart = Sim::getCurrentTime(); image.lightStart = Sim::getCurrentTime();
// HACK: Only works properly if you are in control
// of the one and only shapeBase object in the scene
// which fires an image that uses camera shake.
if ( imageData->shakeCamera )
{
if ( !mWeaponCamShake )
{
mWeaponCamShake = new CameraShake();
mWeaponCamShake->remoteControlled = true;
}
mWeaponCamShake->init();
mWeaponCamShake->setFrequency( imageData->camShakeFreq );
mWeaponCamShake->setAmplitude( imageData->camShakeAmp );
if ( !mWeaponCamShake->isAdded )
{
gCamFXMgr.addFX( mWeaponCamShake );
mWeaponCamShake->isAdded = true;
}
}
} }
updateImageState(i,0); updateImageState(i,0);
if ( !image.triggerDown && !image.altTriggerDown )
{
if ( mWeaponCamShake && mWeaponCamShake->isAdded )
{
gCamFXMgr.removeFX( mWeaponCamShake );
mWeaponCamShake->isAdded = false;
}
}
} }
else else
{ {
......
...@@ -324,7 +324,10 @@ struct ShapeBaseImageData: public GameBaseData { ...@@ -324,7 +324,10 @@ struct ShapeBaseImageData: public GameBaseData {
/// @{ /// @{
bool shakeCamera; bool shakeCamera;
VectorF camShakeFreq; VectorF camShakeFreq;
VectorF camShakeAmp; VectorF camShakeAmp;
F32 camShakeDuration;
F32 camShakeRadius;
F32 camShakeFalloff;
/// @} /// @}
/// Maximum number of sounds this image can play at a time. /// Maximum number of sounds this image can play at a time.
...@@ -903,9 +906,6 @@ protected: ...@@ -903,9 +906,6 @@ protected:
bool mFlipFadeVal; bool mFlipFadeVal;
/// Camera shake caused by weapon fire.
CameraShake *mWeaponCamShake;
public: public:
/// @name Collision Notification /// @name Collision Notification
...@@ -1101,6 +1101,7 @@ protected: ...@@ -1101,6 +1101,7 @@ protected:
virtual void onImageAnimThreadChange(U32 imageSlot, S32 imageShapeIndex, ShapeBaseImageData::StateData* lastState, const char* anim, F32 pos, F32 timeScale, bool reset=false); 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 onImageAnimThreadUpdate(U32 imageSlot, S32 imageShapeIndex, F32 dt);
virtual void ejectShellCasing( U32 imageSlot ); virtual void ejectShellCasing( U32 imageSlot );
virtual void shakeCamera( U32 imageSlot );
virtual void updateDamageLevel(); virtual void updateDamageLevel();
virtual void updateDamageState(); virtual void updateDamageState();
virtual void onImpact(SceneObject* obj, VectorF vec); virtual void onImpact(SceneObject* obj, VectorF vec);
......
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include "sfx/sfxTypes.h" #include "sfx/sfxTypes.h"
#include "scene/sceneManager.h" #include "scene/sceneManager.h"
#include "core/stream/fileStream.h" #include "core/stream/fileStream.h"
#include "T3D/fx/cameraFXMgr.h"
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
...@@ -297,6 +298,9 @@ ShapeBaseImageData::ShapeBaseImageData() ...@@ -297,6 +298,9 @@ ShapeBaseImageData::ShapeBaseImageData()
shakeCamera = false; shakeCamera = false;
camShakeFreq = Point3F::Zero; camShakeFreq = Point3F::Zero;
camShakeAmp = Point3F::Zero; camShakeAmp = Point3F::Zero;
camShakeDuration = 1.5f;
camShakeRadius = 3.0f;
camShakeFalloff = 10.0f;
} }
ShapeBaseImageData::~ShapeBaseImageData() ShapeBaseImageData::~ShapeBaseImageData()
...@@ -739,10 +743,7 @@ void ShapeBaseImageData::initPersistFields() ...@@ -739,10 +743,7 @@ void ShapeBaseImageData::initPersistFields()
"@see lightType"); "@see lightType");
addField( "shakeCamera", TypeBool, Offset(shakeCamera, ShapeBaseImageData), addField( "shakeCamera", TypeBool, Offset(shakeCamera, ShapeBaseImageData),
"@brief Flag indicating whether the camera should shake when this Image fires.\n\n" "@brief Flag indicating whether the camera should shake when this Image fires.\n\n" );
"@note Camera shake only works properly if the player is in control of "
"the one and only shapeBase object in the scene which fires an Image that "
"uses camera shake." );
addField( "camShakeFreq", TypePoint3F, Offset(camShakeFreq, ShapeBaseImageData), addField( "camShakeFreq", TypePoint3F, Offset(camShakeFreq, ShapeBaseImageData),
"@brief Frequency of the camera shaking effect.\n\n" "@brief Frequency of the camera shaking effect.\n\n"
...@@ -752,6 +753,16 @@ void ShapeBaseImageData::initPersistFields() ...@@ -752,6 +753,16 @@ void ShapeBaseImageData::initPersistFields()
"@brief Amplitude of the camera shaking effect.\n\n" "@brief Amplitude of the camera shaking effect.\n\n"
"@see shakeCamera" ); "@see shakeCamera" );
addField( "camShakeDuration", TypeF32, Offset(camShakeDuration, ShapeBaseImageData),
"Duration (in seconds) to shake the camera." );
addField( "camShakeRadius", TypeF32, Offset(camShakeRadius, ShapeBaseImageData),
"Radial distance that a camera's position must be within relative to the "
"center of the explosion to be shaken." );
addField( "camShakeFalloff", TypeF32, Offset(camShakeFalloff, ShapeBaseImageData),
"Falloff value for the camera shake." );
addField( "casing", TYPEID< DebrisData >(), Offset(casing, ShapeBaseImageData), addField( "casing", TYPEID< DebrisData >(), Offset(casing, ShapeBaseImageData),
"@brief DebrisData datablock to use for ejected casings.\n\n" "@brief DebrisData datablock to use for ejected casings.\n\n"
"@see stateEjectShell" ); "@see stateEjectShell" );
...@@ -1028,6 +1039,9 @@ void ShapeBaseImageData::packData(BitStream* stream) ...@@ -1028,6 +1039,9 @@ void ShapeBaseImageData::packData(BitStream* stream)
{ {
mathWrite( *stream, camShakeFreq ); mathWrite( *stream, camShakeFreq );
mathWrite( *stream, camShakeAmp ); mathWrite( *stream, camShakeAmp );
stream->write( camShakeDuration );
stream->write( camShakeRadius );
stream->write( camShakeFalloff );
} }
mathWrite( *stream, shellExitDir ); mathWrite( *stream, shellExitDir );
...@@ -1208,7 +1222,10 @@ void ShapeBaseImageData::unpackData(BitStream* stream) ...@@ -1208,7 +1222,10 @@ void ShapeBaseImageData::unpackData(BitStream* stream)
if ( shakeCamera ) if ( shakeCamera )
{ {
mathRead( *stream, &camShakeFreq ); mathRead( *stream, &camShakeFreq );
mathRead( *stream, &camShakeAmp ); mathRead( *stream, &camShakeAmp );
stream->read( &camShakeDuration );
stream->read( &camShakeRadius );
stream->read( &camShakeFalloff );
} }
mathRead( *stream, &shellExitDir ); mathRead( *stream, &shellExitDir );
...@@ -2596,6 +2613,10 @@ void ShapeBase::setImageState(U32 imageSlot, U32 newState,bool force) ...@@ -2596,6 +2613,10 @@ void ShapeBase::setImageState(U32 imageSlot, U32 newState,bool force)
ejectShellCasing( imageSlot ); ejectShellCasing( imageSlot );
} }
// Shake camera on client.
if (isGhost() && nextStateData.fire && image.dataBlock->shakeCamera) {
shakeCamera( imageSlot );
}
// Server must animate the shape if it is a firestate... // Server must animate the shape if it is a firestate...
if (isServerObject() && (image.dataBlock->state[newState].fire || image.dataBlock->state[newState].altFire)) if (isServerObject() && (image.dataBlock->state[newState].fire || image.dataBlock->state[newState].altFire))
...@@ -3342,3 +3363,57 @@ void ShapeBase::ejectShellCasing( U32 imageSlot ) ...@@ -3342,3 +3363,57 @@ void ShapeBase::ejectShellCasing( U32 imageSlot )
casing->init( shellPos, shellVel ); casing->init( shellPos, shellVel );
} }
void ShapeBase::shakeCamera( U32 imageSlot )
{
MountedImage& image = mMountedImageList[imageSlot];
ShapeBaseImageData* imageData = image.dataBlock;
if (!imageData->shakeCamera)
return;
// Warning: this logic was duplicated from Explosion.
// first check if explosion is near camera
GameConnection* connection = GameConnection::getConnectionToServer();
ShapeBase *obj = dynamic_cast<ShapeBase*>(connection->getControlObject());
bool applyShake = true;
if (obj)
{
ShapeBase* cObj = obj;
while ((cObj = cObj->getControlObject()) != 0)
{
if (cObj->useObjsEyePoint())
{
applyShake = false;
break;
}
}
}
if (applyShake && obj)
{
VectorF diff;
getMuzzlePoint(imageSlot, &diff);
diff = obj->getPosition() - diff;
F32 dist = diff.len();
if (dist < imageData->camShakeRadius)
{
CameraShake *camShake = new CameraShake;
camShake->setDuration(imageData->camShakeDuration);
camShake->setFrequency(imageData->camShakeFreq);
F32 falloff = dist / imageData->camShakeRadius;
falloff = 1.0f + falloff * 10.0f;
falloff = 1.0f / (falloff * falloff);
VectorF shakeAmp = imageData->camShakeAmp * falloff;
camShake->setAmplitude(shakeAmp);
camShake->setFalloff(imageData->camShakeFalloff);
camShake->init();
gCamFXMgr.addFX(camShake);
}
}
}
\ No newline at end of file
...@@ -41,10 +41,10 @@ ...@@ -41,10 +41,10 @@
/// code version, the game name, and which type of game it is (TGB, TGE, TGEA, etc.). /// code version, the game name, and which type of game it is (TGB, TGE, TGEA, etc.).
/// ///
/// Version number is major * 1000 + minor * 100 + revision * 10. /// Version number is major * 1000 + minor * 100 + revision * 10.
#define TORQUE_GAME_ENGINE 3620 #define TORQUE_GAME_ENGINE 3630
/// Human readable engine version string. /// Human readable engine version string.
#define TORQUE_GAME_ENGINE_VERSION_STRING "3.6.2" #define TORQUE_GAME_ENGINE_VERSION_STRING "3.6.3"
/// Gets the engine version number. The version number is specified as a global in version.cc /// Gets the engine version number. The version number is specified as a global in version.cc
U32 getVersionNumber(); U32 getVersionNumber();
......
...@@ -1599,8 +1599,7 @@ void SimObject::unlinkNamespaces() ...@@ -1599,8 +1599,7 @@ void SimObject::unlinkNamespaces()
// Handle object name. // Handle object name.
StringTableEntry objectName = getName(); if (mNameSpace && mNameSpace->mClassRep == NULL)
if( objectName && objectName[ 0 ] )
mNameSpace->decRefCountToParent(); mNameSpace->decRefCountToParent();
mNameSpace = NULL; mNameSpace = NULL;
......
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#include "collision/concretePolyList.h" #include "collision/concretePolyList.h"