Merge branch 'master' into console-func-refactor

Conflicts:
	Engine/source/app/net/net.cpp
	Engine/source/console/astNodes.cpp
	Engine/source/console/compiledEval.cpp
	Engine/source/console/console.h
	Engine/source/console/consoleInternal.h
	Engine/source/console/engineAPI.h
This commit is contained in:
Daniel Buckmaster 2014-10-14 14:40:17 +11:00
commit b507dc9555
6487 changed files with 315149 additions and 609761 deletions

View file

@ -63,7 +63,7 @@ AIClient::AIClient() {
mMoveTolerance = 0.25f;
// Clear the triggers
for( int i = 0; i < MaxTriggerKeys; i++ )
for( S32 i = 0; i < MaxTriggerKeys; i++ )
mTriggers[i] = false;
mAimToDestination = true;
@ -355,7 +355,7 @@ U32 AIClient::getMoveList( Move **movePtr,U32 *numMoves ) {
Point3F targetLoc = mMoveDestination; // Change this
if( mPlayer ) {
if( !mPlayer->getContainer()->castRay( mLocation, targetLoc, InteriorObjectType |
if( !mPlayer->getContainer()->castRay( mLocation, targetLoc,
StaticShapeObjectType | StaticObjectType |
TerrainObjectType, &dummy ) ) {
if( !mTargetInLOS )
@ -369,7 +369,7 @@ U32 AIClient::getMoveList( Move **movePtr,U32 *numMoves ) {
}
// Copy over the trigger status
for( int i = 0; i < MaxTriggerKeys; i++ ) {
for( S32 i = 0; i < MaxTriggerKeys; i++ ) {
mMove.trigger[i] = mTriggers[i];
mTriggers[i] = false;
}
@ -457,8 +457,9 @@ ConsoleMethod( AIClient, getAimLocation, const char *, 2, 2, "ai.getAimLocation(
AIClient *ai = static_cast<AIClient *>( object );
Point3F aimPoint = ai->getAimLocation();
char *returnBuffer = Con::getReturnBuffer( 256 );
dSprintf( returnBuffer, 256, "%f %f %f", aimPoint.x, aimPoint.y, aimPoint.z );
static const U32 bufSize = 256;
char *returnBuffer = Con::getReturnBuffer( bufSize );
dSprintf( returnBuffer, bufSize, "%f %f %f", aimPoint.x, aimPoint.y, aimPoint.z );
return returnBuffer;
}
@ -470,8 +471,9 @@ ConsoleMethod( AIClient, getMoveDestination, const char *, 2, 2, "ai.getMoveDest
AIClient *ai = static_cast<AIClient *>( object );
Point3F movePoint = ai->getMoveDestination();
char *returnBuffer = Con::getReturnBuffer( 256 );
dSprintf( returnBuffer, 256, "%f %f %f", movePoint.x, movePoint.y, movePoint.z );
static const U32 bufSize = 256;
char *returnBuffer = Con::getReturnBuffer( bufSize );
dSprintf( returnBuffer, bufSize, "%f %f %f", movePoint.x, movePoint.y, movePoint.z );
return returnBuffer;
}
@ -522,8 +524,9 @@ ConsoleMethod( AIClient, getLocation, const char *, 2, 2, "ai.getLocation();" )
AIClient *ai = static_cast<AIClient *>( object );
Point3F locPoint = ai->getLocation();
char *returnBuffer = Con::getReturnBuffer( 256 );
dSprintf( returnBuffer, 256, "%f %f %f", locPoint.x, locPoint.y, locPoint.z );
static const U32 bufSize = 256;
char *returnBuffer = Con::getReturnBuffer( bufSize );
dSprintf( returnBuffer, bufSize, "%f %f %f", locPoint.x, locPoint.y, locPoint.z );
return returnBuffer;
}

View file

@ -28,6 +28,8 @@
#include "T3D/gameBase/moveManager.h"
#include "console/engineAPI.h"
static U32 sAIPlayerLoSMask = TerrainObjectType | StaticShapeObjectType | StaticObjectType;
IMPLEMENT_CO_NETOBJECT_V1(AIPlayer);
ConsoleDocClass( AIPlayer,
@ -417,33 +419,26 @@ bool AIPlayer::getAIMove(Move *movePtr)
// Test for target location in sight if it's an object. The LOS is
// run from the eye position to the center of the object's bounding,
// which is not very accurate.
if (mAimObject) {
MatrixF eyeMat;
getEyeTransform(&eyeMat);
eyeMat.getColumn(3,&location);
Point3F targetLoc = mAimObject->getBoxCenter();
// This ray ignores non-static shapes. Cast Ray returns true
// if it hit something.
RayInfo dummy;
if (getContainer()->castRay( location, targetLoc,
InteriorObjectType | StaticShapeObjectType | StaticObjectType |
TerrainObjectType, &dummy)) {
if (mTargetInLOS) {
throwCallback( "onTargetExitLOS" );
mTargetInLOS = false;
}
}
else
if (!mTargetInLOS) {
throwCallback( "onTargetEnterLOS" );
if (mAimObject)
{
if (checkInLos(mAimObject.getPointer()))
{
if (!mTargetInLOS)
{
throwCallback("onTargetEnterLOS");
mTargetInLOS = true;
}
}
else if (mTargetInLOS)
{
throwCallback("onTargetExitLOS");
mTargetInLOS = false;
}
}
// Replicate the trigger state into the move so that
// triggers can be controlled from scripts.
for( int i = 0; i < MaxTriggerKeys; i++ )
for( S32 i = 0; i < MaxTriggerKeys; i++ )
movePtr->trigger[i] = getImageTriggerState(i);
mLastLocation = location;
@ -610,3 +605,112 @@ DefineEngineMethod( AIPlayer, getAimObject, S32, (),,
GameBase* obj = object->getAimObject();
return obj? obj->getId(): -1;
}
bool AIPlayer::checkInLos(GameBase* target, bool _useMuzzle, bool _checkEnabled)
{
if (!isServerObject()) return false;
if (!target)
{
target = mAimObject.getPointer();
if (!target)
return false;
}
if (_checkEnabled)
{
if (target->getTypeMask() & ShapeBaseObjectType)
{
ShapeBase *shapeBaseCheck = static_cast<ShapeBase *>(target);
if (shapeBaseCheck)
if (shapeBaseCheck->getDamageState() != Enabled) return false;
}
else
return false;
}
RayInfo ri;
disableCollision();
S32 mountCount = target->getMountedObjectCount();
for (S32 i = 0; i < mountCount; i++)
{
target->getMountedObject(i)->disableCollision();
}
Point3F checkPoint ;
if (_useMuzzle)
getMuzzlePointAI(0, &checkPoint );
else
{
MatrixF eyeMat;
getEyeTransform(&eyeMat);
eyeMat.getColumn(3, &checkPoint );
}
bool hit = !gServerContainer.castRay(checkPoint, target->getBoxCenter(), sAIPlayerLoSMask, &ri);
enableCollision();
for (S32 i = 0; i < mountCount; i++)
{
target->getMountedObject(i)->enableCollision();
}
return hit;
}
DefineEngineMethod(AIPlayer, checkInLos, bool, (ShapeBase* obj, bool useMuzzle, bool checkEnabled),(NULL, false, false),
"@brief Check whether an object is in line of sight.\n"
"@obj Object to check. (If blank, it will check the current target).\n"
"@useMuzzle Use muzzle position. Otherwise use eye position. (defaults to false).\n"
"@checkEnabled check whether the object can take damage and if so is still alive.(Defaults to false)\n")
{
return object->checkInLos(obj, useMuzzle, checkEnabled);
}
bool AIPlayer::checkInFoV(GameBase* target, F32 camFov, bool _checkEnabled)
{
if (!isServerObject()) return false;
if (!target)
{
target = mAimObject.getPointer();
if (!target)
return false;
}
if (_checkEnabled)
{
if (target->getTypeMask() & ShapeBaseObjectType)
{
ShapeBase *shapeBaseCheck = static_cast<ShapeBase *>(target);
if (shapeBaseCheck)
if (shapeBaseCheck->getDamageState() != Enabled) return false;
}
else
return false;
}
MatrixF cam = getTransform();
Point3F camPos;
VectorF camDir;
cam.getColumn(3, &camPos);
cam.getColumn(1, &camDir);
camFov = mDegToRad(camFov) / 2;
Point3F shapePos = target->getBoxCenter();
VectorF shapeDir = shapePos - camPos;
// Test to see if it's within our viewcone, this test doesn't
// actually match the viewport very well, should consider
// projection and box test.
shapeDir.normalize();
F32 dot = mDot(shapeDir, camDir);
return (dot > camFov);
}
DefineEngineMethod(AIPlayer, checkInFoV, bool, (ShapeBase* obj, F32 fov, bool checkEnabled), (NULL, 45.0f, false),
"@brief Check whether an object is within a specified veiw cone.\n"
"@obj Object to check. (If blank, it will check the current target).\n"
"@fov view angle in degrees.(Defaults to 45)\n"
"@checkEnabled check whether the object can take damage and if so is still alive.(Defaults to false)\n")
{
return object->checkInFoV(obj, fov, checkEnabled);
}

View file

@ -80,6 +80,8 @@ public:
void setAimLocation( const Point3F &location );
Point3F getAimLocation() const { return mAimLocation; }
void clearAim();
bool checkInLos(GameBase* target = NULL, bool _useMuzzle = false, bool _checkEnabled = false);
bool checkInFoV(GameBase* target = NULL, F32 camFov = 45.0f, bool _checkEnabled = false);
// Movement sets/gets
void setMoveSpeed( const F32 speed );

View file

@ -35,6 +35,12 @@
#include "math/mathUtils.h"
#include "math/mTransform.h"
#ifdef TORQUE_EXTENDED_MOVE
#include "T3D/gameBase/extended/extendedMove.h"
#endif
S32 Camera::smExtendedMovePosRotIndex = 0; // The ExtendedMove position/rotation index used for camera movements
#define MaxPitch 1.5706f
#define CameraRadius 0.05f;
@ -254,6 +260,7 @@ Camera::Camera()
{
mNetFlags.clear(Ghostable);
mTypeMask |= CameraObjectType;
mDataBlock = 0;
mDelta.pos = Point3F(0.0f, 0.0f, 100.0f);
mDelta.rot = Point3F(0.0f, 0.0f, 0.0f);
mDelta.posVec = mDelta.rotVec = VectorF(0.0f, 0.0f, 0.0f);
@ -270,6 +277,9 @@ Camera::Camera()
mObservingClientObject = false;
mMode = FlyMode;
mLastAbsoluteYaw = 0.0f;
mLastAbsolutePitch = 0.0f;
// For NewtonFlyMode
mNewtonRotation = false;
mAngularVelocity.set(0.0f, 0.0f, 0.0f);
@ -301,7 +311,7 @@ Camera::~Camera()
bool Camera::onAdd()
{
if(!Parent::onAdd())
if(!Parent::onAdd() || !mDataBlock)
return false;
mObjBox.maxExtents = mObjScale;
@ -310,6 +320,31 @@ bool Camera::onAdd()
resetWorldBox();
addToScene();
scriptOnAdd();
return true;
}
//----------------------------------------------------------------------------
void Camera::onRemove()
{
scriptOnRemove();
removeFromScene();
Parent::onRemove();
}
//----------------------------------------------------------------------------
bool Camera::onNewDataBlock( GameBaseData *dptr, bool reload )
{
mDataBlock = dynamic_cast<CameraData*>(dptr);
if ( !mDataBlock || !Parent::onNewDataBlock( dptr, reload ) )
return false;
scriptOnNewDataBlock();
return true;
}
@ -329,14 +364,6 @@ void Camera::onEditorDisable()
//----------------------------------------------------------------------------
void Camera::onRemove()
{
removeFromScene();
Parent::onRemove();
}
//----------------------------------------------------------------------------
// check if the object needs to be observed through its own camera...
void Camera::getCameraTransform(F32* pos, MatrixF* mat)
{
@ -460,79 +487,154 @@ void Camera::processTick(const Move* move)
VectorF rotVec(0, 0, 0);
// process input/determine rotation vector
if(virtualMode != StationaryMode &&
virtualMode != TrackObjectMode &&
(!mLocked || virtualMode != OrbitObjectMode && virtualMode != OrbitPointMode))
bool doStandardMove = true;
#ifdef TORQUE_EXTENDED_MOVE
GameConnection* con = getControllingClient();
// Work with an absolute rotation from the ExtendedMove class?
if(con && con->getControlSchemeAbsoluteRotation())
{
if(!strafeMode)
doStandardMove = false;
const ExtendedMove* emove = dynamic_cast<const ExtendedMove*>(move);
U32 emoveIndex = smExtendedMovePosRotIndex;
if(emoveIndex >= ExtendedMove::MaxPositionsRotations)
emoveIndex = 0;
if(emove->EulerBasedRotation[emoveIndex])
{
rotVec.x = move->pitch;
rotVec.z = move->yaw;
if(virtualMode != StationaryMode &&
virtualMode != TrackObjectMode &&
(!mLocked || virtualMode != OrbitObjectMode && virtualMode != OrbitPointMode))
{
// Pitch
mRot.x += (emove->rotX[emoveIndex] - mLastAbsolutePitch);
// Do we also include the relative pitch value?
if(con->getControlSchemeAddPitchToAbsRot() && !strafeMode)
{
F32 x = move->pitch;
if (x > M_PI_F)
x -= M_2PI_F;
mRot.x += x;
}
// Constrain the range of mRot.x
while (mRot.x < -M_PI_F)
mRot.x += M_2PI_F;
while (mRot.x > M_PI_F)
mRot.x -= M_2PI_F;
// Yaw
mRot.z += (emove->rotZ[emoveIndex] - mLastAbsoluteYaw);
// Do we also include the relative yaw value?
if(con->getControlSchemeAddYawToAbsRot() && !strafeMode)
{
F32 z = move->yaw;
if (z > M_PI_F)
z -= M_2PI_F;
mRot.z += z;
}
// Constrain the range of mRot.z
while (mRot.z < -M_PI_F)
mRot.z += M_2PI_F;
while (mRot.z > M_PI_F)
mRot.z -= M_2PI_F;
mLastAbsoluteYaw = emove->rotZ[emoveIndex];
mLastAbsolutePitch = emove->rotX[emoveIndex];
// Bank
mRot.y = emove->rotY[emoveIndex];
// Constrain the range of mRot.y
while (mRot.y > M_PI_F)
mRot.y -= M_2PI_F;
}
}
}
else if(virtualMode == TrackObjectMode && bool(mOrbitObject))
#endif
if(doStandardMove)
{
// orient the camera to face the object
Point3F objPos;
// If this is a shapebase, use its render eye transform
// to avoid jittering.
ShapeBase *shape = dynamic_cast<ShapeBase*>((GameBase*)mOrbitObject);
if( shape != NULL )
// process input/determine rotation vector
if(virtualMode != StationaryMode &&
virtualMode != TrackObjectMode &&
(!mLocked || virtualMode != OrbitObjectMode && virtualMode != OrbitPointMode))
{
MatrixF ret;
shape->getRenderEyeTransform( &ret );
objPos = ret.getPosition();
if(!strafeMode)
{
rotVec.x = move->pitch;
rotVec.z = move->yaw;
}
}
else if(virtualMode == TrackObjectMode && bool(mOrbitObject))
{
// orient the camera to face the object
Point3F objPos;
// If this is a shapebase, use its render eye transform
// to avoid jittering.
ShapeBase *shape = dynamic_cast<ShapeBase*>((GameBase*)mOrbitObject);
if( shape != NULL )
{
MatrixF ret;
shape->getRenderEyeTransform( &ret );
objPos = ret.getPosition();
}
else
{
mOrbitObject->getWorldBox().getCenter(&objPos);
}
mObjToWorld.getColumn(3,&pos);
vec = objPos - pos;
vec.normalizeSafe();
F32 pitch, yaw;
MathUtils::getAnglesFromVector(vec, yaw, pitch);
rotVec.x = -pitch - mRot.x;
rotVec.z = yaw - mRot.z;
if(rotVec.z > M_PI_F)
rotVec.z -= M_2PI_F;
else if(rotVec.z < -M_PI_F)
rotVec.z += M_2PI_F;
}
// apply rotation vector according to physics rules
if(mNewtonRotation)
{
const F32 force = mAngularForce;
const F32 drag = mAngularDrag;
VectorF acc(0.0f, 0.0f, 0.0f);
rotVec.x *= 2.0f; // Assume that our -2PI to 2PI range was clamped to -PI to PI in script
rotVec.z *= 2.0f; // Assume that our -2PI to 2PI range was clamped to -PI to PI in script
F32 rotVecL = rotVec.len();
if(rotVecL > 0)
{
acc = (rotVec * force / mMass) * TickSec;
}
// Accelerate
mAngularVelocity += acc;
// Drag
mAngularVelocity -= mAngularVelocity * drag * TickSec;
// Rotate
mRot += mAngularVelocity * TickSec;
clampPitchAngle(mRot.x);
}
else
{
mOrbitObject->getWorldBox().getCenter(&objPos);
mRot.x += rotVec.x;
mRot.z += rotVec.z;
clampPitchAngle(mRot.x);
}
mObjToWorld.getColumn(3,&pos);
vec = objPos - pos;
vec.normalizeSafe();
F32 pitch, yaw;
MathUtils::getAnglesFromVector(vec, yaw, pitch);
rotVec.x = -pitch - mRot.x;
rotVec.z = yaw - mRot.z;
if(rotVec.z > M_PI_F)
rotVec.z -= M_2PI_F;
else if(rotVec.z < -M_PI_F)
rotVec.z += M_2PI_F;
}
// apply rotation vector according to physics rules
if(mNewtonRotation)
{
const F32 force = mAngularForce;
const F32 drag = mAngularDrag;
VectorF acc(0.0f, 0.0f, 0.0f);
rotVec.x *= 2.0f; // Assume that our -2PI to 2PI range was clamped to -PI to PI in script
rotVec.z *= 2.0f; // Assume that our -2PI to 2PI range was clamped to -PI to PI in script
F32 rotVecL = rotVec.len();
if(rotVecL > 0)
{
acc = (rotVec * force / mMass) * TickSec;
}
// Accelerate
mAngularVelocity += acc;
// Drag
mAngularVelocity -= mAngularVelocity * drag * TickSec;
// Rotate
mRot += mAngularVelocity * TickSec;
clampPitchAngle(mRot.x);
}
else
{
mRot.x += rotVec.x;
mRot.z += rotVec.z;
clampPitchAngle(mRot.x);
}
// Update position
@ -667,6 +769,13 @@ void Camera::processTick(const Move* move)
mDelta.rot = mRot;
mDelta.posVec = mDelta.posVec - mDelta.pos;
mDelta.rotVec = mDelta.rotVec - mDelta.rot;
for(U32 i=0; i<3; ++i)
{
if (mDelta.rotVec[i] > M_PI_F)
mDelta.rotVec[i] -= M_2PI_F;
else if (mDelta.rotVec[i] < -M_PI_F)
mDelta.rotVec[i] += M_2PI_F;
}
}
if(mustValidateEyePoint)
@ -793,7 +902,21 @@ void Camera::_setPosition(const Point3F& pos, const Point3F& rot)
zRot.set(EulerF(0.0f, 0.0f, rot.z));
MatrixF temp;
temp.mul(zRot, xRot);
if(mDataBlock && mDataBlock->cameraCanBank)
{
// Take rot.y into account to bank the camera
MatrixF imat;
imat.mul(zRot, xRot);
MatrixF ymat;
ymat.set(EulerF(0.0f, rot.y, 0.0f));
temp.mul(imat, ymat);
}
else
{
temp.mul(zRot, xRot);
}
temp.setColumn(3, pos);
Parent::setTransform(temp);
mRot = rot;
@ -808,7 +931,21 @@ void Camera::setRotation(const Point3F& rot)
zRot.set(EulerF(0.0f, 0.0f, rot.z));
MatrixF temp;
temp.mul(zRot, xRot);
if(mDataBlock && mDataBlock->cameraCanBank)
{
// Take rot.y into account to bank the camera
MatrixF imat;
imat.mul(zRot, xRot);
MatrixF ymat;
ymat.set(EulerF(0.0f, rot.y, 0.0f));
temp.mul(imat, ymat);
}
else
{
temp.mul(zRot, xRot);
}
temp.setColumn(3, getPosition());
Parent::setTransform(temp);
mRot = rot;
@ -821,8 +958,25 @@ void Camera::_setRenderPosition(const Point3F& pos,const Point3F& rot)
MatrixF xRot, zRot;
xRot.set(EulerF(rot.x, 0, 0));
zRot.set(EulerF(0, 0, rot.z));
MatrixF temp;
temp.mul(zRot, xRot);
// mDataBlock may not be defined yet as this method is called during
// SceneObject::onAdd().
if(mDataBlock && mDataBlock->cameraCanBank)
{
// Take rot.y into account to bank the camera
MatrixF imat;
imat.mul(zRot, xRot);
MatrixF ymat;
ymat.set(EulerF(0.0f, rot.y, 0.0f));
temp.mul(imat, ymat);
}
else
{
temp.mul(zRot, xRot);
}
temp.setColumn(3, pos);
Parent::setRenderTransform(temp);
}
@ -839,6 +993,11 @@ void Camera::writePacketData(GameConnection *connection, BitStream *bstream)
bstream->setCompressionPoint(pos);
mathWrite(*bstream, pos);
bstream->write(mRot.x);
if(mDataBlock && bstream->writeFlag(mDataBlock->cameraCanBank))
{
// Include mRot.y to allow for camera banking
bstream->write(mRot.y);
}
bstream->write(mRot.z);
U32 writeMode = mMode;
@ -912,6 +1071,11 @@ void Camera::readPacketData(GameConnection *connection, BitStream *bstream)
mathRead(*bstream, &pos);
bstream->setCompressionPoint(pos);
bstream->read(&rot.x);
if(bstream->readFlag())
{
// Include rot.y to allow for camera banking
bstream->read(&rot.y);
}
bstream->read(&rot.z);
GameBase* obj = 0;
@ -1184,6 +1348,11 @@ void Camera::consoleInit()
"- Fly Mode\n"
"- Overhead Mode\n"
"@ingroup BaseCamera\n");
// ExtendedMove support
Con::addVariable("$camera::extendedMovePosRotIndex", TypeS32, &smExtendedMovePosRotIndex,
"@brief The ExtendedMove position/rotation index used for camera movements.\n\n"
"@ingroup BaseCamera\n");
}
//-----------------------------------------------------------------------------
@ -1363,7 +1532,6 @@ void Camera::_validateEyePoint(F32 pos, MatrixF *mat)
disableCollision();
RayInfo collision;
U32 mask = TerrainObjectType |
InteriorObjectType |
WaterObjectType |
StaticShapeObjectType |
PlayerObjectType |
@ -1378,7 +1546,7 @@ void Camera::_validateEyePoint(F32 pos, MatrixF *mat)
float dot = mDot(dir, collision.normal);
if (dot > 0.01f)
{
float colDist = mDot(startPos - collision.point, dir) - (1 / dot) * CameraRadius;
F32 colDist = mDot(startPos - collision.point, dir) - (1 / dot) * CameraRadius;
if (colDist > pos)
colDist = pos;
if (colDist < 0.0f)

View file

@ -73,6 +73,9 @@ class Camera: public ShapeBase
CameraLastMode = EditOrbitMode
};
/// The ExtendedMove position/rotation index used for camera movements
static S32 smExtendedMovePosRotIndex;
protected:
enum MaskBits
@ -92,6 +95,8 @@ class Camera: public ShapeBase
VectorF rotVec;
};
CameraData* mDataBlock;
Point3F mRot;
StateDelta mDelta;
@ -106,6 +111,9 @@ class Camera: public ShapeBase
Point3F mPosition;
bool mObservingClientObject;
F32 mLastAbsoluteYaw; ///< Stores that last absolute yaw value as passed in by ExtendedMove
F32 mLastAbsolutePitch; ///< Stores that last absolute pitch value as passed in by ExtendedMove
/// @name NewtonFlyMode
/// @{
@ -223,6 +231,7 @@ class Camera: public ShapeBase
virtual bool onAdd();
virtual void onRemove();
virtual bool onNewDataBlock( GameBaseData *dptr, bool reload );
virtual void processTick( const Move* move );
virtual void interpolateTick( F32 delta);
virtual void getCameraTransform( F32* pos,MatrixF* mat );

View file

@ -190,10 +190,11 @@ void CameraSpline::renderTimeMap()
// Build vertex buffer
GFXVertexBufferHandle<GFXVertexPC> vb;
vb.set(GFX, mTimeMap.size(), GFXBufferTypeVolatile);
vb.lock();
void *ptr = vb.lock();
if(!ptr) return;
MRandomLCG random(1376312589 * (U32)this);
int index = 0;
S32 index = 0;
for(Vector<TimeMap>::iterator itr=mTimeMap.begin(); itr != mTimeMap.end(); itr++)
{
Knot a;

View file

@ -653,6 +653,29 @@ bool ConvexShape::buildPolyList( PolyListContext context, AbstractPolyList *plis
const Vector< ConvexShape::Face > faceList = mGeometry.faces;
if(context == PLC_Navigation)
{
for(S32 i = 0; i < faceList.size(); i++)
{
const ConvexShape::Face &face = faceList[i];
S32 s = face.triangles.size();
for(S32 j = 0; j < s; j++)
{
plist->begin(0, s*i + j);
plist->plane(PlaneF(face.centroid, face.normal));
plist->vertex(base + face.points[face.triangles[j].p0]);
plist->vertex(base + face.points[face.triangles[j].p1]);
plist->vertex(base + face.points[face.triangles[j].p2]);
plist->end();
}
}
return true;
}
for ( S32 i = 0; i < faceList.size(); i++ )
{
const ConvexShape::Face &face = faceList[i];
@ -924,68 +947,6 @@ void ConvexShape::exportToCollada()
Con::errorf( "ConvexShape::exportToCollada() - has no surfaces to export!" );
return;
}
/*
// Get an optimized version of our mesh
OptimizedPolyList polyList;
if (bakeTransform)
{
MatrixF mat = getTransform();
Point3F scale = getScale();
pInterior->buildExportPolyList(interiorMesh, &mat, &scale);
}
else
pInterior->buildExportPolyList(interiorMesh);
// Get our export path
Torque::Path colladaFile = mInteriorRes.getPath();
// Make sure to set our Collada extension
colladaFile.setExtension("dae");
// Use the InteriorInstance name if possible
String meshName = getName();
// Otherwise use the DIF's file name
if (meshName.isEmpty())
meshName = colladaFile.getFileName();
// If we are baking the transform then append
// a CRC version of the transform to the mesh/file name
if (bakeTransform)
{
F32 trans[19];
const MatrixF& mat = getTransform();
const Point3F& scale = getScale();
// Copy in the transform
for (U32 i = 0; i < 4; i++)
{
for (U32 j = 0; j < 4; j++)
{
trans[i * 4 + j] = mat(i, j);
}
}
// Copy in the scale
trans[16] = scale.x;
trans[17] = scale.y;
trans[18] = scale.z;
U32 crc = CRC::calculateCRC(trans, sizeof(F32) * 19);
meshName += String::ToString("_%x", crc);
}
// Set the file name as the meshName
colladaFile.setFileName(meshName);
// Use a ColladaUtils function to do the actual export to a Collada file
ColladaUtils::exportToCollada(colladaFile, interiorMesh, meshName);
}
*/
}
void ConvexShape::resizePlanes( const Point3F &size )

View file

@ -41,8 +41,7 @@
#include "lighting/lightQuery.h"
const U32 csmStaticCollisionMask = TerrainObjectType |
InteriorObjectType;
const U32 csmStaticCollisionMask = TerrainObjectType | StaticShapeObjectType | StaticObjectType;
const U32 csmDynamicCollisionMask = StaticShapeObjectType;
@ -123,7 +122,7 @@ bool DebrisData::onAdd()
if(!Parent::onAdd())
return false;
for( int i=0; i<DDC_NUM_EMITTERS; i++ )
for( S32 i=0; i<DDC_NUM_EMITTERS; i++ )
{
if( !emitterList[i] && emitterIDList[i] != 0 )
{
@ -304,7 +303,7 @@ void DebrisData::packData(BitStream* stream)
stream->writeString( textureName );
stream->writeString( shapeName );
for( int i=0; i<DDC_NUM_EMITTERS; i++ )
for( S32 i=0; i<DDC_NUM_EMITTERS; i++ )
{
if( stream->writeFlag( emitterList[i] != NULL ) )
{
@ -347,7 +346,7 @@ void DebrisData::unpackData(BitStream* stream)
textureName = stream->readSTString();
shapeName = stream->readSTString();
for( int i=0; i<DDC_NUM_EMITTERS; i++ )
for( S32 i=0; i<DDC_NUM_EMITTERS; i++ )
{
if( stream->readFlag() )
{
@ -512,8 +511,14 @@ bool Debris::onAdd()
return false;
}
if( !mDataBlock )
{
Con::errorf("Debris::onAdd - Fail - No datablock");
return false;
}
// create emitters
for( int i=0; i<DebrisData::DDC_NUM_EMITTERS; i++ )
for( S32 i=0; i<DebrisData::DDC_NUM_EMITTERS; i++ )
{
if( mDataBlock->emitterList[i] != NULL )
{
@ -632,7 +637,7 @@ bool Debris::onAdd()
void Debris::onRemove()
{
for( int i=0; i<DebrisData::DDC_NUM_EMITTERS; i++ )
for( S32 i=0; i<DebrisData::DDC_NUM_EMITTERS; i++ )
{
if( mEmitterList[i] )
{
@ -654,8 +659,11 @@ void Debris::onRemove()
}
}
getSceneManager()->removeObjectFromScene(this);
getContainer()->removeObject(this);
if( getSceneManager() )
getSceneManager()->removeObjectFromScene(this);
if( getContainer() )
getContainer()->removeObject(this);
Parent::onRemove();
}
@ -849,7 +857,7 @@ void Debris::updateEmitters( Point3F &pos, Point3F &vel, U32 ms )
Point3F lastPos = mLastPos;
for( int i=0; i<DebrisData::DDC_NUM_EMITTERS; i++ )
for( S32 i=0; i<DebrisData::DDC_NUM_EMITTERS; i++ )
{
if( mEmitterList[i] )
{

View file

@ -117,7 +117,7 @@ ConsoleDocClass( DecalManager,
namespace {
int QSORT_CALLBACK cmpDecalInstance(const void* p1, const void* p2)
S32 QSORT_CALLBACK cmpDecalInstance(const void* p1, const void* p2)
{
const DecalInstance** pd1 = (const DecalInstance**)p1;
const DecalInstance** pd2 = (const DecalInstance**)p2;
@ -125,7 +125,7 @@ int QSORT_CALLBACK cmpDecalInstance(const void* p1, const void* p2)
return int(((char *)(*pd1)->mDataBlock) - ((char *)(*pd2)->mDataBlock));
}
int QSORT_CALLBACK cmpPointsXY( const void *p1, const void *p2 )
S32 QSORT_CALLBACK cmpPointsXY( const void *p1, const void *p2 )
{
const Point3F *pnt1 = (const Point3F*)p1;
const Point3F *pnt2 = (const Point3F*)p2;
@ -142,7 +142,7 @@ int QSORT_CALLBACK cmpPointsXY( const void *p1, const void *p2 )
return 0;
}
int QSORT_CALLBACK cmpQuadPointTheta( const void *p1, const void *p2 )
S32 QSORT_CALLBACK cmpQuadPointTheta( const void *p1, const void *p2 )
{
const Point4F *pnt1 = (const Point4F*)p1;
const Point4F *pnt2 = (const Point4F*)p2;
@ -157,7 +157,7 @@ int QSORT_CALLBACK cmpQuadPointTheta( const void *p1, const void *p2 )
static Point3F gSortPoint;
int QSORT_CALLBACK cmpDecalDistance( const void *p1, const void *p2 )
S32 QSORT_CALLBACK cmpDecalDistance( const void *p1, const void *p2 )
{
const DecalInstance** pd1 = (const DecalInstance**)p1;
const DecalInstance** pd2 = (const DecalInstance**)p2;
@ -168,7 +168,7 @@ int QSORT_CALLBACK cmpDecalDistance( const void *p1, const void *p2 )
return mSign( dist1 - dist2 );
}
int QSORT_CALLBACK cmpDecalRenderOrder( const void *p1, const void *p2 )
S32 QSORT_CALLBACK cmpDecalRenderOrder( const void *p1, const void *p2 )
{
const DecalInstance** pd1 = (const DecalInstance**)p1;
const DecalInstance** pd2 = (const DecalInstance**)p2;
@ -179,14 +179,14 @@ int QSORT_CALLBACK cmpDecalRenderOrder( const void *p1, const void *p2 )
return 1;
else
{
int priority = (*pd1)->getRenderPriority() - (*pd2)->getRenderPriority();
S32 priority = (*pd1)->getRenderPriority() - (*pd2)->getRenderPriority();
if ( priority != 0 )
return priority;
if ( (*pd2)->mFlags & SaveDecal )
{
int id = ( (*pd1)->mDataBlock->getMaterial()->getId() - (*pd2)->mDataBlock->getMaterial()->getId() );
S32 id = ( (*pd1)->mDataBlock->getMaterial()->getId() - (*pd2)->mDataBlock->getMaterial()->getId() );
if ( id != 0 )
return id;
@ -1004,7 +1004,7 @@ void DecalManager::prepRenderImage( SceneRenderState* state )
PROFILE_START( DecalManager_RenderDecals_SphereTreeCull );
const Frustum& rootFrustum = state->getFrustum();
const Frustum& rootFrustum = state->getCameraFrustum();
// Populate vector of decal instances to be rendered with all
// decals from visible decal spheres.
@ -1448,7 +1448,7 @@ void DecalManager::_renderDecalSpheres( ObjectRenderInst* ri, SceneRenderState*
DecalSphere *decalSphere = grid[i];
const SphereF &worldSphere = decalSphere->mWorldSphere;
if( state->getFrustum().isCulled( worldSphere ) )
if( state->getCullingFrustum().isCulled( worldSphere ) )
continue;
drawUtil->drawSphere( desc, worldSphere.radius, worldSphere.center, sphereColor );

View file

@ -108,6 +108,9 @@ bool RenderMeshExample::onAdd()
// Add this object to the scene
addToScene();
// Refresh this object's material (if any)
updateMaterial();
return true;
}
@ -284,6 +287,13 @@ void RenderMeshExample::prepRenderImage( SceneRenderState *state )
// Set our RenderInst as a standard mesh render
ri->type = RenderPassManager::RIT_Mesh;
//If our material has transparency set on this will redirect it to proper render bin
if ( matInst->getMaterial()->isTranslucent() )
{
ri->type = RenderPassManager::RIT_Translucent;
ri->translucentSort = true;
}
// Calculate our sorting point
if ( state )
{

View file

@ -138,7 +138,7 @@ void GuiCrossHairHud::onRender(Point2I offset, const RectI &updateRect)
// Collision info. We're going to be running LOS tests and we
// don't want to collide with the control object.
static U32 losMask = TerrainObjectType | InteriorObjectType | ShapeBaseObjectType;
static U32 losMask = TerrainObjectType | ShapeBaseObjectType;
control->disableCollision();
RayInfo info;

View file

@ -50,11 +50,17 @@ class GuiShapeNameHud : public GuiControl {
ColorF mFillColor;
ColorF mFrameColor;
ColorF mTextColor;
ColorF mLabelFillColor;
ColorF mLabelFrameColor;
F32 mVerticalOffset;
F32 mDistanceFade;
bool mShowFrame;
bool mShowFill;
bool mShowLabelFrame;
bool mShowLabelFill;
Point2I mLabelPadding;
protected:
void drawName( Point2I offset, const char *buf, F32 opacity);
@ -92,6 +98,10 @@ ConsoleDocClass( GuiShapeNameHud,
" textColor = \"1.0 1.0 1.0 1.0\"; // Solid white text Color\n"
" showFill = \"true\";\n"
" showFrame = \"true\";\n"
" labelFillColor = \"0.0 1.0 0.0 1.0\"; // Fills with a solid green color\n"
" labelFrameColor = \"1.0 1.0 1.0 1.0\"; // Solid white frame color\n"
" showLabelFill = \"true\";\n"
" showLabelFrame = \"true\";\n"
" verticalOffset = \"0.15\";\n"
" distanceFade = \"15.0\";\n"
"};\n"
@ -111,6 +121,7 @@ GuiShapeNameHud::GuiShapeNameHud()
mShowFrame = mShowFill = true;
mVerticalOffset = 0.5f;
mDistanceFade = 0.1f;
mLabelPadding.set(0, 0);
}
void GuiShapeNameHud::initPersistFields()
@ -119,11 +130,16 @@ void GuiShapeNameHud::initPersistFields()
addField( "fillColor", TypeColorF, Offset( mFillColor, GuiShapeNameHud ), "Standard color for the background of the control." );
addField( "frameColor", TypeColorF, Offset( mFrameColor, GuiShapeNameHud ), "Color for the control's frame." );
addField( "textColor", TypeColorF, Offset( mTextColor, GuiShapeNameHud ), "Color for the text on this control." );
addField( "labelFillColor", TypeColorF, Offset( mLabelFillColor, GuiShapeNameHud ), "Color for the background of each shape name label." );
addField( "labelFrameColor", TypeColorF, Offset( mLabelFrameColor, GuiShapeNameHud ), "Color for the frames around each shape name label." );
endGroup("Colors");
addGroup("Misc");
addField( "showFill", TypeBool, Offset( mShowFill, GuiShapeNameHud ), "If true, we draw the background color of the control." );
addField( "showFrame", TypeBool, Offset( mShowFrame, GuiShapeNameHud ), "If true, we draw the frame of the control." );
addField( "showLabelFill", TypeBool, Offset( mShowLabelFill, GuiShapeNameHud ), "If true, we draw a background for each shape name label." );
addField( "showLabelFrame", TypeBool, Offset( mShowLabelFrame, GuiShapeNameHud ), "If true, we draw a frame around each shape name label." );
addField( "labelPadding", TypePoint2I, Offset( mLabelPadding, GuiShapeNameHud ), "The padding (in pixels) between the label text and the frame." );
addField( "verticalOffset", TypeF32, Offset( mVerticalOffset, GuiShapeNameHud ), "Amount to vertically offset the control in relation to the ShapeBase object in focus." );
addField( "distanceFade", TypeF32, Offset( mDistanceFade, GuiShapeNameHud ), "Visibility distance (how far the player must be from the ShapeBase object in focus) for this control to render." );
endGroup("Misc");
@ -177,7 +193,7 @@ void GuiShapeNameHud::onRender( Point2I, const RectI &updateRect)
// Collision info. We're going to be running LOS tests and we
// don't want to collide with the control object.
static U32 losMask = TerrainObjectType | InteriorObjectType | ShapeBaseObjectType;
static U32 losMask = TerrainObjectType | ShapeBaseObjectType;
control->disableCollision();
// All ghosted objects are added to the server connection group,
@ -274,14 +290,26 @@ void GuiShapeNameHud::onRender( Point2I, const RectI &updateRect)
/// @param opacity Opacity of name (a fraction).
void GuiShapeNameHud::drawName(Point2I offset, const char *name, F32 opacity)
{
F32 width = mProfile->mFont->getStrWidth((const UTF8 *)name) + mLabelPadding.x * 2;
F32 height = mProfile->mFont->getHeight() + mLabelPadding.y * 2;
Point2I extent = Point2I(width, height);
// Center the name
offset.x -= mProfile->mFont->getStrWidth((const UTF8 *)name) / 2;
offset.y -= mProfile->mFont->getHeight();
offset.x -= width / 2;
offset.y -= height / 2;
// Background fill first
if (mShowLabelFill)
GFX->getDrawUtil()->drawRectFill(RectI(offset, extent), mLabelFillColor);
// Deal with opacity and draw.
mTextColor.alpha = opacity;
GFX->getDrawUtil()->setBitmapModulation(mTextColor);
GFX->getDrawUtil()->drawText(mProfile->mFont, offset, name);
GFX->getDrawUtil()->drawText(mProfile->mFont, offset + mLabelPadding, name);
GFX->getDrawUtil()->clearBitmapModulation();
// Border last
if (mShowLabelFrame)
GFX->getDrawUtil()->drawRect(RectI(offset, extent), mLabelFrameColor);
}

View file

@ -45,6 +45,7 @@ protected:
public:
CameraFX();
virtual ~CameraFX() { }
MatrixF & getTrans(){ return mCamFXTrans; }
virtual bool isExpired(){ return mElapsedTime >= mDuration; }

View file

@ -106,18 +106,31 @@ ConsoleDocClass( Explosion,
" lightEndBrightness = 0.0;\n"
" lightNormalOffset = 2.0;\n"
"};\n\n"
"function createExplosion()\n"
"function ServerPlayExplosion(%position, %datablock)\n"
"{\n"
" // Create a new explosion - it will explode automatically\n"
" %pos = \"0 0 100\";\n"
" %obj = new Explosion()\n"
" // Play the given explosion on every client.\n"
" // The explosion will be transmitted as an event, not attached to any object.\n"
" for(%idx = 0; %idx < ClientGroup.getCount(); %idx++)\n"
" {\n"
" position = %pos;\n"
" dataBlock = GrenadeLauncherExplosion;\n"
" };\n"
" %client = ClientGroup.getObject(%idx);\n"
" commandToClient(%client, 'PlayExplosion', %position, %datablock.getId());\n"
" }\n"
"}\n\n"
"function clientCmdPlayExplosion(%position, %effectDataBlock)\n"
"{\n"
" // Play an explosion sent by the server. Make sure this function is defined\n"
" // on the client.\n"
" if (isObject(%effectDataBlock))\n"
" {\n"
" new Explosion()\n"
" {\n"
" position = %position;\n"
" dataBlock = %effectDataBlock;\n"
" };\n"
" }\n"
"}\n\n"
"// schedule an explosion\n"
"schedule(1000, 0, createExplosion);\n"
"schedule(1000, 0, ServerPlayExplosion, \"0 0 0\", GrenadeLauncherExplosion);\n"
"@endtsexample"
);
@ -151,7 +164,7 @@ DefineEngineFunction(calcExplosionCoverage, F32, (Point3F pos, S32 id, U32 covMa
SceneObject* sceneObject = NULL;
if (Sim::findObject(id, sceneObject) == false) {
Con::warnf(ConsoleLogEntry::General, "calcExplosionCoverage: couldn't find object: %s", id);
Con::warnf(ConsoleLogEntry::General, "calcExplosionCoverage: couldn't find object: %d", id);
return 1.0f;
}
if (sceneObject->isClientObject() || sceneObject->getContainer() == NULL) {
@ -736,9 +749,9 @@ bool ExplosionData::preload(bool server, String &errorStr)
if( !server )
{
String errorStr;
if( !sfxResolve( &soundProfile, errorStr ) )
Con::errorf(ConsoleLogEntry::General, "Error, unable to load sound profile for explosion datablock: %s", errorStr.c_str());
String sfxErrorStr;
if( !sfxResolve( &soundProfile, sfxErrorStr ) )
Con::errorf(ConsoleLogEntry::General, "Error, unable to load sound profile for explosion datablock: %s", sfxErrorStr.c_str());
if (!particleEmitter && particleEmitterId != 0)
if (Sim::findObject(particleEmitterId, particleEmitter) == false)
Con::errorf(ConsoleLogEntry::General, "Error, unable to load particle emitter for explosion datablock");
@ -771,6 +784,7 @@ bool ExplosionData::preload(bool server, String &errorStr)
//--------------------------------------
//
Explosion::Explosion()
: mDataBlock( NULL )
{
mTypeMask |= ExplosionObjectType | LightObjectType;
@ -831,6 +845,12 @@ bool Explosion::onAdd()
if ( !conn || !Parent::onAdd() )
return false;
if( !mDataBlock )
{
Con::errorf("Explosion::onAdd - Fail - No datablok");
return false;
}
mDelayMS = mDataBlock->delayMS + sgRandom.randI( -mDataBlock->delayVariance, mDataBlock->delayVariance );
mEndingMS = mDataBlock->lifetimeMS + sgRandom.randI( -mDataBlock->lifetimeVariance, mDataBlock->lifetimeVariance );
@ -929,7 +949,7 @@ bool Explosion::onAdd()
void Explosion::onRemove()
{
for( int i=0; i<ExplosionData::EC_NUM_EMITTERS; i++ )
for( S32 i=0; i<ExplosionData::EC_NUM_EMITTERS; i++ )
{
if( mEmitterList[i] )
{
@ -1114,7 +1134,7 @@ void Explosion::updateEmitters( F32 dt )
{
Point3F pos = getPosition();
for( int i=0; i<ExplosionData::EC_NUM_EMITTERS; i++ )
for( S32 i=0; i<ExplosionData::EC_NUM_EMITTERS; i++ )
{
if( mEmitterList[i] )
{
@ -1134,7 +1154,7 @@ void Explosion::launchDebris( Point3F &axis )
return;
bool hasDebris = false;
for( int j=0; j<ExplosionData::EC_NUM_DEBRIS_TYPES; j++ )
for( S32 j=0; j<ExplosionData::EC_NUM_DEBRIS_TYPES; j++ )
{
if( mDataBlock->debrisList[j] )
{
@ -1160,7 +1180,7 @@ void Explosion::launchDebris( Point3F &axis )
U32 numDebris = mDataBlock->debrisNum + sgRandom.randI( -mDataBlock->debrisNumVariance, mDataBlock->debrisNumVariance );
for( int i=0; i<numDebris; i++ )
for( S32 i=0; i<numDebris; i++ )
{
Point3F launchDir = MathUtils::randomDir( axis, mDataBlock->debrisThetaMin, mDataBlock->debrisThetaMax,
@ -1249,7 +1269,7 @@ bool Explosion::explode()
Point3F::Zero, U32(mDataBlock->particleDensity * mFade));
}
for( int i=0; i<ExplosionData::EC_NUM_EMITTERS; i++ )
for( S32 i=0; i<ExplosionData::EC_NUM_EMITTERS; i++ )
{
if( mDataBlock->emitterList[i] != NULL )
{

View file

@ -146,7 +146,7 @@ void fxFoliageRenderList::SetupClipPlanes( SceneRenderState* state, const F32 fa
const F32 nearPlane = state->getNearPlane();
const F32 farPlane = farClipPlane;
const Frustum& frustum = state->getFrustum();
const Frustum& frustum = state->getCullingFrustum();
// [rene, 23-Feb-11] Why isn't this preserving the ortho state of the original frustum?
@ -397,7 +397,6 @@ void fxFoliageReplicator::initPersistFields()
addGroup( "Restrictions" ); // MM: Added Group Header.
addField( "AllowOnTerrain", TypeBool, Offset( mFieldData.mAllowOnTerrain, fxFoliageReplicator ), "Foliage will be placed on terrain when set." );
addField( "AllowOnInteriors", TypeBool, Offset( mFieldData.mAllowOnInteriors, fxFoliageReplicator ), "Foliage will be placed on InteriorInstances when set." );
addField( "AllowOnStatics", TypeBool, Offset( mFieldData.mAllowStatics, fxFoliageReplicator ), "Foliage will be placed on Static shapes when set." );
addField( "AllowOnWater", TypeBool, Offset( mFieldData.mAllowOnWater, fxFoliageReplicator ), "Foliage will be placed on/under water when set." );
addField( "AllowWaterSurface", TypeBool, Offset( mFieldData.mAllowWaterSurface, fxFoliageReplicator ), "Foliage will be placed on water when set. Requires AllowOnWater." );
@ -435,7 +434,6 @@ void fxFoliageReplicator::CreateFoliage(void)
// Check that we can position somewhere!
if (!( mFieldData.mAllowOnTerrain ||
mFieldData.mAllowOnInteriors ||
mFieldData.mAllowStatics ||
mFieldData.mAllowOnWater))
{
@ -633,7 +631,6 @@ void fxFoliageReplicator::CreateFoliage(void)
// Check Illegal Placements, fail if we hit a disallowed type.
if (((CollisionType & TerrainObjectType) && !mFieldData.mAllowOnTerrain) ||
((CollisionType & InteriorObjectType) && !mFieldData.mAllowOnInteriors) ||
((CollisionType & StaticShapeObjectType ) && !mFieldData.mAllowStatics) ||
((CollisionType & WaterObjectType) && !mFieldData.mAllowOnWater) ) continue;
@ -1700,7 +1697,6 @@ U32 fxFoliageReplicator::packUpdate(NetConnection * con, U32 mask, BitStream * s
stream->write(mFieldData.mLightTime); // Foliage Light Time.
stream->writeFlag(mFieldData.mAllowOnTerrain); // Allow on Terrain.
stream->writeFlag(mFieldData.mAllowOnInteriors); // Allow on Interiors.
stream->writeFlag(mFieldData.mAllowStatics); // Allow on Statics.
stream->writeFlag(mFieldData.mAllowOnWater); // Allow on Water.
stream->writeFlag(mFieldData.mAllowWaterSurface); // Allow on Water Surface.
@ -1777,7 +1773,6 @@ void fxFoliageReplicator::unpackUpdate(NetConnection * con, BitStream * stream)
stream->read(&mFieldData.mLightTime); // Foliage Light Time.
mFieldData.mAllowOnTerrain = stream->readFlag(); // Allow on Terrain.
mFieldData.mAllowOnInteriors = stream->readFlag(); // Allow on Interiors.
mFieldData.mAllowStatics = stream->readFlag(); // Allow on Statics.
mFieldData.mAllowOnWater = stream->readFlag(); // Allow on Water.
mFieldData.mAllowWaterSurface = stream->readFlag(); // Allow on Water Surface.

View file

@ -47,12 +47,10 @@
#define AREA_ANIMATION_ARC (1.0f / 360.0f)
#define FXFOLIAGEREPLICATOR_COLLISION_MASK ( TerrainObjectType | \
InteriorObjectType | \
StaticShapeObjectType | \
WaterObjectType )
#define FXFOLIAGEREPLICATOR_NOWATER_COLLISION_MASK ( TerrainObjectType | \
InteriorObjectType | \
StaticShapeObjectType )
@ -311,7 +309,6 @@ public:
F32 mLightTime;
bool mAllowOnTerrain;
bool mAllowOnInteriors;
bool mAllowStatics;
bool mAllowOnWater;
bool mAllowWaterSurface;
@ -371,7 +368,6 @@ public:
mLightTime = 5.0f;
mAllowOnTerrain = true;
mAllowOnInteriors = true;
mAllowStatics = true;
mAllowOnWater = false;
mAllowWaterSurface = false;

View file

@ -166,7 +166,6 @@ void fxShapeReplicator::initPersistFields()
addGroup( "Restraints" ); // MM: Added Group Header.
addField( "AllowOnTerrain", TypeBool, Offset( mFieldData.mAllowOnTerrain, fxShapeReplicator ), "Shapes will be placed on terrain when set." );
addField( "AllowOnInteriors", TypeBool, Offset( mFieldData.mAllowOnInteriors, fxShapeReplicator ), "Shapes will be placed on InteriorInstances when set." );
addField( "AllowOnStatics", TypeBool, Offset( mFieldData.mAllowStatics, fxShapeReplicator ), "Shapes will be placed on Static shapes when set." );
addField( "AllowOnWater", TypeBool, Offset( mFieldData.mAllowOnWater, fxShapeReplicator ), "Shapes will be placed on/under water when set." );
addField( "AllowWaterSurface", TypeBool, Offset( mFieldData.mAllowWaterSurface, fxShapeReplicator ), "Shapes will be placed on water when set. Requires AllowOnWater." );
@ -214,7 +213,6 @@ void fxShapeReplicator::CreateShapes(void)
// Check that we can position somewhere!
if (!( mFieldData.mAllowOnTerrain ||
mFieldData.mAllowOnInteriors ||
mFieldData.mAllowStatics ||
mFieldData.mAllowOnWater))
{
@ -318,7 +316,6 @@ void fxShapeReplicator::CreateShapes(void)
// Check Illegal Placements.
if (((CollisionType & TerrainObjectType) && !mFieldData.mAllowOnTerrain) ||
((CollisionType & InteriorObjectType) && !mFieldData.mAllowOnInteriors) ||
((CollisionType & StaticShapeObjectType) && !mFieldData.mAllowStatics) ||
((CollisionType & WaterObjectType) && !mFieldData.mAllowOnWater) ) continue;
@ -696,7 +693,6 @@ U32 fxShapeReplicator::packUpdate(NetConnection * con, U32 mask, BitStream * str
mathWrite(*stream, mFieldData.mShapeRotateMax); // Shapes Rotate Max.
stream->writeSignedInt(mFieldData.mOffsetZ, 32); // Shapes Offset Z.
stream->writeFlag(mFieldData.mAllowOnTerrain); // Allow on Terrain.
stream->writeFlag(mFieldData.mAllowOnInteriors); // Allow on Interiors.
stream->writeFlag(mFieldData.mAllowStatics); // Allow on Statics.
stream->writeFlag(mFieldData.mAllowOnWater); // Allow on Water.
stream->writeFlag(mFieldData.mAllowWaterSurface); // Allow on Water Surface.
@ -742,7 +738,6 @@ void fxShapeReplicator::unpackUpdate(NetConnection * con, BitStream * stream)
mathRead(*stream, &mFieldData.mShapeRotateMax); // Shapes Rotate Max.
mFieldData.mOffsetZ = stream->readSignedInt(32); // Shapes Offset Z.
mFieldData.mAllowOnTerrain = stream->readFlag(); // Allow on Terrain.
mFieldData.mAllowOnInteriors = stream->readFlag(); // Allow on Interiors.
mFieldData.mAllowStatics = stream->readFlag(); // Allow on Statics.
mFieldData.mAllowOnWater = stream->readFlag(); // Allow on Water.
mFieldData.mAllowWaterSurface = stream->readFlag(); // Allow on Water Surface.

View file

@ -36,12 +36,10 @@
#define AREA_ANIMATION_ARC (1.0f / 360.0f)
#define FXREPLICATOR_COLLISION_MASK ( TerrainObjectType | \
InteriorObjectType | \
StaticShapeObjectType | \
WaterObjectType )
#define FXREPLICATOR_NOWATER_COLLISION_MASK ( TerrainObjectType | \
InteriorObjectType | \
StaticShapeObjectType )
@ -139,7 +137,6 @@ public:
U32 mOuterRadiusY;
S32 mOffsetZ;
bool mAllowOnTerrain;
bool mAllowOnInteriors;
bool mAllowStatics;
bool mAllowOnWater;
S32 mAllowedTerrainSlope;
@ -166,7 +163,6 @@ public:
mOffsetZ = 0;
mAllowOnTerrain = true;
mAllowOnInteriors = true;
mAllowStatics = true;
mAllowOnWater = false;
mAllowWaterSurface = false;

View file

@ -1225,14 +1225,17 @@ GroundCoverCell* GroundCover::_generateCell( const Point2I& index,
flipBB *= -1.0f;
PROFILE_START( GroundCover_TerrainRayCast );
hit = terrainBlock->getNormalHeightMaterial( Point2F( cp.x - pos.x, cp.y - pos.y ),
// Transform billboard point into terrain's frame of reference.
Point3F pp = Point3F(cp.x, cp.y, 0);
terrainBlock->getWorldTransform().mulP(pp);
hit = terrainBlock->getNormalHeightMaterial( Point2F ( pp.x, pp.y ),
&normal, &h, matName );
PROFILE_END(); // GroundCover_TerrainRayCast
// TODO: When did we loose the world space elevation when
// getting the terrain height?
h += pos.z + mZOffset;
PROFILE_END(); // GroundCover_TerrainRayCast
if ( !hit || h > typeMaxElevation || h < typeMinElevation ||
( typeLayer[0] && !typeInvertLayer && matName != typeLayer ) ||
( typeLayer[0] && typeInvertLayer && matName == typeLayer ) )
@ -1536,7 +1539,7 @@ void GroundCover::prepRenderImage( SceneRenderState *state )
// Setup the frustum culler.
if ( ( mCuller.getPosition().isZero() || !mDebugLockFrustum ) && !state->isShadowPass() )
mCuller = state->getFrustum();
mCuller = state->getCullingFrustum();
// Update the cells, but only during the diffuse pass.
// We don't want cell generation to thrash when the reflection camera
@ -1550,8 +1553,11 @@ void GroundCover::prepRenderImage( SceneRenderState *state )
{
PROFILE_SCOPE( GroundCover_RenderBillboards );
// Take zoom into account.
F32 screenScale = state->getWorldToScreenScale().y / state->getViewport().extent.y;
// Set the far distance for billboards.
mCuller.setFarDist( mRadius );
mCuller.setFarDist( mRadius * screenScale );
F32 cullScale = 1.0f;
if ( state->isReflectPass() )
@ -1560,18 +1566,26 @@ void GroundCover::prepRenderImage( SceneRenderState *state )
// Setup our shader const data.
// Must be done prior to submitting our render instance.
mShaderConstData.fadeInfo.set( mFadeRadius * cullScale, mRadius * cullScale );
mShaderConstData.fadeInfo.set( mFadeRadius * cullScale * screenScale, mRadius * cullScale * screenScale );
const F32 simTime = Sim::getCurrentTime() * 0.001f;
mShaderConstData.gustInfo.set( mWindGustLength, mWindGustFrequency * simTime, mWindGustStrength );
mShaderConstData.turbInfo.set( mWindTurbulenceFrequency * simTime, mWindTurbulenceStrength );
// Use the camera's forward vector to calculate the camera's right
// and up vectors. This removes any camera banking from affecting
// the ground cover.
const MatrixF &camMat = state->getDiffuseCameraTransform();
Point3F camDir, camUp, camRight;
camMat.getColumn( 1, &camDir );
camMat.getColumn( 2, &camUp );
camMat.getColumn( 0, &camRight );
mCross( camDir, Point3F::UnitZ, &camRight );
if ( camRight.magnitudeSafe() == 0.0f )
{
camRight.set( 0.0f, -1.0f, 0.0f );
}
camRight.normalizeSafe();
mCross( camRight, camDir, &camUp );
// Limit the camera up vector to keep the billboards
// from leaning too far down into the terrain.

View file

@ -287,14 +287,14 @@ bool LightningData::preload(bool server, String &errorStr)
if (server == false)
{
String errorStr;
String sfxErrorStr;
for (U32 i = 0; i < MaxThunders; i++) {
if( !sfxResolve( &thunderSounds[ i ], errorStr ) )
Con::errorf(ConsoleLogEntry::General, "LightningData::preload: Invalid packet: %s", errorStr.c_str());
if( !sfxResolve( &thunderSounds[ i ], sfxErrorStr ) )
Con::errorf(ConsoleLogEntry::General, "LightningData::preload: Invalid packet: %s", sfxErrorStr.c_str());
}
if( !sfxResolve( &strikeSound, errorStr ) )
Con::errorf(ConsoleLogEntry::General, "LightningData::preload: Invalid packet: %s", errorStr.c_str());
if( !sfxResolve( &strikeSound, sfxErrorStr ) )
Con::errorf(ConsoleLogEntry::General, "LightningData::preload: Invalid packet: %s", sfxErrorStr.c_str());
for (U32 i = 0; i < MaxTextures; i++)
{
@ -1139,7 +1139,7 @@ void LightningBolt::generateMinorNodes()
{
mMinorNodes.clear();
for( int i=0; i<mMajorNodes.numNodes - 1; i++ )
for( S32 i=0; i<mMajorNodes.numNodes - 1; i++ )
{
NodeManager segment;
segment.startPoint = mMajorNodes.nodeList[i].point;

View file

@ -66,11 +66,11 @@ ConsoleDocClass( ParticleData,
"@see ParticleEmitterNode\n"
);
static const float sgDefaultWindCoefficient = 0.0f;
static const float sgDefaultConstantAcceleration = 0.f;
static const float sgDefaultSpinSpeed = 1.f;
static const float sgDefaultSpinRandomMin = 0.f;
static const float sgDefaultSpinRandomMax = 0.f;
static const F32 sgDefaultWindCoefficient = 0.0f;
static const F32 sgDefaultConstantAcceleration = 0.f;
static const F32 sgDefaultSpinSpeed = 1.f;
static const F32 sgDefaultSpinRandomMin = 0.f;
static const F32 sgDefaultSpinRandomMax = 0.f;
//-----------------------------------------------------------------------------
@ -128,16 +128,20 @@ ParticleData::~ParticleData()
}
}
FRangeValidator dragCoefFValidator(0.f, 5.f);
FRangeValidator gravCoefFValidator(-10.f, 10.f);
FRangeValidator spinRandFValidator(-1000.f, 1000.f);
//-----------------------------------------------------------------------------
// initPersistFields
//-----------------------------------------------------------------------------
void ParticleData::initPersistFields()
{
addFieldV( "dragCoefficient", TYPEID< F32 >(), Offset(dragCoefficient, ParticleData), new FRangeValidator(0, 5),
addFieldV( "dragCoefficient", TYPEID< F32 >(), Offset(dragCoefficient, ParticleData), &dragCoefFValidator,
"Particle physics drag amount." );
addField( "windCoefficient", TYPEID< F32 >(), Offset(windCoefficient, ParticleData),
"Strength of wind on the particles." );
addFieldV( "gravityCoefficient", TYPEID< F32 >(), Offset(gravityCoefficient, ParticleData), new FRangeValidator(-10, 10),
addFieldV( "gravityCoefficient", TYPEID< F32 >(), Offset(gravityCoefficient, ParticleData), &gravCoefFValidator,
"Strength of gravity on the particles." );
addFieldV( "inheritedVelFactor", TYPEID< F32 >(), Offset(inheritedVelFactor, ParticleData), &CommonValidators::NormalizedFloat,
"Amount of emitter velocity to add to particle initial velocity." );
@ -149,10 +153,10 @@ void ParticleData::initPersistFields()
"Variance in lifetime of particle, from 0 - lifetimeMS." );
addField( "spinSpeed", TYPEID< F32 >(), Offset(spinSpeed, ParticleData),
"Speed at which to spin the particle." );
addField( "spinRandomMin", TYPEID< F32 >(), Offset(spinRandomMin, ParticleData),
"Minimum allowed spin speed of this particle, between -10000 and spinRandomMax." );
addField( "spinRandomMax", TYPEID< F32 >(), Offset(spinRandomMax, ParticleData),
"Maximum allowed spin speed of this particle, between spinRandomMin and 10000." );
addFieldV( "spinRandomMin", TYPEID< F32 >(), Offset(spinRandomMin, ParticleData), &spinRandFValidator,
"Minimum allowed spin speed of this particle, between -1000 and spinRandomMax." );
addFieldV( "spinRandomMax", TYPEID< F32 >(), Offset(spinRandomMax, ParticleData), &spinRandFValidator,
"Maximum allowed spin speed of this particle, between spinRandomMin and 1000." );
addField( "useInvAlpha", TYPEID< bool >(), Offset(useInvAlpha, ParticleData),
"@brief Controls how particles blend with the scene.\n\n"
"If true, particles blend like ParticleBlendStyle NORMAL, if false, "
@ -200,7 +204,8 @@ void ParticleData::initPersistFields()
"@brief Particle RGBA color keyframe values.\n\n"
"The particle color will linearly interpolate between the color/time keys "
"over the lifetime of the particle." );
addField( "sizes", TYPEID< F32 >(), Offset(sizes, ParticleData), PDC_NUM_KEYS,
addProtectedField( "sizes", TYPEID< F32 >(), Offset(sizes, ParticleData), &protectedSetSizes,
&defaultProtectedGetFn, PDC_NUM_KEYS,
"@brief Particle size keyframe values.\n\n"
"The particle size will linearly interpolate between the size/time keys "
"over the lifetime of the particle." );
@ -343,6 +348,22 @@ void ParticleData::unpackData(BitStream* stream)
}
}
bool ParticleData::protectedSetSizes( void *object, const char *index, const char *data)
{
ParticleData *pData = static_cast<ParticleData*>( object );
F32 val = dAtof(data);
U32 i;
if (!index)
i = 0;
else
i = dAtoui(index);
pData->sizes[i] = mClampF( val, 0.f, MaxParticleSize );
return false;
}
bool ParticleData::protectedSetTimes( void *object, const char *index, const char *data)
{
ParticleData *pData = static_cast<ParticleData*>( object );
@ -356,7 +377,7 @@ bool ParticleData::protectedSetTimes( void *object, const char *index, const cha
pData->times[i] = mClampF( val, 0.f, 1.f );
return true;
return false;
}
//-----------------------------------------------------------------------------
@ -379,11 +400,11 @@ bool ParticleData::onAdd()
Con::warnf(ConsoleLogEntry::General, "ParticleData(%s) lifetimeVariance >= lifetime", getName());
lifetimeVarianceMS = lifetimeMS - 1;
}
if (spinSpeed > 10000.0 || spinSpeed < -10000.0) {
if (spinSpeed > 1000.f || spinSpeed < -1000.f) {
Con::warnf(ConsoleLogEntry::General, "ParticleData(%s) spinSpeed invalid", getName());
return false;
}
if (spinRandomMin > 10000.0 || spinRandomMin < -10000.0) {
if (spinRandomMin > 1000.f || spinRandomMin < -1000.f) {
Con::warnf(ConsoleLogEntry::General, "ParticleData(%s) spinRandomMin invalid", getName());
spinRandomMin = -360.0;
return false;
@ -393,7 +414,7 @@ bool ParticleData::onAdd()
spinRandomMin = spinRandomMax - (spinRandomMin - spinRandomMax );
return false;
}
if (spinRandomMax > 10000.0 || spinRandomMax < -10000.0) {
if (spinRandomMax > 1000.f || spinRandomMax < -1000.f) {
Con::warnf(ConsoleLogEntry::General, "ParticleData(%s) spinRandomMax invalid", getName());
spinRandomMax = 360.0;
return false;
@ -601,7 +622,7 @@ bool ParticleData::reload(char errorBuffer[256])
}
/*
numFrames = 0;
for( int i=0; i<PDC_MAX_TEX; i++ )
for( S32 i=0; i<PDC_MAX_TEX; i++ )
{
if( textureNameList[i] && textureNameList[i][0] )
{

View file

@ -79,6 +79,7 @@ class ParticleData : public SimDataBlock
StringTableEntry textureName;
GFXTexHandle textureHandle;
static bool protectedSetSizes( void *object, const char *index, const char *data );
static bool protectedSetTimes( void *object, const char *index, const char *data );
public:

View file

@ -100,9 +100,9 @@ ConsoleDocClass( ParticleEmitterData,
"@see ParticleEmitterNode\n"
);
static const float sgDefaultEjectionOffset = 0.f;
static const float sgDefaultPhiReferenceVel = 0.f;
static const float sgDefaultPhiVariance = 360.f;
static const F32 sgDefaultEjectionOffset = 0.f;
static const F32 sgDefaultPhiReferenceVel = 0.f;
static const F32 sgDefaultPhiVariance = 360.f;
//-----------------------------------------------------------------------------
// ParticleEmitterData
@ -118,6 +118,7 @@ ParticleEmitterData::ParticleEmitterData()
ejectionVelocity = 2.0f; // From 1.0 - 3.0 meters per sec
velocityVariance = 1.0f;
ejectionOffset = sgDefaultEjectionOffset; // ejection from the emitter point
ejectionOffsetVariance = 0.0f;
thetaMin = 0.0f; // All heights
thetaMax = 90.0f;
@ -171,6 +172,13 @@ ImplementEnumType( ParticleBlendStyle,
{ ParticleRenderInst::BlendPremultAlpha, "PREMULTALPHA", "Color blends with the colors of the imagemap rather than the alpha.\n" },
EndImplementEnumType;
IRangeValidator ejectPeriodIValidator(1, 2047);
IRangeValidator periodVarianceIValidator(0, 2047);
FRangeValidator ejectionFValidator(0.f, 655.35f);
FRangeValidator velVarianceFValidator(0.f, 163.83f);
FRangeValidator thetaFValidator(0.f, 180.f);
FRangeValidator phiFValidator(0.f, 360.f);
//-----------------------------------------------------------------------------
// initPersistFields
//-----------------------------------------------------------------------------
@ -178,31 +186,34 @@ void ParticleEmitterData::initPersistFields()
{
addGroup( "ParticleEmitterData" );
addFieldV("ejectionPeriodMS", TYPEID< S32 >(), Offset(ejectionPeriodMS, ParticleEmitterData), new IRangeValidator(1, 2047),
addFieldV("ejectionPeriodMS", TYPEID< S32 >(), Offset(ejectionPeriodMS, ParticleEmitterData), &ejectPeriodIValidator,
"Time (in milliseconds) between each particle ejection." );
addFieldV("periodVarianceMS", TYPEID< S32 >(), Offset(periodVarianceMS, ParticleEmitterData), new IRangeValidator(0, 2047),
addFieldV("periodVarianceMS", TYPEID< S32 >(), Offset(periodVarianceMS, ParticleEmitterData), &periodVarianceIValidator,
"Variance in ejection period, from 1 - ejectionPeriodMS." );
addFieldV( "ejectionVelocity", TYPEID< F32 >(), Offset(ejectionVelocity, ParticleEmitterData), new FRangeValidator(0, 655.35f),
addFieldV( "ejectionVelocity", TYPEID< F32 >(), Offset(ejectionVelocity, ParticleEmitterData), &ejectionFValidator,
"Particle ejection velocity." );
addFieldV( "velocityVariance", TYPEID< F32 >(), Offset(velocityVariance, ParticleEmitterData), new FRangeValidator(0, 163.83f),
addFieldV( "velocityVariance", TYPEID< F32 >(), Offset(velocityVariance, ParticleEmitterData), &velVarianceFValidator,
"Variance for ejection velocity, from 0 - ejectionVelocity." );
addFieldV( "ejectionOffset", TYPEID< F32 >(), Offset(ejectionOffset, ParticleEmitterData), new FRangeValidator(0, 655.35f),
addFieldV( "ejectionOffset", TYPEID< F32 >(), Offset(ejectionOffset, ParticleEmitterData), &ejectionFValidator,
"Distance along ejection Z axis from which to eject particles." );
addFieldV( "ejectionOffsetVariance", TYPEID< F32 >(), Offset(ejectionOffsetVariance, ParticleEmitterData), &ejectionFValidator,
"Distance Padding along ejection Z axis from which to eject particles." );
addFieldV( "thetaMin", TYPEID< F32 >(), Offset(thetaMin, ParticleEmitterData), new FRangeValidator(0, 180.0f),
addFieldV( "thetaMin", TYPEID< F32 >(), Offset(thetaMin, ParticleEmitterData), &thetaFValidator,
"Minimum angle, from the horizontal plane, to eject from." );
addFieldV( "thetaMax", TYPEID< F32 >(), Offset(thetaMax, ParticleEmitterData), new FRangeValidator(0, 180.0f),
addFieldV( "thetaMax", TYPEID< F32 >(), Offset(thetaMax, ParticleEmitterData), &thetaFValidator,
"Maximum angle, from the horizontal plane, to eject particles from." );
addFieldV( "phiReferenceVel", TYPEID< F32 >(), Offset(phiReferenceVel, ParticleEmitterData), new FRangeValidator(0, 360.0f),
addFieldV( "phiReferenceVel", TYPEID< F32 >(), Offset(phiReferenceVel, ParticleEmitterData), &phiFValidator,
"Reference angle, from the vertical plane, to eject particles from." );
addFieldV( "phiVariance", TYPEID< F32 >(), Offset(phiVariance, ParticleEmitterData), new FRangeValidator(0, 360.0f),
addFieldV( "phiVariance", TYPEID< F32 >(), Offset(phiVariance, ParticleEmitterData), &phiFValidator,
"Variance from the reference angle, from 0 - 360." );
addField( "softnessDistance", TYPEID< F32 >(), Offset(softnessDistance, ParticleEmitterData),
@ -309,6 +320,8 @@ void ParticleEmitterData::packData(BitStream* stream)
stream->writeInt((S32)(velocityVariance * 100), 14);
if( stream->writeFlag( ejectionOffset != sgDefaultEjectionOffset ) )
stream->writeInt((S32)(ejectionOffset * 100), 16);
if( stream->writeFlag( ejectionOffsetVariance != 0.0f ) )
stream->writeInt((S32)(ejectionOffsetVariance * 100), 16);
stream->writeRangedU32((U32)thetaMin, 0, 180);
stream->writeRangedU32((U32)thetaMax, 0, 180);
if( stream->writeFlag( phiReferenceVel != sgDefaultPhiReferenceVel ) )
@ -361,7 +374,10 @@ void ParticleEmitterData::unpackData(BitStream* stream)
ejectionOffset = stream->readInt(16) / 100.0f;
else
ejectionOffset = sgDefaultEjectionOffset;
if( stream->readFlag() )
ejectionOffsetVariance = stream->readInt(16) / 100.0f;
else
ejectionOffsetVariance = 0.0f;
thetaMin = (F32)stream->readRangedU32(0, 180);
thetaMax = (F32)stream->readRangedU32(0, 180);
if( stream->readFlag() )
@ -719,6 +735,7 @@ ParticleEmitter::ParticleEmitter()
mCurBuffSize = 0;
mDead = false;
mDataBlock = NULL;
// ParticleEmitter should be allocated on the client only.
mNetFlags.set( IsGhost );
@ -749,11 +766,6 @@ bool ParticleEmitter::onAdd()
{
cleanup->addObject( this );
}
else
{
AssertFatal( false, "Error, could not find ClientMissionCleanup group" );
return false;
}
removeFromProcessList();
@ -917,7 +929,7 @@ void ParticleEmitter::prepRenderImage(SceneRenderState* state)
//-----------------------------------------------------------------------------
void ParticleEmitter::setSizes( F32 *sizeList )
{
for( int i=0; i<ParticleData::PDC_NUM_KEYS; i++ )
for( S32 i=0; i<ParticleData::PDC_NUM_KEYS; i++ )
{
sizes[i] = sizeList[i];
}
@ -928,7 +940,7 @@ void ParticleEmitter::setSizes( F32 *sizeList )
//-----------------------------------------------------------------------------
void ParticleEmitter::setColors( ColorF *colorList )
{
for( int i=0; i<ParticleData::PDC_NUM_KEYS; i++ )
for( S32 i=0; i<ParticleData::PDC_NUM_KEYS; i++ )
{
colors[i] = colorList[i];
}
@ -1279,7 +1291,7 @@ void ParticleEmitter::addParticle(const Point3F& pos,
F32 initialVel = mDataBlock->ejectionVelocity;
initialVel += (mDataBlock->velocityVariance * 2.0f * gRandGen.randF()) - mDataBlock->velocityVariance;
pNew->pos = pos + (ejectionAxis * mDataBlock->ejectionOffset);
pNew->pos = pos + (ejectionAxis * (mDataBlock->ejectionOffset + mDataBlock->ejectionOffsetVariance* gRandGen.randF()) );
pNew->vel = ejectionAxis * initialVel;
pNew->orientDir = ejectionAxis;
pNew->acc.set(0, 0, 0);
@ -1443,7 +1455,7 @@ struct SortParticle
};
// qsort callback function for particle sorting
int QSORT_CALLBACK cmpSortParticles(const void* p1, const void* p2)
S32 QSORT_CALLBACK cmpSortParticles(const void* p1, const void* p2)
{
const SortParticle* sp1 = (const SortParticle*)p1;
const SortParticle* sp2 = (const SortParticle*)p2;

View file

@ -73,7 +73,7 @@ class ParticleEmitterData : public GameBaseData
F32 ejectionVelocity; ///< Ejection velocity
F32 velocityVariance; ///< Variance for velocity between 0 and n
F32 ejectionOffset; ///< Z offset from emitter point to eject from
F32 ejectionOffsetVariance; ///< Z offset Variance from emitter point to eject
F32 thetaMin; ///< Minimum angle, from the horizontal plane, to eject from
F32 thetaMax; ///< Maximum angle, from the horizontal plane, to eject from

View file

@ -45,7 +45,6 @@
static const U32 dropHitMask =
TerrainObjectType |
InteriorObjectType |
WaterObjectType |
StaticShapeObjectType;
@ -1169,9 +1168,7 @@ void Precipitation::destroySplash(Raindrop *drop)
PROFILE_START(PrecipDestroySplash);
if (drop == mSplashHead)
{
mSplashHead = NULL;
PROFILE_END();
return;
mSplashHead = mSplashHead->nextSplashDrop;
}
if (drop->nextSplashDrop)
@ -1728,6 +1725,7 @@ void Precipitation::renderObject(ObjectRenderInst *ri, SceneRenderState *state,
// Do we need to relock the buffer?
if ( !vertPtr )
vertPtr = mRainVB.lock();
if(!vertPtr) return;
// Set the proper texture coords... (it's fun!)
tc = &mTexCoords[4*curr->texCoordIndex];
@ -1818,6 +1816,7 @@ void Precipitation::renderObject(ObjectRenderInst *ri, SceneRenderState *state,
// Do we need to relock the buffer?
if ( !vertPtr )
vertPtr = mRainVB.lock();
if(!vertPtr) return;
vertPtr->point = pos + leftUp;
vertPtr->texCoord = *tc;

View file

@ -303,6 +303,7 @@ bool SplashData::preload(bool server, String &errorStr)
// Splash
//--------------------------------------------------------------------------
Splash::Splash()
: mDataBlock( NULL )
{
dMemset( mEmitterList, 0, sizeof( mEmitterList ) );
@ -353,6 +354,12 @@ bool Splash::onAdd()
if(!conn || !Parent::onAdd())
return false;
if( !mDataBlock )
{
Con::errorf("Splash::onAdd - Fail - No datablock");
return false;
}
mDelayMS = mDataBlock->delayMS + sgRandom.randI( -mDataBlock->delayVariance, mDataBlock->delayVariance );
mEndingMS = mDataBlock->lifetimeMS + sgRandom.randI( -mDataBlock->lifetimeVariance, mDataBlock->lifetimeVariance );
@ -408,8 +415,11 @@ void Splash::onRemove()
ringList.clear();
getSceneManager()->removeObjectFromScene(this);
getContainer()->removeObject(this);
if( getSceneManager() )
getSceneManager()->removeObjectFromScene(this);
if( getContainer() )
getContainer()->removeObject(this);
Parent::onRemove();
}

View file

@ -0,0 +1,379 @@
#include "platform/platform.h"
#include "T3D/gameBase/extended/extendedGameProcess.h"
#include "T3D/gameBase/extended/extendedMoveList.h"
#include "platform/profiler.h"
#include "console/consoleTypes.h"
#include "core/dnet.h"
#include "core/stream/bitStream.h"
#include "core/frameAllocator.h"
#include "core/util/refBase.h"
#include "math/mPoint3.h"
#include "math/mMatrix.h"
#include "math/mathUtils.h"
#include "T3D/gameBase/gameBase.h"
#include "T3D/gameBase/gameConnection.h"
#include "T3D/fx/cameraFXMgr.h"
MODULE_BEGIN( ProcessList )
MODULE_INIT
{
ExtendedServerProcessList::init();
ExtendedClientProcessList::init();
}
MODULE_SHUTDOWN
{
ExtendedServerProcessList::shutdown();
ExtendedClientProcessList::shutdown();
}
MODULE_END;
void ExtendedServerProcessList::init()
{
smServerProcessList = new ExtendedServerProcessList();
}
void ExtendedServerProcessList::shutdown()
{
delete smServerProcessList;
}
void ExtendedClientProcessList::init()
{
smClientProcessList = new ExtendedClientProcessList();
}
void ExtendedClientProcessList::shutdown()
{
delete smClientProcessList;
}
//----------------------------------------------------------------------------
namespace
{
// local work class
struct GameBaseListNode
{
GameBaseListNode()
{
mPrev=this;
mNext=this;
mObject=NULL;
}
GameBaseListNode * mPrev;
GameBaseListNode * mNext;
GameBase * mObject;
void linkBefore(GameBaseListNode * obj)
{
// Link this before obj
mNext = obj;
mPrev = obj->mPrev;
obj->mPrev = this;
mPrev->mNext = this;
}
};
} // namespace
//--------------------------------------------------------------------------
// ExtendedClientProcessList
//--------------------------------------------------------------------------
ExtendedClientProcessList::ExtendedClientProcessList()
{
}
bool ExtendedClientProcessList::advanceTime( SimTime timeDelta )
{
PROFILE_SCOPE( ExtendedClientProcessList_AdvanceTime );
if ( doBacklogged( timeDelta ) )
return false;
bool ret = Parent::advanceTime( timeDelta );
ProcessObject *obj = NULL;
AssertFatal( mLastDelta >= 0.0f && mLastDelta <= 1.0f, "mLastDelta is not zero to one.");
obj = mHead.mProcessLink.next;
while ( obj != &mHead )
{
if ( obj->isTicking() )
obj->interpolateTick( mLastDelta );
obj = obj->mProcessLink.next;
}
// Inform objects of total elapsed delta so they can advance
// client side animations.
F32 dt = F32(timeDelta) / 1000;
// Update camera FX.
gCamFXMgr.update( dt );
obj = mHead.mProcessLink.next;
while ( obj != &mHead )
{
obj->advanceTime( dt );
obj = obj->mProcessLink.next;
}
return ret;
}
//----------------------------------------------------------------------------
void ExtendedClientProcessList::onAdvanceObjects()
{
PROFILE_SCOPE( ExtendedClientProcessList_OnAdvanceObjects );
GameConnection* connection = GameConnection::getConnectionToServer();
if ( connection )
{
// process any demo blocks that are NOT moves, and exactly one move
// we advance time in the demo stream by a move inserted on
// each tick. So before doing the tick processing we advance
// the demo stream until a move is ready
if ( connection->isPlayingBack() )
{
U32 blockType;
do
{
blockType = connection->getNextBlockType();
bool res = connection->processNextBlock();
// if there are no more blocks, exit out of this function,
// as no more client time needs to process right now - we'll
// get it all on the next advanceClientTime()
if(!res)
return;
}
while ( blockType != GameConnection::BlockTypeMove );
}
connection->mMoveList->collectMove();
advanceObjects();
}
else
advanceObjects();
}
void ExtendedClientProcessList::onTickObject( ProcessObject *obj )
{
PROFILE_SCOPE( ExtendedClientProcessList_OnTickObject );
// In case the object deletes itself during its processTick.
SimObjectPtr<SceneObject> safePtr = static_cast<SceneObject*>( obj );
// Each object is either advanced a single tick, or if it's
// being controlled by a client, ticked once for each pending move.
ExtendedMove* extMovePtr;
U32 numMoves;
GameConnection* con = obj->getControllingClient();
if ( con && con->getControlObject() == obj )
{
ExtendedMoveList* extMoveList = static_cast<ExtendedMoveList*>(con->mMoveList);
extMoveList->getExtMoves( &extMovePtr, &numMoves );
if ( numMoves )
{
// Note: should only have a single move at this point
AssertFatal(numMoves==1,"ClientProccessList::onTickObject: more than one move in queue");
#ifdef TORQUE_DEBUG_NET_MOVES
U32 sum = Move::ChecksumMask & obj->getPacketDataChecksum(obj->getControllingClient());
#endif
if ( obj->isTicking() )
obj->processTick( extMovePtr );
if ( bool(safePtr) && obj->getControllingClient() )
{
U32 newsum = Move::ChecksumMask & obj->getPacketDataChecksum( obj->getControllingClient() );
// set checksum if not set or check against stored value if set
extMovePtr->checksum = newsum;
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("move checksum: %i, (start %i), (move %f %f %f)",
movePtr->checksum,sum,movePtr->yaw,movePtr->y,movePtr->z);
#endif
}
con->mMoveList->clearMoves( 1 );
}
}
else if ( obj->isTicking() )
obj->processTick( 0 );
}
void ExtendedClientProcessList::advanceObjects()
{
PROFILE_SCOPE( ExtendedClientProcessList_AdvanceObjects );
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("Advance client time...");
#endif
Parent::advanceObjects();
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("---------");
#endif
}
void ExtendedClientProcessList::clientCatchup( GameConnection * connection )
{
SimObjectPtr<GameBase> control = connection->getControlObject();
if ( control )
{
ExtendedMove * extMovePtr;
U32 numMoves;
U32 m = 0;
ExtendedMoveList* extMoveList = static_cast<ExtendedMoveList*>(connection->mMoveList);
extMoveList->getExtMoves( &extMovePtr, &numMoves );
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("client catching up... (%i)", numMoves);
#endif
preTickSignal().trigger();
if ( control->isTicking() )
for ( m = 0; m < numMoves; m++ )
control->processTick( extMovePtr++ );
extMoveList->clearMoves( m );
}
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("---------");
#endif
}
//--------------------------------------------------------------------------
// ServerProcessList
//--------------------------------------------------------------------------
ExtendedServerProcessList::ExtendedServerProcessList()
{
}
void ExtendedServerProcessList::onPreTickObject( ProcessObject *pobj )
{
if ( pobj->mIsGameBase )
{
SimObjectPtr<GameBase> obj = getGameBase( pobj );
// Each object is either advanced a single tick, or if it's
// being controlled by a client, ticked once for each pending move.
GameConnection *con = obj->getControllingClient();
if ( con && con->getControlObject() == obj )
{
ExtendedMove* extMovePtr;
U32 numMoves;
ExtendedMoveList* extMoveList = static_cast<ExtendedMoveList*>(con->mMoveList);
extMoveList->getExtMoves( &extMovePtr, &numMoves );
if ( numMoves == 0 )
{
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("no moves on object %i, skip tick",obj->getId());
#endif
return;
}
}
}
Parent::onPreTickObject (pobj );
}
void ExtendedServerProcessList::onTickObject( ProcessObject *pobj )
{
PROFILE_SCOPE( ExtendedServerProcessList_OnTickObject );
// Each object is either advanced a single tick, or if it's
// being controlled by a client, ticked once for each pending move.
GameConnection *con = pobj->getControllingClient();
if ( pobj->mIsGameBase && con && con->getControlObject() == pobj )
{
// In case the object is deleted during its own tick.
SimObjectPtr<GameBase> obj = getGameBase( pobj );
ExtendedMove* extMovePtr;
U32 m, numMoves;
ExtendedMoveList* extMoveList = static_cast<ExtendedMoveList*>(con->mMoveList);
extMoveList->getExtMoves( &extMovePtr, &numMoves );
// For debugging it can be useful to know when this happens.
//if ( numMoves > 1 )
// Con::printf( "numMoves: %i", numMoves );
// Do we really need to test the control object each iteration? Does it change?
for ( m = 0; m < numMoves && con && con->getControlObject() == obj; m++, extMovePtr++ )
{
#ifdef TORQUE_DEBUG_NET_MOVES
U32 sum = Move::ChecksumMask & obj->getPacketDataChecksum(obj->getControllingClient());
#endif
if ( obj->isTicking() )
obj->processTick( extMovePtr );
if ( con && con->getControlObject() == obj )
{
U32 newsum = Move::ChecksumMask & obj->getPacketDataChecksum( obj->getControllingClient() );
// check move checksum
if ( extMovePtr->checksum != newsum )
{
#ifdef TORQUE_DEBUG_NET_MOVES
if( !obj->isAIControlled() )
Con::printf("move %i checksum disagree: %i != %i, (start %i), (move %f %f %f)",
extMovePtr->id, extMovePtr->checksum,newsum,sum,extMovePtr->yaw,extMovePtr->y,extMovePtr->z);
#endif
extMovePtr->checksum = Move::ChecksumMismatch;
}
else
{
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("move %i checksum agree: %i == %i, (start %i), (move %f %f %f)",
extMovePtr->id, extMovePtr->checksum,newsum,sum,extMovePtr->yaw,extMovePtr->y,extMovePtr->z);
#endif
}
}
}
extMoveList->clearMoves( m );
}
else if ( pobj->isTicking() )
pobj->processTick( 0 );
}
void ExtendedServerProcessList::advanceObjects()
{
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("Advance server time...");
#endif
Parent::advanceObjects();
// Credit all connections with the elapsed tick
SimGroup *clientGroup = Sim::getClientGroup();
for(SimGroup::iterator i = clientGroup->begin(); i != clientGroup->end(); i++)
{
if (GameConnection *con = dynamic_cast<GameConnection *>(*i))
{
con->mMoveList->advanceMove();
}
}
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("---------");
#endif
}

View file

@ -0,0 +1,60 @@
#ifndef _GAMEPROCESS_EXTENDED_H_
#define _GAMEPROCESS_EXTENDED_H_
//#include "T3D/gameBase/processList.h"
#ifndef _GAMEPROCESS_H_
#include "T3D/gameBase/gameProcess.h"
#endif
class GameBase;
class GameConnection;
struct Move;
//----------------------------------------------------------------------------
/// List to keep track of GameBases to process.
class ExtendedClientProcessList : public ClientProcessList
{
typedef ClientProcessList Parent;
protected:
// ProcessList
void onTickObject(ProcessObject *);
void advanceObjects();
void onAdvanceObjects();
public:
ExtendedClientProcessList();
// ProcessList
bool advanceTime( SimTime timeDelta );
// ClientProcessList
void clientCatchup( GameConnection *conn );
static void init();
static void shutdown();
};
class ExtendedServerProcessList : public ServerProcessList
{
typedef ServerProcessList Parent;
protected:
// ProcessList
void onPreTickObject( ProcessObject *pobj );
void onTickObject( ProcessObject *pobj );
void advanceObjects();
public:
ExtendedServerProcessList();
static void init();
static void shutdown();
};
#endif // _GAMEPROCESS_EXTENDED_H_

View file

@ -0,0 +1,302 @@
#include "T3D/gameBase/extended/extendedMove.h"
#include "core/stream/bitStream.h"
#include "math/mathIO.h"
#include "core/module.h"
#include "console/consoleTypes.h"
#include "core/strings/stringFunctions.h"
MODULE_BEGIN( ExtendedMoveManager )
MODULE_INIT_AFTER( MoveManager )
MODULE_INIT
{
ExtendedMoveManager::init();
}
MODULE_END;
S32 ExtendedMoveManager::mPosX[ExtendedMove::MaxPositionsRotations] = { 0, };
S32 ExtendedMoveManager::mPosY[ExtendedMove::MaxPositionsRotations] = { 0, };
S32 ExtendedMoveManager::mPosZ[ExtendedMove::MaxPositionsRotations] = { 0, };
bool ExtendedMoveManager::mRotIsEuler[ExtendedMove::MaxPositionsRotations] = { 0, };
F32 ExtendedMoveManager::mRotAX[ExtendedMove::MaxPositionsRotations] = { 0, };
F32 ExtendedMoveManager::mRotAY[ExtendedMove::MaxPositionsRotations] = { 0, };
F32 ExtendedMoveManager::mRotAZ[ExtendedMove::MaxPositionsRotations] = { 0, };
F32 ExtendedMoveManager::mRotAA[ExtendedMove::MaxPositionsRotations] = { 1, };
void ExtendedMoveManager::init()
{
for(U32 i = 0; i < ExtendedMove::MaxPositionsRotations; ++i)
{
char varName[256];
dSprintf(varName, sizeof(varName), "mvPosX%d", i);
Con::addVariable(varName, TypeS32, &mPosX[i],
"X position of controller in millimeters. Only 13 bits are networked.\n"
"@ingroup Game");
dSprintf(varName, sizeof(varName), "mvPosY%d", i);
Con::addVariable(varName, TypeS32, &mPosY[i],
"Y position of controller in millimeters. Only 13 bits are networked.\n"
"@ingroup Game");
dSprintf(varName, sizeof(varName), "mvPosZ%d", i);
Con::addVariable(varName, TypeS32, &mPosZ[i],
"Z position of controller in millimeters. Only 13 bits are networked.\n"
"@ingroup Game");
dSprintf(varName, sizeof(varName), "mvRotIsEuler%d", i);
Con::addVariable(varName, TypeBool, &mRotIsEuler[i],
"@brief Indicates that the given rotation is Euler angles.\n\n"
"When false (the default) the given rotation is a four component angled axis "
"(a vector and angle). When true, the given rotation is a three component "
"Euler angle. When using Euler angles, the $mvRotA component of the ExtendedMove "
"is ignored for this set of rotations.\n"
"@ingroup Game");
dSprintf(varName, sizeof(varName), "mvRotX%d", i);
Con::addVariable(varName, TypeF32, &mRotAX[i],
"X rotation vector component of controller.\n"
"@ingroup Game");
dSprintf(varName, sizeof(varName), "mvRotY%d", i);
Con::addVariable(varName, TypeF32, &mRotAY[i],
"Y rotation vector component of controller.\n"
"@ingroup Game");
dSprintf(varName, sizeof(varName), "mvRotZ%d", i);
Con::addVariable(varName, TypeF32, &mRotAZ[i],
"Z rotation vector component of controller.\n"
"@ingroup Game");
dSprintf(varName, sizeof(varName), "mvRotA%d", i);
Con::addVariable(varName, TypeF32, &mRotAA[i],
"Angle rotation (in degrees) component of controller.\n"
"@ingroup Game");
}
}
const ExtendedMove NullExtendedMove;
#define CLAMPPOS(x) (x<0 ? -((-x) & (1<<(MaxPositionBits-1))-1) : (x & (1<<(MaxPositionBits-1))-1))
#define CLAMPROT(f) ((S32)(((f + 1) * .5) * ((1 << MaxRotationBits) - 1)) & ((1<<MaxRotationBits)-1))
#define UNCLAMPROT(x) ((F32)(x * 2 / F32((1 << MaxRotationBits) - 1) - 1.0f))
ExtendedMove::ExtendedMove() : Move()
{
for(U32 i=0; i<MaxPositionsRotations; ++i)
{
posX[i] = 0;
posY[i] = 0;
posZ[i] = 0;
rotX[i] = 0;
rotY[i] = 0;
rotZ[i] = 0;
rotW[i] = 1;
EulerBasedRotation[i] = false;
}
}
void ExtendedMove::pack(BitStream *stream, const Move * basemove)
{
bool alwaysWriteAll = basemove!=NULL;
if (!basemove)
basemove = &NullExtendedMove;
// Write the standard Move stuff
packMove(stream, basemove, alwaysWriteAll);
// Extended Move
const ExtendedMove* extBaseMove = static_cast<const ExtendedMove*>(basemove);
bool extendedDifferent = false;
for(U32 i=0; i<MaxPositionsRotations; ++i)
{
bool check = (posX[i] != extBaseMove->posX[i]) ||
(posY[i] != extBaseMove->posY[i]) ||
(posZ[i] != extBaseMove->posZ[i]) ||
(rotX[i] != extBaseMove->rotX[i]) ||
(rotY[i] != extBaseMove->rotY[i]) ||
(rotZ[i] != extBaseMove->rotZ[i]);
if(!EulerBasedRotation[i])
{
check = check || (rotW[i] != extBaseMove->rotW[i]);
}
extendedDifferent = extendedDifferent || check;
}
if (alwaysWriteAll || stream->writeFlag(extendedDifferent))
{
for(U32 i=0; i<MaxPositionsRotations; ++i)
{
// Position
if(stream->writeFlag(posX[i] != extBaseMove->posX[i]))
stream->writeSignedInt(posX[i], MaxPositionBits);
if(stream->writeFlag(posY[i] != extBaseMove->posY[i]))
stream->writeSignedInt(posY[i], MaxPositionBits);
if(stream->writeFlag(posZ[i] != extBaseMove->posZ[i]))
stream->writeSignedInt(posZ[i], MaxPositionBits);
// Rotation
stream->writeFlag(EulerBasedRotation[i]);
if(stream->writeFlag(rotX[i] != extBaseMove->rotX[i]))
stream->writeInt(crotX[i], MaxRotationBits);
if(stream->writeFlag(rotY[i] != extBaseMove->rotY[i]))
stream->writeInt(crotY[i], MaxRotationBits);
if(stream->writeFlag(rotZ[i] != extBaseMove->rotZ[i]))
stream->writeInt(crotZ[i], MaxRotationBits);
if(!EulerBasedRotation[i])
{
if(stream->writeFlag(rotW[i] != extBaseMove->rotW[i]))
stream->writeInt(crotW[i], MaxRotationBits);
}
}
}
}
void ExtendedMove::unpack(BitStream *stream, const Move * basemove)
{
bool alwaysReadAll = basemove!=NULL;
if (!basemove)
basemove=&NullExtendedMove;
// Standard Move stuff
bool isBaseMove = !unpackMove(stream, basemove, alwaysReadAll);
// ExtendedMove
const ExtendedMove* extBaseMove = static_cast<const ExtendedMove*>(basemove);
if (alwaysReadAll || stream->readFlag())
{
isBaseMove = false;
for(U32 i=0; i<MaxPositionsRotations; ++i)
{
// Position
if(stream->readFlag())
posX[i] = stream->readSignedInt(MaxPositionBits);
else
posX[i] = extBaseMove->posX[i];
if(stream->readFlag())
posY[i] = stream->readSignedInt(MaxPositionBits);
else
posY[i] = extBaseMove->posY[i];
if(stream->readFlag())
posZ[i] = stream->readSignedInt(MaxPositionBits);
else
posZ[i] = extBaseMove->posZ[i];
// Rotation
EulerBasedRotation[i] = stream->readFlag();
F32 scale = 1.0f;
if(EulerBasedRotation[i])
scale = M_2PI_F;
if(stream->readFlag())
{
crotX[i] = stream->readInt(MaxRotationBits);
rotX[i] = UNCLAMPROT(crotX[i]) * scale;
}
else
{
rotX[i] = extBaseMove->rotX[i];
}
if(stream->readFlag())
{
crotY[i] = stream->readInt(MaxRotationBits);
rotY[i] = UNCLAMPROT(crotY[i]) * scale;
}
else
{
rotY[i] = extBaseMove->rotY[i];
}
if(stream->readFlag())
{
crotZ[i] = stream->readInt(MaxRotationBits);
rotZ[i] = UNCLAMPROT(crotZ[i]) * scale;
}
else
{
rotZ[i] = extBaseMove->rotZ[i];
}
if(!EulerBasedRotation[i])
{
if(stream->readFlag())
{
crotW[i] = stream->readInt(MaxRotationBits);
rotW[i] = UNCLAMPROT(crotW[i]);
}
else
{
rotW[i] = extBaseMove->rotW[i];
}
}
}
}
if(isBaseMove)
{
*this = *extBaseMove;
}
}
void ExtendedMove::clamp()
{
// Clamp the values the same as for net traffic so the client matches the server
for(U32 i=0; i<MaxPositionsRotations; ++i)
{
// Positions
posX[i] = CLAMPPOS(posX[i]);
posY[i] = CLAMPPOS(posY[i]);
posZ[i] = CLAMPPOS(posZ[i]);
// Rotations
if(EulerBasedRotation[i])
{
crotX[i] = CLAMPROT(rotX[i] / M_2PI_F);
crotY[i] = CLAMPROT(rotY[i] / M_2PI_F);
crotZ[i] = CLAMPROT(rotZ[i] / M_2PI_F);
}
else
{
crotX[i] = CLAMPROT(rotX[i]);
crotY[i] = CLAMPROT(rotY[i]);
crotZ[i] = CLAMPROT(rotZ[i]);
crotW[i] = CLAMPROT(rotW[i]);
}
}
// Perform the standard Move clamp
Parent::clamp();
}
void ExtendedMove::unclamp()
{
// Unclamp the values the same as for net traffic so the client matches the server
for(U32 i=0; i<MaxPositionsRotations; ++i)
{
// Rotations
if(EulerBasedRotation[i])
{
rotX[i] = UNCLAMPROT(crotX[i]) * M_2PI_F;
rotY[i] = UNCLAMPROT(crotY[i]) * M_2PI_F;
rotZ[i] = UNCLAMPROT(crotZ[i]) * M_2PI_F;
}
else
{
rotX[i] = UNCLAMPROT(crotX[i]);
rotY[i] = UNCLAMPROT(crotY[i]);
rotZ[i] = UNCLAMPROT(crotZ[i]);
rotW[i] = UNCLAMPROT(crotW[i]);
}
}
// Perform the standard Move unclamp
Parent::unclamp();
}

View file

@ -0,0 +1,54 @@
#ifndef _EXTENDEDMOVE_H_
#define _EXTENDEDMOVE_H_
#include "T3D/gameBase/moveManager.h"
#include "math/mQuat.h"
struct ExtendedMove : public Move
{
typedef Move Parent;
enum Constants {
MaxPositionsRotations = 3,
MaxPositionBits = 13,
MaxRotationBits = 16,
};
// Position is in millimeters
S32 posX[MaxPositionsRotations], posY[MaxPositionsRotations], posZ[MaxPositionsRotations];
bool EulerBasedRotation[MaxPositionsRotations];
F32 rotX[MaxPositionsRotations], rotY[MaxPositionsRotations], rotZ[MaxPositionsRotations], rotW[MaxPositionsRotations];
// Network clamped rotation
S32 crotX[MaxPositionsRotations], crotY[MaxPositionsRotations], crotZ[MaxPositionsRotations], crotW[MaxPositionsRotations];
ExtendedMove();
virtual void pack(BitStream *stream, const Move * move = NULL);
virtual void unpack(BitStream *stream, const Move * move = NULL);
virtual void clamp();
virtual void unclamp();
};
extern const ExtendedMove NullExtendedMove;
class ExtendedMoveManager
{
public:
static S32 mPosX[ExtendedMove::MaxPositionsRotations];
static S32 mPosY[ExtendedMove::MaxPositionsRotations];
static S32 mPosZ[ExtendedMove::MaxPositionsRotations];
static bool mRotIsEuler[ExtendedMove::MaxPositionsRotations];
static F32 mRotAX[ExtendedMove::MaxPositionsRotations];
static F32 mRotAY[ExtendedMove::MaxPositionsRotations];
static F32 mRotAZ[ExtendedMove::MaxPositionsRotations];
static F32 mRotAA[ExtendedMove::MaxPositionsRotations];
static void init();
};
#endif // _EXTENDEDMOVE_H_

View file

@ -0,0 +1,380 @@
#include "platform/platform.h"
#include "T3D/gameBase/extended/extendedMoveList.h"
#include "T3D/gameBase/gameConnection.h"
#include "core/stream/bitStream.h"
#define MAX_MOVE_PACKET_SENDS 4
ExtendedMoveList::ExtendedMoveList()
{
mMoveCredit = MaxMoveCount;
mControlMismatch = false;
reset();
}
void ExtendedMoveList::reset()
{
mLastMoveAck = 0;
mLastClientMove = 0;
mFirstMoveIndex = 0;
mExtMoveVec.clear();
}
bool ExtendedMoveList::getNextExtMove( ExtendedMove &curMove )
{
if ( mExtMoveVec.size() > MaxMoveQueueSize )
return false;
// From MoveList
F32 pitchAdd = MoveManager::mPitchUpSpeed - MoveManager::mPitchDownSpeed;
F32 yawAdd = MoveManager::mYawLeftSpeed - MoveManager::mYawRightSpeed;
F32 rollAdd = MoveManager::mRollRightSpeed - MoveManager::mRollLeftSpeed;
curMove.pitch = MoveManager::mPitch + pitchAdd;
curMove.yaw = MoveManager::mYaw + yawAdd;
curMove.roll = MoveManager::mRoll + rollAdd;
MoveManager::mPitch = 0;
MoveManager::mYaw = 0;
MoveManager::mRoll = 0;
curMove.x = MoveManager::mRightAction - MoveManager::mLeftAction + MoveManager::mXAxis_L;
curMove.y = MoveManager::mForwardAction - MoveManager::mBackwardAction + MoveManager::mYAxis_L;
curMove.z = MoveManager::mUpAction - MoveManager::mDownAction;
curMove.freeLook = MoveManager::mFreeLook;
curMove.deviceIsKeyboardMouse = MoveManager::mDeviceIsKeyboardMouse;
for(U32 i = 0; i < MaxTriggerKeys; i++)
{
curMove.trigger[i] = false;
if(MoveManager::mTriggerCount[i] & 1)
curMove.trigger[i] = true;
else if(!(MoveManager::mPrevTriggerCount[i] & 1) && MoveManager::mPrevTriggerCount[i] != MoveManager::mTriggerCount[i])
curMove.trigger[i] = true;
MoveManager::mPrevTriggerCount[i] = MoveManager::mTriggerCount[i];
}
for(U32 i=0; i<ExtendedMove::MaxPositionsRotations; ++i)
{
// Process position
curMove.posX[i] = ExtendedMoveManager::mPosX[i];
curMove.posY[i] = ExtendedMoveManager::mPosY[i];
curMove.posZ[i] = ExtendedMoveManager::mPosZ[i];
// Process rotation. There are two possible forms of rotation: Angle Axis and Euler angles.
curMove.EulerBasedRotation[i] = ExtendedMoveManager::mRotIsEuler[i];
if(curMove.EulerBasedRotation[i])
{
// Euler angle based rotation passed in as degrees. We only need to work with three components.
curMove.rotX[i] = mDegToRad(ExtendedMoveManager::mRotAX[i]);
curMove.rotY[i] = mDegToRad(ExtendedMoveManager::mRotAY[i]);
curMove.rotZ[i] = mDegToRad(ExtendedMoveManager::mRotAZ[i]);
}
else
{
//Rotation is passed in as an Angle Axis in degrees. We need to convert this into a Quat.
QuatF q(Point3F(ExtendedMoveManager::mRotAX[i], ExtendedMoveManager::mRotAY[i], ExtendedMoveManager::mRotAZ[i]), mDegToRad(ExtendedMoveManager::mRotAA[i]));
curMove.rotX[i] = q.x;
curMove.rotY[i] = q.y;
curMove.rotZ[i] = q.z;
curMove.rotW[i] = q.w;
}
}
if (mConnection->getControlObject())
mConnection->getControlObject()->preprocessMove(&curMove);
curMove.clamp(); // clamp for net traffic
return true;
}
U32 ExtendedMoveList::getMoves(Move** movePtr,U32* numMoves)
{
// We don't want to be here
AssertFatal(0, "getMoves() called");
numMoves = 0;
return 0;
}
U32 ExtendedMoveList::getExtMoves( ExtendedMove** movePtr, U32 *numMoves )
{
if (!mConnection->isConnectionToServer())
{
if (mExtMoveVec.size() > mMoveCredit)
mExtMoveVec.setSize(mMoveCredit);
}
// From MoveList but converted to use mExtMoveVec
if (mConnection->isConnectionToServer())
{
// give back moves starting at the last client move...
AssertFatal(mLastClientMove >= mFirstMoveIndex, "Bad move request");
AssertFatal(mLastClientMove - mFirstMoveIndex <= mExtMoveVec.size(), "Desynched first and last move.");
*numMoves = mExtMoveVec.size() - mLastClientMove + mFirstMoveIndex;
*movePtr = mExtMoveVec.address() + mLastClientMove - mFirstMoveIndex;
}
else
{
// return the full list
*numMoves = mExtMoveVec.size();
*movePtr = mExtMoveVec.begin();
}
return *numMoves;
}
void ExtendedMoveList::collectMove()
{
ExtendedMove mv;
if (mConnection)
{
if(!mConnection->isPlayingBack() && getNextExtMove(mv))
{
mv.checksum=Move::ChecksumMismatch;
pushMove(mv);
mConnection->recordBlock(GameConnection::BlockTypeMove, sizeof(ExtendedMove), &mv);
}
}
else
{
if(getNextExtMove(mv))
{
mv.checksum=Move::ChecksumMismatch;
pushMove(mv);
}
}
}
void ExtendedMoveList::pushMove(const Move &mv)
{
const ExtendedMove* extMove = dynamic_cast<const ExtendedMove*>(&mv);
AssertFatal(extMove, "Regular Move struct passed to pushMove()");
pushExtMove(*extMove);
}
void ExtendedMoveList::pushExtMove( const ExtendedMove &mv )
{
U32 id = mFirstMoveIndex + mExtMoveVec.size();
U32 sz = mExtMoveVec.size();
mExtMoveVec.push_back(mv);
mExtMoveVec[sz].id = id;
mExtMoveVec[sz].sendCount = 0;
}
void ExtendedMoveList::clearMoves(U32 count)
{
if (!mConnection->isConnectionToServer())
{
count = mClamp(count,0,mMoveCredit);
mMoveCredit -= count;
}
// From MoveList but converted to use mExtMoveVec
if (mConnection->isConnectionToServer())
{
mLastClientMove += count;
AssertFatal(mLastClientMove >= mFirstMoveIndex, "Bad move request");
AssertFatal(mLastClientMove - mFirstMoveIndex <= mExtMoveVec.size(), "Desynched first and last move.");
if (!mConnection)
// drop right away if no connection
ackMoves(count);
}
else
{
AssertFatal(count <= mExtMoveVec.size(),"GameConnection: Clearing too many moves");
for (S32 i=0; i<count; i++)
if (mExtMoveVec[i].checksum == Move::ChecksumMismatch)
mControlMismatch = true;
else
mControlMismatch = false;
if (count == mExtMoveVec.size())
mExtMoveVec.clear();
else
while (count--)
mExtMoveVec.pop_front();
}
}
void ExtendedMoveList::advanceMove()
{
AssertFatal(!mConnection->isConnectionToServer(), "Cannot inc move credit on the client.");
// Game tick increment
mMoveCredit++;
if (mMoveCredit > MaxMoveCount)
mMoveCredit = MaxMoveCount;
// Clear pending moves for the elapsed time if there
// is no control object.
if ( mConnection->getControlObject() == NULL )
mExtMoveVec.clear();
}
void ExtendedMoveList::clientWriteMovePacket(BitStream *bstream)
{
AssertFatal(mLastMoveAck == mFirstMoveIndex, "Invalid move index.");
U32 count = mExtMoveVec.size();
ExtendedMove* extMove = mExtMoveVec.address();
U32 start = mLastMoveAck;
U32 offset;
for(offset = 0; offset < count; offset++)
if(extMove[offset].sendCount < MAX_MOVE_PACKET_SENDS)
break;
if(offset == count && count != 0)
offset--;
start += offset;
count -= offset;
if (count > MaxMoveCount)
count = MaxMoveCount;
bstream->writeInt(start,32);
bstream->writeInt(count,MoveCountBits);
ExtendedMove* prevExtMove = NULL;
for (int i = 0; i < count; i++)
{
extMove[offset + i].sendCount++;
extMove[offset + i].pack(bstream,prevExtMove);
bstream->writeInt(extMove[offset + i].checksum & (~(0xFFFFFFFF << Move::ChecksumBits)),Move::ChecksumBits);
prevExtMove = &extMove[offset+i];
}
}
void ExtendedMoveList::serverReadMovePacket(BitStream *bstream)
{
// Server side packet read.
U32 start = bstream->readInt(32);
U32 count = bstream->readInt(MoveCountBits);
ExtendedMove* prevExtMove = NULL;
ExtendedMove prevExtMoveHolder;
// Skip forward (must be starting up), or over the moves
// we already have.
int skip = mLastMoveAck - start;
if (skip < 0)
{
mLastMoveAck = start;
}
else
{
if (skip > count)
skip = count;
for (int i = 0; i < skip; i++)
{
prevExtMoveHolder.unpack(bstream,prevExtMove);
prevExtMoveHolder.checksum = bstream->readInt(Move::ChecksumBits);
prevExtMove = &prevExtMoveHolder;
S32 idx = mExtMoveVec.size()-skip+i;
if (idx>=0)
{
#ifdef TORQUE_DEBUG_NET_MOVES
if (mExtMoveVec[idx].checksum != prevExtMoveHolder.checksum)
Con::printf("updated checksum on move %i from %i to %i",mExtMoveVec[idx].id,mExtMoveVec[idx].checksum,prevExtMoveHolder.checksum);
#endif
mExtMoveVec[idx].checksum = prevExtMoveHolder.checksum;
}
}
start += skip;
count = count - skip;
}
// Put the rest on the move list.
int index = mExtMoveVec.size();
mExtMoveVec.increment(count);
while (index < mExtMoveVec.size())
{
mExtMoveVec[index].unpack(bstream,prevExtMove);
mExtMoveVec[index].checksum = bstream->readInt(Move::ChecksumBits);
prevExtMove = &mExtMoveVec[index];
mExtMoveVec[index].id = start++;
index ++;
}
mLastMoveAck += count;
}
void ExtendedMoveList::serverWriteMovePacket(BitStream * bstream)
{
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("ack %i minus %i",mLastMoveAck,mExtMoveVec.size());
#endif
// acknowledge only those moves that have been ticked
bstream->writeInt(mLastMoveAck - mExtMoveVec.size(),32);
}
void ExtendedMoveList::clientReadMovePacket(BitStream * bstream)
{
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("pre move ack: %i", mLastMoveAck);
#endif
mLastMoveAck = bstream->readInt(32);
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("post move ack %i, first move %i, last move %i", mLastMoveAck, mFirstMoveIndex, mLastClientMove);
#endif
if (mLastMoveAck < mFirstMoveIndex)
mLastMoveAck = mFirstMoveIndex;
if(mLastMoveAck > mLastClientMove)
mLastClientMove = mLastMoveAck;
while(mFirstMoveIndex < mLastMoveAck)
{
if (mExtMoveVec.size())
{
mExtMoveVec.pop_front();
mFirstMoveIndex++;
}
else
{
AssertWarn(1, "Popping off too many moves!");
mFirstMoveIndex = mLastMoveAck;
}
}
}
bool ExtendedMoveList::isBacklogged()
{
if ( !mConnection->isConnectionToServer() )
return false;
return mLastClientMove - mFirstMoveIndex == mExtMoveVec.size() &&
mExtMoveVec.size() >= MaxMoveCount;
}
bool ExtendedMoveList::areMovesPending()
{
return mConnection->isConnectionToServer() ?
mExtMoveVec.size() - mLastClientMove + mFirstMoveIndex :
mExtMoveVec.size();
}
void ExtendedMoveList::ackMoves(U32 count)
{
mLastMoveAck += count;
if(mLastMoveAck > mLastClientMove)
mLastClientMove = mLastMoveAck;
while(mFirstMoveIndex < mLastMoveAck)
{
if (mExtMoveVec.size())
{
mExtMoveVec.pop_front();
mFirstMoveIndex++;
}
else
{
AssertWarn(1, "Popping off too many moves!");
mFirstMoveIndex = mLastMoveAck;
}
}
}

View file

@ -0,0 +1,55 @@
#ifndef _EXTENDEDMOVELIST_H_
#define _EXTENDEDMOVELIST_H_
#ifndef _TVECTOR_H_
#include "core/util/tVector.h"
#endif
#ifndef _MOVELIST_H_
#include "T3D/gameBase/moveList.h"
#endif
#include "T3D/gameBase/extended/extendedMove.h"
class ExtendedMoveList : public MoveList
{
typedef MoveList Parent;
public:
ExtendedMoveList();
void clientWriteMovePacket(BitStream *);
void clientReadMovePacket(BitStream *);
void serverWriteMovePacket(BitStream *);
void serverReadMovePacket(BitStream *);
void advanceMove();
void onAdvanceObjects() {}
U32 getMoves(Move** movePtr,U32* numMoves);
U32 getExtMoves( ExtendedMove** movePtr, U32 *numMoves );
void collectMove();
void pushMove( const Move &mv );
void pushExtMove( const ExtendedMove &mv );
void clearMoves( U32 count );
virtual void reset();
bool isBacklogged();
bool areMovesPending();
void ackMoves( U32 count );
protected:
U32 mMoveCredit;
Vector<ExtendedMove> mExtMoveVec;
protected:
bool getNextExtMove( ExtendedMove &curMove );
};
#endif // _EXTENDEDMOVELIST_H_

View file

@ -614,7 +614,7 @@ void GameBase::onUnmount( SceneObject *obj, S32 node )
bool GameBase::setDataBlockProperty( void *obj, const char *index, const char *db)
{
if( db == NULL || !db || !db[ 0 ] )
if( db == NULL || !db[ 0 ] )
{
Con::errorf( "GameBase::setDataBlockProperty - Can't unset datablock on GameBase objects" );
return false;

View file

@ -409,8 +409,8 @@ public:
virtual bool isValidCameraFov( F32 fov ) { return true; }
virtual bool useObjsEyePoint() const { return false; }
virtual bool onlyFirstPerson() const { return false; }
virtual F32 getDamageFlash() const { return 1.0f; }
virtual F32 getWhiteOut() const { return 1.0f; }
virtual F32 getDamageFlash() const { return 0.0f; }
virtual F32 getWhiteOut() const { return 0.0f; }
// Not implemented here, but should return the Camera to world transformation matrix
virtual void getCameraTransform (F32 *pos, MatrixF *mat ) { *mat = MatrixF::Identity; }

View file

@ -41,6 +41,8 @@
#ifdef TORQUE_HIFI_NET
#include "T3D/gameBase/hifi/hifiMoveList.h"
#elif defined TORQUE_EXTENDED_MOVE
#include "T3D/gameBase/extended/extendedMoveList.h"
#else
#include "T3D/gameBase/std/stdMoveList.h"
#endif
@ -175,6 +177,8 @@ GameConnection::GameConnection()
#ifdef TORQUE_HIFI_NET
mMoveList = new HifiMoveList();
#elif defined TORQUE_EXTENDED_MOVE
mMoveList = new ExtendedMoveList();
#else
mMoveList = new StdMoveList();
#endif
@ -215,6 +219,14 @@ GameConnection::GameConnection()
// first person
mFirstPerson = true;
mUpdateFirstPerson = false;
// Control scheme
mUpdateControlScheme = false;
mAbsoluteRotation = false;
mAddYawToAbsRot = false;
mAddPitchToAbsRot = false;
clearDisplayDevice();
}
GameConnection::~GameConnection()
@ -740,7 +752,15 @@ void GameConnection::setFirstPerson(bool firstPerson)
mUpdateFirstPerson = true;
}
//----------------------------------------------------------------------------
void GameConnection::setControlSchemeParameters(bool absoluteRotation, bool addYawToAbsRot, bool addPitchToAbsRot)
{
mAbsoluteRotation = absoluteRotation;
mAddYawToAbsRot = addYawToAbsRot;
mAddPitchToAbsRot = addPitchToAbsRot;
mUpdateControlScheme = true;
}
//----------------------------------------------------------------------------
@ -823,6 +843,11 @@ void GameConnection::writeDemoStartBlock(ResizeBitStream *stream)
stream->write(mCameraPos);
stream->write(mCameraSpeed);
// Control scheme
stream->write(mAbsoluteRotation);
stream->write(mAddYawToAbsRot);
stream->write(mAddPitchToAbsRot);
stream->writeString(Con::getVariable("$Client::MissionFile"));
mMoveList->writeDemoStartBlock(stream);
@ -899,6 +924,11 @@ bool GameConnection::readDemoStartBlock(BitStream *stream)
stream->read(&mCameraPos);
stream->read(&mCameraSpeed);
// Control scheme
stream->read(&mAbsoluteRotation);
stream->read(&mAddYawToAbsRot);
stream->read(&mAddPitchToAbsRot);
char buf[256];
stream->readString(buf);
Con::setVariable("$Client::MissionFile",buf);
@ -1075,6 +1105,16 @@ void GameConnection::readPacket(BitStream *bstream)
else
setCameraObject(0);
// server changed control scheme
if(bstream->readFlag())
{
bool absoluteRotation = bstream->readFlag();
bool addYawToAbsRot = bstream->readFlag();
bool addPitchToAbsRot = bstream->readFlag();
setControlSchemeParameters(absoluteRotation, addYawToAbsRot, addPitchToAbsRot);
mUpdateControlScheme = false;
}
// server changed first person
if(bstream->readFlag())
{
@ -1105,6 +1145,16 @@ void GameConnection::readPacket(BitStream *bstream)
if (bstream->readFlag())
mControlForceMismatch = true;
// client changed control scheme
if(bstream->readFlag())
{
bool absoluteRotation = bstream->readFlag();
bool addYawToAbsRot = bstream->readFlag();
bool addPitchToAbsRot = bstream->readFlag();
setControlSchemeParameters(absoluteRotation, addYawToAbsRot, addPitchToAbsRot);
mUpdateControlScheme = false;
}
// client changed first person
if(bstream->readFlag())
{
@ -1167,6 +1217,15 @@ void GameConnection::writePacket(BitStream *bstream, PacketNotify *note)
}
bstream->writeFlag(forceUpdate);
// Control scheme changed?
if(bstream->writeFlag(mUpdateControlScheme))
{
bstream->writeFlag(mAbsoluteRotation);
bstream->writeFlag(mAddYawToAbsRot);
bstream->writeFlag(mAddPitchToAbsRot);
mUpdateControlScheme = false;
}
// first person changed?
if(bstream->writeFlag(mUpdateFirstPerson))
{
@ -1255,6 +1314,15 @@ void GameConnection::writePacket(BitStream *bstream, PacketNotify *note)
else
bstream->writeFlag( false );
// Control scheme changed?
if(bstream->writeFlag(mUpdateControlScheme))
{
bstream->writeFlag(mAbsoluteRotation);
bstream->writeFlag(mAddYawToAbsRot);
bstream->writeFlag(mAddPitchToAbsRot);
mUpdateControlScheme = false;
}
// first person changed?
if(bstream->writeFlag(mUpdateFirstPerson))
{
@ -1727,6 +1795,13 @@ DefineEngineMethod( GameConnection, setControlObject, bool, (GameBase* ctrlObj),
return true;
}
DefineEngineMethod( GameConnection, clearDisplayDevice, void, (),,
"@brief Clear any display device.\n\n"
"A display device may define a number of properties that are used during rendering.\n\n")
{
object->clearDisplayDevice();
}
DefineEngineMethod( GameConnection, getControlObject, GameBase*, (),,
"@brief On the server, returns the object that the client is controlling."
"By default the control object is an instance of the Player class, but can also be an instance "
@ -2105,3 +2180,21 @@ DefineEngineMethod( GameConnection, setFirstPerson, void, (bool firstPerson),,
{
object->setFirstPerson(firstPerson);
}
DefineEngineMethod( GameConnection, setControlSchemeParameters, void, (bool absoluteRotation, bool addYawToAbsRot, bool addPitchToAbsRot),,
"@brief Set the control scheme that may be used by a connection's control object.\n\n"
"@param absoluteRotation Use absolute rotation values from client, likely through ExtendedMove.\n"
"@param addYawToAbsRot Add relative yaw control to the absolute rotation calculation. Only useful when absoluteRotation is true.\n\n" )
{
object->setControlSchemeParameters(absoluteRotation, addYawToAbsRot, addPitchToAbsRot);
}
DefineEngineMethod( GameConnection, getControlSchemeAbsoluteRotation, bool, (),,
"@brief Get the connection's control scheme absolute rotation property.\n\n"
"@return True if the connection's control object should use an absolute rotation control scheme.\n\n"
"@see GameConnection::setControlSchemeParameters()\n\n")
{
return object->getControlSchemeAbsoluteRotation();
}

View file

@ -45,6 +45,7 @@ enum GameConnectionConstants
DataBlockQueueCount = 16
};
class IDisplayDevice;
class SFXProfile;
class MatrixF;
class MatrixF;
@ -86,6 +87,16 @@ private:
F32 mCameraFov; ///< Current camera fov (in degrees).
F32 mCameraPos; ///< Current camera pos (0-1).
F32 mCameraSpeed; ///< Camera in/out speed.
IDisplayDevice* mDisplayDevice; ///< Optional client display device that imposes rendering properties.
/// @}
/// @name Client side control scheme that may be referenced by control objects
/// @{
bool mUpdateControlScheme; ///< Set to notify client or server of control scheme change
bool mAbsoluteRotation; ///< Use absolute rotation values from client, likely through ExtendedMove
bool mAddYawToAbsRot; ///< Add relative yaw control to the absolute rotation calculation. Only useful with mAbsoluteRotation.
bool mAddPitchToAbsRot; ///< Add relative pitch control to the absolute rotation calculation. Only useful with mAbsoluteRotation.
/// @}
public:
@ -263,6 +274,16 @@ public:
void setFirstPerson(bool firstPerson);
bool hasDisplayDevice() const { return mDisplayDevice != NULL; }
const IDisplayDevice* getDisplayDevice() const { return mDisplayDevice; }
void setDisplayDevice(IDisplayDevice* display) { mDisplayDevice = display; }
void clearDisplayDevice() { mDisplayDevice = NULL; }
void setControlSchemeParameters(bool absoluteRotation, bool addYawToAbsRot, bool addPitchToAbsRot);
bool getControlSchemeAbsoluteRotation() {return mAbsoluteRotation;}
bool getControlSchemeAddYawToAbsRot() {return mAddYawToAbsRot;}
bool getControlSchemeAddPitchToAbsRot() {return mAddPitchToAbsRot;}
/// @}
void detectLag();

View file

@ -76,8 +76,8 @@ public:
/// Reset move list back to last acknowledged move.
void resetCatchup() { mLastClientMove = mLastMoveAck; }
void collectMove();
void pushMove( const Move &mv );
virtual void collectMove();
virtual void pushMove( const Move &mv );
virtual void clearMoves( U32 count );
virtual void markControlDirty() { mLastClientMove = mLastMoveAck; }
@ -85,15 +85,15 @@ public:
void clearMismatch() { mControlMismatch = false; }
/// Clear out all moves in the list and reset to initial state.
void reset();
virtual void reset();
/// If there are no pending moves and the input queue is full,
/// then the connection to the server must be clogged.
bool isBacklogged();
virtual bool isBacklogged();
bool areMovesPending();
virtual bool areMovesPending();
void ackMoves( U32 count );
virtual void ackMoves( U32 count );
protected:

View file

@ -66,20 +66,7 @@ F32 MoveManager::mYAxis_R = 0;
U32 MoveManager::mTriggerCount[MaxTriggerKeys] = { 0, };
U32 MoveManager::mPrevTriggerCount[MaxTriggerKeys] = { 0, };
const Move NullMove =
{
/*px=*/16, /*py=*/16, /*pz=*/16,
/*pyaw=*/0, /*ppitch=*/0, /*proll=*/0,
/*x=*/0, /*y=*/0,/*z=*/0,
/*yaw=*/0, /*pitch=*/0, /*roll=*/0,
/*id=*/0,
/*sendCount=*/0,
/*checksum=*/false,
/*deviceIsKeyboardMouse=*/false,
/*freeLook=*/false,
/*triggers=*/{false,false,false,false,false,false}
};
const Move NullMove;
void MoveManager::init()
{
@ -161,6 +148,26 @@ void MoveManager::init()
}
}
Move::Move()
{
px=16; py=16; pz=16;
pyaw=0; ppitch=0; proll=0;
x=0; y=0; z=0;
yaw=0; pitch=0; roll=0;
id=0;
sendCount=0;
checksum = false;
deviceIsKeyboardMouse = false;
freeLook = false;
trigger[0] = false;
trigger[1] = false;
trigger[2] = false;
trigger[3] = false;
trigger[4] = false;
trigger[5] = false;
}
static inline F32 clampFloatWrap(F32 val)
{
return val - F32(S32(val));
@ -235,6 +242,11 @@ void Move::pack(BitStream *stream, const Move * basemove)
if (!basemove)
basemove = &NullMove;
packMove(stream, basemove, alwaysWriteAll);
}
bool Move::packMove(BitStream *stream, const Move* basemove, bool alwaysWriteAll)
{
S32 i;
bool triggerDifferent = false;
for (i=0; i < MaxTriggerKeys; i++)
@ -272,6 +284,8 @@ void Move::pack(BitStream *stream, const Move * basemove)
for(i = 0; i < MaxTriggerKeys; i++)
stream->writeFlag(trigger[i]);
}
return (triggerDifferent || somethingDifferent);
}
void Move::unpack(BitStream *stream, const Move * basemove)
@ -280,7 +294,20 @@ void Move::unpack(BitStream *stream, const Move * basemove)
if (!basemove)
basemove=&NullMove;
if (alwaysReadAll || stream->readFlag())
bool readMove = unpackMove(stream, basemove, alwaysReadAll);
if(!readMove)
*this = *basemove;
}
bool Move::unpackMove(BitStream *stream, const Move* basemove, bool alwaysReadAll)
{
bool readMove = alwaysReadAll;
if(!readMove)
{
readMove = stream->readFlag();
}
if (readMove)
{
pyaw = stream->readFlag() ? stream->readInt(16) : basemove->pyaw;
ppitch = stream->readFlag() ? stream->readInt(16) : basemove->ppitch;
@ -297,6 +324,6 @@ void Move::unpack(BitStream *stream, const Move * basemove)
trigger[i] = triggersDiffer ? stream->readFlag() : basemove->trigger[i];
unclamp();
}
else
*this = *basemove;
return readMove;
}

View file

@ -51,10 +51,16 @@ struct Move
bool freeLook;
bool trigger[MaxTriggerKeys];
void pack(BitStream *stream, const Move * move = NULL);
void unpack(BitStream *stream, const Move * move = NULL);
void clamp();
void unclamp();
Move();
virtual void pack(BitStream *stream, const Move * move = NULL);
virtual void unpack(BitStream *stream, const Move * move = NULL);
virtual void clamp();
virtual void unclamp();
protected:
bool packMove(BitStream *stream, const Move* basemove, bool alwaysWriteAll);
bool unpackMove(BitStream *stream, const Move* basemove, bool alwaysReadAll);
};
extern const Move NullMove;

View file

@ -92,7 +92,7 @@ void StdMoveList::clientWriteMovePacket(BitStream *bstream)
bstream->writeInt(start,32);
bstream->writeInt(count,MoveCountBits);
Move * prevMove = NULL;
for (int i = 0; i < count; i++)
for (S32 i = 0; i < count; i++)
{
move[offset + i].sendCount++;
move[offset + i].pack(bstream,prevMove);
@ -112,7 +112,7 @@ void StdMoveList::serverReadMovePacket(BitStream *bstream)
// Skip forward (must be starting up), or over the moves
// we already have.
int skip = mLastMoveAck - start;
S32 skip = mLastMoveAck - start;
if (skip < 0)
{
mLastMoveAck = start;
@ -121,7 +121,7 @@ void StdMoveList::serverReadMovePacket(BitStream *bstream)
{
if (skip > count)
skip = count;
for (int i = 0; i < skip; i++)
for (S32 i = 0; i < skip; i++)
{
prevMoveHolder.unpack(bstream,prevMove);
prevMoveHolder.checksum = bstream->readInt(Move::ChecksumBits);
@ -141,7 +141,7 @@ void StdMoveList::serverReadMovePacket(BitStream *bstream)
}
// Put the rest on the move list.
int index = mMoveVec.size();
S32 index = mMoveVec.size();
mMoveVec.increment(count);
while (index < mMoveVec.size())
{

View file

@ -32,7 +32,7 @@
#include "math/mEase.h"
#include "core/module.h"
#include "console/engineAPI.h"
#include "platform/output/IDisplayDevice.h"
static void RegisterGameFunctions();
static void Process3D();
@ -82,6 +82,8 @@ static S32 gEaseBack = Ease::Back;
static S32 gEaseBounce = Ease::Bounce;
extern bool gEditingMission;
extern void ShowInit();
//------------------------------------------------------------------------------
@ -143,9 +145,10 @@ ConsoleFunction(containerFindFirst, const char*, 6, 6, "(int mask, Point3F point
//return the first element
sgServerQueryIndex = 0;
char *buff = Con::getReturnBuffer(100);
static const U32 bufSize = 100;
char *buff = Con::getReturnBuffer(bufSize);
if (sgServerQueryList.mList.size())
dSprintf(buff, 100, "%d", sgServerQueryList.mList[sgServerQueryIndex++]->getId());
dSprintf(buff, bufSize, "%d", sgServerQueryList.mList[sgServerQueryIndex++]->getId());
else
buff[0] = '\0';
@ -160,9 +163,10 @@ ConsoleFunction( containerFindNext, const char*, 1, 1, "()"
"@ingroup Game")
{
//return the next element
char *buff = Con::getReturnBuffer(100);
static const U32 bufSize = 100;
char *buff = Con::getReturnBuffer(bufSize);
if (sgServerQueryIndex < sgServerQueryList.mList.size())
dSprintf(buff, 100, "%d", sgServerQueryList.mList[sgServerQueryIndex++]->getId());
dSprintf(buff, bufSize, "%d", sgServerQueryList.mList[sgServerQueryIndex++]->getId());
else
buff[0] = '\0';
@ -354,9 +358,44 @@ bool GameProcessCameraQuery(CameraQuery *query)
sVisDistanceScale = mClampF( sVisDistanceScale, 0.01f, 1.0f );
query->farPlane = gClientSceneGraph->getVisibleDistance() * sVisDistanceScale;
F32 cameraFov;
if(!connection->getControlCameraFov(&cameraFov))
// Provide some default values
query->projectionOffset = Point2F::Zero;
query->eyeOffset = Point3F::Zero;
F32 cameraFov = 0.0f;
bool fovSet = false;
// Try to use the connection's display deivce, if any, but only if the editor
// is not open
if(!gEditingMission && connection->hasDisplayDevice())
{
const IDisplayDevice* display = connection->getDisplayDevice();
// The connection's display device may want to set the FOV
if(display->providesYFOV())
{
cameraFov = mRadToDeg(display->getYFOV());
fovSet = true;
}
// The connection's display device may want to set the projection offset
if(display->providesProjectionOffset())
{
query->projectionOffset = display->getProjectionOffset();
}
// The connection's display device may want to set the eye offset
if(display->providesEyeOffset())
{
query->eyeOffset = display->getEyeOffset();
}
}
// Use the connection's FOV settings if requried
if(!fovSet && !connection->getControlCameraFov(&cameraFov))
{
return false;
}
query->fov = mDegToRad(cameraFov);
return true;
@ -404,7 +443,6 @@ static void RegisterGameFunctions()
Con::setIntVariable("$TypeMasks::StaticObjectType", StaticObjectType);
Con::setIntVariable("$TypeMasks::EnvironmentObjectType", EnvironmentObjectType);
Con::setIntVariable("$TypeMasks::TerrainObjectType", TerrainObjectType);
Con::setIntVariable("$TypeMasks::InteriorObjectType", InteriorObjectType);
Con::setIntVariable("$TypeMasks::WaterObjectType", WaterObjectType);
Con::setIntVariable("$TypeMasks::TriggerObjectType", TriggerObjectType);
Con::setIntVariable("$TypeMasks::MarkerObjectType", MarkerObjectType);

View file

@ -288,11 +288,45 @@ void GroundPlane::buildConvex( const Box3F& box, Convex* convex )
}
}
bool GroundPlane::buildPolyList( PolyListContext context, AbstractPolyList* polyList, const Box3F&, const SphereF& )
bool GroundPlane::buildPolyList( PolyListContext context, AbstractPolyList* polyList, const Box3F& box, const SphereF& )
{
polyList->setObject( this );
polyList->setTransform( &MatrixF::Identity, Point3F( 1.0f, 1.0f, 1.0f ) );
if(context == PLC_Navigation)
{
F32 z = getPosition().z;
Point3F
p0(box.minExtents.x, box.maxExtents.y, z),
p1(box.maxExtents.x, box.maxExtents.y, z),
p2(box.maxExtents.x, box.minExtents.y, z),
p3(box.minExtents.x, box.minExtents.y, z);
// Add vertices to poly list.
U32 v0 = polyList->addPoint(p0);
polyList->addPoint(p1);
polyList->addPoint(p2);
polyList->addPoint(p3);
// Add plane between first three vertices.
polyList->begin(0, 0);
polyList->vertex(v0);
polyList->vertex(v0+1);
polyList->vertex(v0+2);
polyList->plane(v0, v0+1, v0+2);
polyList->end();
// Add plane between last three vertices.
polyList->begin(0, 1);
polyList->vertex(v0+2);
polyList->vertex(v0+3);
polyList->vertex(v0);
polyList->plane(v0+2, v0+3, v0);
polyList->end();
return true;
}
Box3F planeBox = getPlaneBox();
polyList->addBox( planeBox, mMaterial );
@ -318,7 +352,7 @@ void GroundPlane::prepRenderImage( SceneRenderState* state )
PROFILE_SCOPE( GroundPlane_prepRender );
// Update the geometry.
createGeometry( state->getFrustum() );
createGeometry( state->getCullingFrustum() );
if( mVertexBuffer.isNull() )
return;

View file

@ -103,6 +103,7 @@ GuiObjectView::GuiObjectView()
mMountNodeName( "mount0" ),
mMountNode( -1 ),
mCameraSpeed( 0.01f ),
mCameraRotation( 0.0f, 0.0f, 0.0f ),
mLightColor( 1.0f, 1.0f, 1.0f ),
mLightAmbient( 0.5f, 0.5f, 0.5f ),
mLightDirection( 0.f, 0.707f, -0.707f )
@ -182,7 +183,8 @@ void GuiObjectView::initPersistFields()
"Minimum distance below which the camera will not zoom in further." );
addField( "cameraSpeed", TypeF32, Offset( mCameraSpeed, GuiObjectView ),
"Multiplier for mouse camera operations." );
addField( "cameraRotation", TypePoint3F, Offset( mCameraRotation, GuiObjectView ),
"Set the camera rotation." );
endGroup( "Camera" );
Parent::initPersistFields();
@ -205,6 +207,7 @@ void GuiObjectView::onStaticModified( StringTableEntry slotName, const char* new
static StringTableEntry sOrbitDistance = StringTable->insert( "orbitDistance" );
static StringTableEntry sMinOrbitDistance = StringTable->insert( "minOrbitDistance" );
static StringTableEntry sMaxOrbitDistance = StringTable->insert( "maxOrbitDistance" );
static StringTableEntry sCameraRotation = StringTable->insert( "cameraRotation" );
static StringTableEntry sAnimSequence = StringTable->insert( "animSequence" );
if( slotName == sShapeFile )
@ -225,6 +228,8 @@ void GuiObjectView::onStaticModified( StringTableEntry slotName, const char* new
setLightDirection( mLightDirection );
else if( slotName == sOrbitDistance || slotName == sMinOrbitDistance || slotName == sMaxOrbitDistance )
setOrbitDistance( mOrbitDist );
else if( slotName == sCameraRotation )
setCameraRotation( mCameraRotation );
else if( slotName == sAnimSequence )
setObjectAnimation( String( mAnimationSeqName ) );
}
@ -579,6 +584,12 @@ void GuiObjectView::setCameraSpeed( F32 factor )
//------------------------------------------------------------------------------
void GuiObjectView::setCameraRotation( const EulerF& rotation )
{
mCameraRot.set(rotation);
}
//------------------------------------------------------------------------------
void GuiObjectView::setLightColor( const ColorF& color )
{
mLightColor = color;

View file

@ -88,6 +88,7 @@ class GuiObjectView : public GuiTSCtrl
F32 mMaxOrbitDist;
F32 mMinOrbitDist;
EulerF mCameraRotation;
///
F32 mOrbitDist;
@ -245,6 +246,9 @@ class GuiObjectView : public GuiTSCtrl
/// @param distance The distance to set the orbit to (will be clamped).
void setOrbitDistance( F32 distance );
/// Sets the angle of the camera on it's orbit in relation to the object.
void setCameraRotation( const EulerF& rotation );
/// @}
/// @name Lighting

View file

@ -53,8 +53,9 @@ static S32 sMaxWarpTicks = 3; // Max warp duration in ticks
F32 Item::mGravity = -20.0f;
const U32 sClientCollisionMask = (TerrainObjectType |
InteriorObjectType | StaticShapeObjectType |
VehicleObjectType | PlayerObjectType);
StaticShapeObjectType |
VehicleObjectType |
PlayerObjectType);
const U32 sServerCollisionMask = (sClientCollisionMask);
@ -892,7 +893,7 @@ void Item::updatePos(const U32 /*mask*/, const F32 dt)
// Pick the most resistant surface
F32 bd = 0;
const Collision* collision = 0;
for (int c = 0; c < collisionList.getCount(); c++) {
for (S32 c = 0; c < collisionList.getCount(); c++) {
const Collision &cp = collisionList[c];
F32 dot = -mDot(mVelocity,cp.normal);
if (dot > bd) {
@ -1203,7 +1204,7 @@ DefineEngineMethod( Item, isRotating, bool, (),,
return object->isRotating();
}
DefineEngineMethod( Item, setCollisionTimeout, bool, (int ignoreColObj),(NULL),
DefineEngineMethod( Item, setCollisionTimeout, bool, (S32 ignoreColObj),(NULL),
"@brief Temporarily disable collisions against a specific ShapeBase object.\n\n"
"This is useful to prevent a player from immediately picking up an Item they have "
@ -1240,9 +1241,10 @@ DefineEngineMethod( Item, getLastStickyPos, const char*, (),,
"@note Server side only.\n"
)
{
char* ret = Con::getReturnBuffer(256);
static const U32 bufSize = 256;
char* ret = Con::getReturnBuffer(bufSize);
if (object->isServerObject())
dSprintf(ret, 255, "%g %g %g",
dSprintf(ret, bufSize, "%g %g %g",
object->mStickyCollisionPos.x,
object->mStickyCollisionPos.y,
object->mStickyCollisionPos.z);
@ -1262,9 +1264,10 @@ DefineEngineMethod( Item, getLastStickyNormal, const char *, (),,
"@note Server side only.\n"
)
{
char* ret = Con::getReturnBuffer(256);
static const U32 bufSize = 256;
char* ret = Con::getReturnBuffer(bufSize);
if (object->isServerObject())
dSprintf(ret, 255, "%g %g %g",
dSprintf(ret, bufSize, "%g %g %g",
object->mStickyCollisionNormal.x,
object->mStickyCollisionNormal.y,
object->mStickyCollisionNormal.z);

View file

@ -278,7 +278,11 @@ bool LightFlareData::_testVisibility(const SceneRenderState *state, LightFlareSt
// the last result.
const Point3F &lightPos = flareState->lightMat.getPosition();
const RectI &viewport = GFX->getViewport();
bool onScreen = MathUtils::mProjectWorldToScreen( lightPos, outLightPosSS, viewport, GFX->getWorldMatrix(), state->getSceneManager()->getNonClipProjection() );
MatrixF projMatrix;
state->getCameraFrustum().getProjectionMatrix(&projMatrix);
if( state->isReflectPass() )
projMatrix = state->getSceneManager()->getNonClipProjection();
bool onScreen = MathUtils::mProjectWorldToScreen( lightPos, outLightPosSS, viewport, GFX->getWorldMatrix(), projMatrix );
// It is onscreen, so raycast as a simple occlusion test.
const LightInfo *lightInfo = flareState->lightInfo;
@ -452,13 +456,17 @@ void LightFlareData::prepRender( SceneRenderState *state, LightFlareState *flare
Point3F oneOverViewportExtent( 1.0f / (F32)viewport.extent.x, 1.0f / (F32)viewport.extent.y, 0.0f );
// Really convert it to screen space.
lightPosSS.x -= viewport.point.x;
lightPosSS.y -= viewport.point.y;
lightPosSS *= oneOverViewportExtent;
lightPosSS = ( lightPosSS * 2.0f ) - Point3F::One;
lightPosSS.y = -lightPosSS.y;
lightPosSS.z = 0.0f;
Point3F flareVec( -lightPosSS );
// Take any projection offset into account so that the point where the flare's
// elements converge is at the 'eye' point rather than the center of the viewport.
const Point2F& projOffset = state->getCameraFrustum().getProjectionOffset();
Point3F flareVec( -lightPosSS + Point3F(projOffset.x, projOffset.y, 0.0f) );
const F32 flareLength = flareVec.len();
if ( flareLength > 0.0f )
flareVec *= 1.0f / flareLength;

View file

@ -52,6 +52,8 @@ ConsoleDocClass( MissionArea,
RectI MissionArea::smMissionArea(Point2I(768, 768), Point2I(512, 512));
MissionArea * MissionArea::smServerObject = NULL;
//------------------------------------------------------------------------------
MissionArea::MissionArea()
@ -79,27 +81,24 @@ void MissionArea::setArea(const RectI & area)
MissionArea * MissionArea::getServerObject()
{
SimSet * scopeAlwaysSet = Sim::getGhostAlwaysSet();
for(SimSet::iterator itr = scopeAlwaysSet->begin(); itr != scopeAlwaysSet->end(); itr++)
{
MissionArea * ma = dynamic_cast<MissionArea*>(*itr);
if(ma)
{
AssertFatal(ma->isServerObject(), "MissionArea::getServerObject: found client object in ghost always set!");
return(ma);
}
}
return(0);
return smServerObject;
}
//------------------------------------------------------------------------------
bool MissionArea::onAdd()
{
if(isServerObject() && MissionArea::getServerObject())
if(isServerObject())
{
Con::errorf(ConsoleLogEntry::General, "MissionArea::onAdd - MissionArea already instantiated!");
return(false);
if(MissionArea::getServerObject())
{
Con::errorf(ConsoleLogEntry::General, "MissionArea::onAdd - MissionArea already instantiated!");
return(false);
}
else
{
smServerObject = this;
}
}
if(!Parent::onAdd())
@ -109,6 +108,14 @@ bool MissionArea::onAdd()
return(true);
}
void MissionArea::onRemove()
{
if (smServerObject == this)
smServerObject = NULL;
Parent::onRemove();
}
//------------------------------------------------------------------------------
void MissionArea::inspectPostApply()
@ -169,10 +176,11 @@ DefineEngineFunction(getMissionAreaServerObject, MissionArea*, (),,
DefineEngineMethod( MissionArea, getArea, const char *, (),,
"Returns 4 fields: starting x, starting y, extents x, extents y.\n")
{
char* returnBuffer = Con::getReturnBuffer(48);
static const U32 bufSize = 48;
char* returnBuffer = Con::getReturnBuffer(bufSize);
RectI area = object->getArea();
dSprintf(returnBuffer, sizeof(returnBuffer), "%d %d %d %d", area.point.x, area.point.y, area.extent.x, area.extent.y);
dSprintf(returnBuffer, bufSize, "%d %d %d %d", area.point.x, area.point.y, area.extent.x, area.extent.y);
return(returnBuffer);
}

View file

@ -36,6 +36,8 @@ class MissionArea : public NetObject
F32 mFlightCeiling;
F32 mFlightCeilingRange;
static MissionArea * smServerObject;
public:
MissionArea();
@ -53,6 +55,7 @@ class MissionArea : public NetObject
/// @name SimObject Inheritance
/// @{
bool onAdd();
void onRemove();
void inspectPostApply();

View file

@ -304,8 +304,9 @@ ConsoleType( WayPointTeam, TypeWayPointTeam, WayPointTeam )
ConsoleGetType( TypeWayPointTeam )
{
char * buf = Con::getReturnBuffer(32);
dSprintf(buf, 32, "%d", ((WayPointTeam*)dptr)->mTeamId);
static const U32 bufSize = 32;
char * buf = Con::getReturnBuffer(bufSize);
dSprintf(buf, bufSize, "%d", ((WayPointTeam*)dptr)->mTeamId);
return(buf);
}

View file

@ -53,25 +53,21 @@ enum SceneObjectTypes
/// @see TerrainBlock
TerrainObjectType = BIT( 2 ),
/// A legacy DIF interior object.
/// @see InteriorInstance
InteriorObjectType = BIT( 3 ),
/// An object defining a water volume.
/// @see WaterObject
WaterObjectType = BIT( 4 ),
WaterObjectType = BIT( 3 ),
/// An object defining an invisible trigger volume.
/// @see Trigger
TriggerObjectType = BIT( 5 ),
TriggerObjectType = BIT( 4 ),
/// An object defining an invisible marker.
/// @see MissionMarker
MarkerObjectType = BIT( 6 ),
MarkerObjectType = BIT( 5 ),
/// A light emitter.
/// @see LightBase
LightObjectType = BIT( 7 ),
LightObjectType = BIT( 6 ),
/// An object that manages zones. This is automatically set by
/// SceneZoneSpaceManager when a SceneZoneSpace registers zones. Should
@ -79,7 +75,7 @@ enum SceneObjectTypes
///
/// @see SceneZoneSpace
/// @see SceneZoneSpaceManager
ZoneObjectType = BIT( 8 ),
ZoneObjectType = BIT( 7 ),
/// Any object that defines one or more solid, renderable static geometries that
/// should be included in collision and raycasts.
@ -87,13 +83,13 @@ enum SceneObjectTypes
/// Use this mask to find objects that are part of the static level geometry.
///
/// @note If you set this, you will also want to set StaticObjectType.
StaticShapeObjectType = BIT( 9 ),
StaticShapeObjectType = BIT( 8 ),
/// Any object that defines one or more solid, renderable dynamic geometries that
/// should be included in collision and raycasts.
///
/// Use this mask to find objects that are part of the dynamic game geometry.
DynamicShapeObjectType = BIT( 10 ),
DynamicShapeObjectType = BIT( 9 ),
/// @}
@ -102,54 +98,54 @@ enum SceneObjectTypes
/// Any GameBase-derived object.
/// @see GameBase
GameBaseObjectType = BIT( 11 ),
GameBaseObjectType = BIT( 10 ),
/// An object that uses hifi networking.
GameBaseHiFiObjectType = BIT( 12 ),
GameBaseHiFiObjectType = BIT( 11 ),
/// Any ShapeBase-derived object.
/// @see ShapeBase
ShapeBaseObjectType = BIT( 13 ),
ShapeBaseObjectType = BIT( 12 ),
/// A camera object.
/// @see Camera
CameraObjectType = BIT( 14 ),
CameraObjectType = BIT( 13 ),
/// A human or AI player object.
/// @see Player
PlayerObjectType = BIT( 15 ),
PlayerObjectType = BIT( 14 ),
/// An item pickup.
/// @see Item
ItemObjectType = BIT( 16 ),
ItemObjectType = BIT( 15 ),
/// A vehicle.
/// @see Vehicle
VehicleObjectType = BIT( 17 ),
VehicleObjectType = BIT( 16 ),
/// An object that blocks vehicles.
/// @see VehicleBlocker
VehicleBlockerObjectType = BIT( 18 ),
VehicleBlockerObjectType = BIT( 17 ),
/// A weapon projectile.
/// @see Projectile
ProjectileObjectType = BIT( 19 ),
ProjectileObjectType = BIT( 18 ),
/// An explosion object.
/// @see Explosion
ExplosionObjectType = BIT( 20 ),
ExplosionObjectType = BIT( 19 ),
/// A dead player. This is dynamically set and unset.
/// @see Player
CorpseObjectType = BIT( 21 ),
CorpseObjectType = BIT( 20 ),
/// A debris object.
/// @see Debris
DebrisObjectType = BIT( 22 ),
DebrisObjectType = BIT( 21 ),
/// A volume that asserts forces on player objects.
/// @see PhysicalZone
PhysicalZoneObjectType = BIT( 23 ),
PhysicalZoneObjectType = BIT( 22 ),
/// @}
};
@ -173,8 +169,7 @@ enum SceneObjectTypeMasks
///
/// Also, objects that do their own culling internally (terrains, forests, etc.)
/// should be excluded.
CULLING_INCLUDE_TYPEMASK = ( InteriorObjectType |
GameBaseObjectType | // Includes most other renderable types; but broader than we ideally want.
CULLING_INCLUDE_TYPEMASK = ( GameBaseObjectType | // Includes most other renderable types; but broader than we ideally want.
StaticShapeObjectType |
DynamicShapeObjectType |
ZoneObjectType ), // This improves the result of zone traversals.
@ -200,7 +195,6 @@ enum SceneObjectTypeMasks
///
/// @note Terrains have their own means for rendering inside interior zones.
OUTDOOR_OBJECT_TYPEMASK = ( TerrainObjectType |
InteriorObjectType |
EnvironmentObjectType )
};

View file

@ -429,7 +429,7 @@ U32 PathCamera::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
if (stream->writeFlag(mask & WindowMask)) {
stream->write(mNodeBase);
stream->write(mNodeCount);
for (int i = 0; i < mNodeCount; i++) {
for (S32 i = 0; i < mNodeCount; i++) {
CameraSpline::Knot *knot = mSpline.getKnot(i);
mathWrite(*stream, knot->mPosition);
mathWrite(*stream, knot->mRotation);
@ -477,7 +477,7 @@ void PathCamera::unpackUpdate(NetConnection *con, BitStream *stream)
mSpline.removeAll();
stream->read(&mNodeBase);
stream->read(&mNodeCount);
for (int i = 0; i < mNodeCount; i++)
for (S32 i = 0; i < mNodeCount; i++)
{
CameraSpline::Knot *knot = new CameraSpline::Knot();
mathRead(*stream, &knot->mPosition);

View file

@ -83,7 +83,7 @@ private:
S32 mNodeBase;
S32 mNodeCount;
F32 mPosition;
int mState;
S32 mState;
F32 mTarget;
bool mTargetSet;

View file

@ -24,7 +24,7 @@
#define _BULLET_H_
// NOTE: We set these defines which bullet needs here.
#ifdef TORQUE_OS_WIN32
#ifdef TORQUE_OS_WIN
#define WIN32
#endif

View file

@ -335,16 +335,22 @@ void BtBody::applyImpulse( const Point3F &origin, const Point3F &force )
AssertFatal( mActor, "BtBody::applyImpulse - The actor is null!" );
AssertFatal( isDynamic(), "BtBody::applyImpulse - This call is only for dynamics!" );
// Convert the world position to local
MatrixF trans = btCast<MatrixF>( mActor->getCenterOfMassTransform() );
trans.inverse();
Point3F localOrigin( origin );
trans.mulP( localOrigin );
if ( mCenterOfMass )
{
Point3F relOrigin( origin );
Point3F relOrigin( localOrigin );
mCenterOfMass->mulP( relOrigin );
Point3F relForce( force );
mCenterOfMass->mulV( relForce );
mActor->applyImpulse( btCast<btVector3>( relForce ), btCast<btVector3>( relOrigin ) );
}
else
mActor->applyImpulse( btCast<btVector3>( force ), btCast<btVector3>( origin ) );
mActor->applyImpulse( btCast<btVector3>( force ), btCast<btVector3>( localOrigin ) );
if ( !mActor->isActive() )
mActor->activate();

View file

@ -286,7 +286,7 @@ void BtWorld::explosion( const Point3F &pos, F32 radius, F32 forceMagnitude )
void BtWorld::onDebugDraw( const SceneRenderState *state )
{
mDebugDraw.setCuller( &state->getFrustum() );
mDebugDraw.setCuller( &state->getCullingFrustum() );
mDynamicsWorld->setDebugDrawer( &mDebugDraw );
mDynamicsWorld->debugDrawWorld();

View file

@ -311,7 +311,8 @@ PhysicsDebris* PhysicsDebris::create( PhysicsDebrisData *datablock,
}
PhysicsDebris::PhysicsDebris()
: mLifetime( 0.0f ),
: mDataBlock( NULL ),
mLifetime( 0.0f ),
mShapeInstance( NULL ),
mWorld( NULL ),
mInitialLinVel( Point3F::Zero )
@ -342,6 +343,12 @@ bool PhysicsDebris::onAdd()
if ( !Parent::onAdd() )
return false;
if( !mDataBlock )
{
Con::errorf("PhysicsDebris::onAdd - Fail - No datablock");
return false;
}
// If it has a fixed lifetime then calculate it.
if ( mDataBlock->lifetime > 0.0f )
{

View file

@ -41,6 +41,7 @@
#include "lighting/lightQuery.h"
#include "console/engineAPI.h"
using namespace Torque;
bool PhysicsShape::smNoCorrections = false;
bool PhysicsShape::smNoSmoothing = false;
@ -240,7 +241,7 @@ void PhysicsShapeData::onRemove()
void PhysicsShapeData::_onResourceChanged( const Torque::Path &path )
{
if ( path != Path( shapeName ) )
if ( path != Path( shapeName ) )
return;
// Reload the changed shape.

View file

@ -46,7 +46,7 @@
#define __APPLE__
#elif defined(TORQUE_OS_LINUX) && !defined(LINUX)
#define LINUX
#elif defined(TORQUE_OS_WIN32) && !defined(WIN32)
#elif defined(TORQUE_OS_WIN) && !defined(WIN32)
#define WIN32
#endif

View file

@ -527,7 +527,7 @@ bool PxMultiActorData::preload( bool server, String &errorBuffer )
return false;
}
if (!shapeName || shapeName == '\0')
if (!shapeName || shapeName[0] == '\0')
{
errorBuffer = "PxMultiActorDatas::preload: no shape name!";
return false;
@ -570,7 +570,7 @@ bool PxMultiActorData::preload( bool server, String &errorBuffer )
// Register for file change notification to reload the collection
if ( server )
FS::AddChangeNotification( physXStream, this, &PxMultiActorData::_onFileChanged );
Torque::FS::AddChangeNotification( physXStream, this, &PxMultiActorData::_onFileChanged );
return true;
}
@ -2648,4 +2648,4 @@ ConsoleMethod( PxMultiActorData, reload, void, 2, 2, ""
"If the reload sucessfully completes, all PxMultiActor's will be notified.\n\n")
{
object->reload();
}
}

View file

@ -39,7 +39,7 @@ AFTER_MODULE_INIT( Sim )
{
NamedFactory<PhysicsPlugin>::add( "PhysX", &PxPlugin::create );
#if defined(TORQUE_OS_WIN32) || defined(TORQUE_OS_XBOX) || defined(TORQUE_OS_XENON)
#if defined(TORQUE_OS_WIN) || defined(TORQUE_OS_XBOX) || defined(TORQUE_OS_XENON)
NamedFactory<PhysicsPlugin>::add( "default", &PxPlugin::create );
#endif

View file

@ -448,9 +448,8 @@ void PxWorld::releaseActor( NxActor &actor )
// Clear the userdata.
actor.userData = NULL;
// If the scene is not simulating then we have the
// write lock and can safely delete it now.
if ( !mIsSimulating )
// actors are one of the few objects that are stable removing this way in physx 2.8
if (mScene->isWritable() )
{
mScene->releaseActor( actor );
}

View file

@ -57,6 +57,10 @@
#include "T3D/decal/decalData.h"
#include "materials/baseMatInstance.h"
#ifdef TORQUE_EXTENDED_MOVE
#include "T3D/gameBase/extended/extendedMove.h"
#endif
// Amount of time if takes to transition to a new action sequence.
static F32 sAnimationTransitionTime = 0.25f;
static bool sUseAnimationTransitions = true;
@ -96,12 +100,13 @@ static F32 sMinWarpTicks = 0.5f; // Fraction of tick at which instant warp
static S32 sMaxWarpTicks = 3; // Max warp duration in ticks
static S32 sMaxPredictionTicks = 30; // Number of ticks to predict
S32 Player::smExtendedMoveHeadPosRotIndex = 0; // The ExtendedMove position/rotation index used for head movements
// Anchor point compression
const F32 sAnchorMaxDistance = 32.0f;
//
static U32 sCollisionMoveMask = TerrainObjectType |
InteriorObjectType |
WaterObjectType |
PlayerObjectType |
StaticShapeObjectType |
@ -123,14 +128,6 @@ enum PlayerConstants {
//----------------------------------------------------------------------------
// Player shape animation sequences:
// look Used to control the upper body arm motion. Must animate
// vertically +-80 deg.
Player::Range Player::mArmRange(mDegToRad(-80.0f),mDegToRad(+80.0f));
// head Used to control the direction the head is looking. Must
// animated vertically +-80 deg .
Player::Range Player::mHeadVRange(mDegToRad(-80.0f),mDegToRad(+80.0f));
// Action Animations:
PlayerData::ActionAnimationDef PlayerData::ActionAnimationList[NumTableActionAnims] =
{
@ -430,9 +427,9 @@ bool PlayerData::preload(bool server, String &errorStr)
{
for( U32 i = 0; i < MaxSounds; ++ i )
{
String errorStr;
if( !sfxResolve( &sound[ i ], errorStr ) )
Con::errorf( "PlayerData::preload: %s", errorStr.c_str() );
String sfxErrorStr;
if( !sfxResolve( &sound[ i ], sfxErrorStr ) )
Con::errorf( "PlayerData::preload: %s", sfxErrorStr.c_str() );
}
}
@ -470,7 +467,7 @@ bool PlayerData::preload(bool server, String &errorStr)
// Extract ground transform velocity from animations
// Get the named ones first so they can be indexed directly.
ActionAnimation *dp = &actionList[0];
for (int i = 0; i < NumTableActionAnims; i++,dp++)
for (S32 i = 0; i < NumTableActionAnims; i++,dp++)
{
ActionAnimationDef *sp = &ActionAnimationList[i];
dp->name = sp->name;
@ -490,12 +487,8 @@ bool PlayerData::preload(bool server, String &errorStr)
dp->death = false;
if (dp->sequence != -1)
getGroundInfo(si,thread,dp);
// No real reason to spam the console about a missing jet animation
if (dStricmp(sp->name, "jet") != 0)
AssertWarn(dp->sequence != -1, avar("PlayerData::preload - Unable to find named animation sequence '%s'!", sp->name));
}
for (int b = 0; b < mShape->sequences.size(); b++)
for (S32 b = 0; b < mShape->sequences.size(); b++)
{
if (!isTableSequence(b))
{
@ -512,7 +505,7 @@ bool PlayerData::preload(bool server, String &errorStr)
// Resolve lookAction index
dp = &actionList[0];
String lookName("look");
for (int c = 0; c < actionCount; c++,dp++)
for (S32 c = 0; c < actionCount; c++,dp++)
if( dStricmp( dp->name, lookName ) == 0 )
lookAction = c;
@ -560,7 +553,7 @@ bool PlayerData::preload(bool server, String &errorStr)
if (!Sim::findObject(dustID, dustEmitter))
Con::errorf(ConsoleLogEntry::General, "PlayerData::preload - Invalid packet, bad datablockId(dustEmitter): 0x%x", dustID);
for (int i=0; i<NUM_SPLASH_EMITTERS; i++)
for (S32 i=0; i<NUM_SPLASH_EMITTERS; i++)
if( !splashEmitterList[i] && splashEmitterIDList[i] != 0 )
if( Sim::findObject( splashEmitterIDList[i], splashEmitterList[i] ) == false)
Con::errorf(ConsoleLogEntry::General, "PlayerData::onAdd - Invalid packet, bad datablockId(particle emitter): 0x%x", splashEmitterIDList[i]);
@ -589,7 +582,10 @@ bool PlayerData::preload(bool server, String &errorStr)
Torque::FS::FileNodeRef fileRef = Torque::FS::GetFileNode(mShapeFP[i].getPath());
if (!fileRef)
{
errorStr = String::ToString("PlayerData: Mounted image %d loading failed, shape \"%s\" is not found.",i,mShapeFP[i].getPath().getFullPath().c_str());
return false;
}
if(server)
mCRCFP[i] = fileRef->getChecksum();
@ -650,7 +646,7 @@ bool PlayerData::isTableSequence(S32 seq)
{
// The sequences from the table must already have
// been loaded for this to work.
for (int i = 0; i < NumTableActionAnims; i++)
for (S32 i = 0; i < NumTableActionAnims; i++)
if (actionList[i].sequence == seq)
return true;
return false;
@ -1650,6 +1646,9 @@ Player::Player()
mShapeFPFlashThread[i] = 0;
mShapeFPSpinThread[i] = 0;
}
mLastAbsoluteYaw = 0.0f;
mLastAbsolutePitch = 0.0f;
}
Player::~Player()
@ -1755,6 +1754,12 @@ void Player::onRemove()
setControlObject(0);
scriptOnRemove();
removeFromScene();
if ( isGhost() )
{
SFX_DELETE( mMoveBubbleSound );
SFX_DELETE( mWaterBreathSound );
}
U32 i;
for( i=0; i<PlayerData::NUM_SPLASH_EMITTERS; i++ )
@ -1938,7 +1943,7 @@ void Player::reSkin()
Vector<String> skins;
String(mSkinNameHandle.getString()).split( ";", skins );
for ( int i = 0; i < skins.size(); i++ )
for ( S32 i = 0; i < skins.size(); i++ )
{
String oldSkin( mAppliedSkinName.c_str() );
String newSkin( skins[i] );
@ -1955,7 +1960,7 @@ void Player::reSkin()
// Apply skin to both 3rd person and 1st person shape instances
mShapeInstance->reSkin( newSkin, oldSkin );
for ( int j = 0; j < ShapeBase::MaxMountedImages; j++ )
for ( S32 j = 0; j < ShapeBase::MaxMountedImages; j++ )
{
if (mShapeFPInstance[j])
mShapeFPInstance[j]->reSkin( newSkin, oldSkin );
@ -2523,38 +2528,130 @@ void Player::updateMove(const Move* move)
F32 prevZRot = mRot.z;
delta.headVec = mHead;
F32 p = move->pitch * (mPose == SprintPose ? mDataBlock->sprintPitchScale : 1.0f);
if (p > M_PI_F)
p -= M_2PI_F;
mHead.x = mClampF(mHead.x + p,mDataBlock->minLookAngle,
mDataBlock->maxLookAngle);
F32 y = move->yaw * (mPose == SprintPose ? mDataBlock->sprintYawScale : 1.0f);
if (y > M_PI_F)
y -= M_2PI_F;
bool doStandardMove = true;
GameConnection* con = getControllingClient();
if (move->freeLook && ((isMounted() && getMountNode() == 0) || (con && !con->isFirstPerson())))
{
mHead.z = mClampF(mHead.z + y,
-mDataBlock->maxFreelookAngle,
mDataBlock->maxFreelookAngle);
}
else
{
mRot.z += y;
// Rotate the head back to the front, center horizontal
// as well if we're controlling another object.
mHead.z *= 0.5f;
if (mControlObject)
mHead.x *= 0.5f;
}
// constrain the range of mRot.z
while (mRot.z < 0.0f)
mRot.z += M_2PI_F;
while (mRot.z > M_2PI_F)
mRot.z -= M_2PI_F;
#ifdef TORQUE_EXTENDED_MOVE
// Work with an absolute rotation from the ExtendedMove class?
if(con && con->getControlSchemeAbsoluteRotation())
{
doStandardMove = false;
const ExtendedMove* emove = dynamic_cast<const ExtendedMove*>(move);
U32 emoveIndex = smExtendedMoveHeadPosRotIndex;
if(emoveIndex >= ExtendedMove::MaxPositionsRotations)
emoveIndex = 0;
if(emove->EulerBasedRotation[emoveIndex])
{
// Head pitch
mHead.x += (emove->rotX[emoveIndex] - mLastAbsolutePitch);
// Do we also include the relative yaw value?
if(con->getControlSchemeAddPitchToAbsRot())
{
F32 x = move->pitch;
if (x > M_PI_F)
x -= M_2PI_F;
mHead.x += x;
}
// Constrain the range of mHead.x
while (mHead.x < -M_PI_F)
mHead.x += M_2PI_F;
while (mHead.x > M_PI_F)
mHead.x -= M_2PI_F;
// Rotate (heading) head or body?
if (move->freeLook && ((isMounted() && getMountNode() == 0) || (con && !con->isFirstPerson())))
{
// Rotate head
mHead.z += (emove->rotZ[emoveIndex] - mLastAbsoluteYaw);
// Do we also include the relative yaw value?
if(con->getControlSchemeAddYawToAbsRot())
{
F32 z = move->yaw;
if (z > M_PI_F)
z -= M_2PI_F;
mHead.z += z;
}
// Constrain the range of mHead.z
while (mHead.z < 0.0f)
mHead.z += M_2PI_F;
while (mHead.z > M_2PI_F)
mHead.z -= M_2PI_F;
}
else
{
// Rotate body
mRot.z += (emove->rotZ[emoveIndex] - mLastAbsoluteYaw);
// Do we also include the relative yaw value?
if(con->getControlSchemeAddYawToAbsRot())
{
F32 z = move->yaw;
if (z > M_PI_F)
z -= M_2PI_F;
mRot.z += z;
}
// Constrain the range of mRot.z
while (mRot.z < 0.0f)
mRot.z += M_2PI_F;
while (mRot.z > M_2PI_F)
mRot.z -= M_2PI_F;
}
mLastAbsoluteYaw = emove->rotZ[emoveIndex];
mLastAbsolutePitch = emove->rotX[emoveIndex];
// Head bank
mHead.y = emove->rotY[emoveIndex];
// Constrain the range of mHead.y
while (mHead.y > M_PI_F)
mHead.y -= M_2PI_F;
}
}
#endif
if(doStandardMove)
{
F32 p = move->pitch * (mPose == SprintPose ? mDataBlock->sprintPitchScale : 1.0f);
if (p > M_PI_F)
p -= M_2PI_F;
mHead.x = mClampF(mHead.x + p,mDataBlock->minLookAngle,
mDataBlock->maxLookAngle);
F32 y = move->yaw * (mPose == SprintPose ? mDataBlock->sprintYawScale : 1.0f);
if (y > M_PI_F)
y -= M_2PI_F;
if (move->freeLook && ((isMounted() && getMountNode() == 0) || (con && !con->isFirstPerson())))
{
mHead.z = mClampF(mHead.z + y,
-mDataBlock->maxFreelookAngle,
mDataBlock->maxFreelookAngle);
}
else
{
mRot.z += y;
// Rotate the head back to the front, center horizontal
// as well if we're controlling another object.
mHead.z *= 0.5f;
if (mControlObject)
mHead.x *= 0.5f;
}
// constrain the range of mRot.z
while (mRot.z < 0.0f)
mRot.z += M_2PI_F;
while (mRot.z > M_2PI_F)
mRot.z -= M_2PI_F;
}
delta.rot = mRot;
delta.rotVec.x = delta.rotVec.y = 0.0f;
@ -2566,6 +2663,13 @@ void Player::updateMove(const Move* move)
delta.head = mHead;
delta.headVec -= mHead;
for(U32 i=0; i<3; ++i)
{
if (delta.headVec[i] > M_PI_F)
delta.headVec[i] -= M_2PI_F;
else if (delta.headVec[i] < -M_PI_F)
delta.headVec[i] += M_2PI_F;
}
}
MatrixF zRot;
zRot.set(EulerF(0.0f, 0.0f, mRot.z));
@ -2757,7 +2861,7 @@ void Player::updateMove(const Move* move)
if (pvl)
pv *= moveSpeed / pvl;
VectorF runAcc = pv - acc;
VectorF runAcc = pv - (mVelocity + acc);
runAcc.z = 0;
runAcc.x = runAcc.x * mDataBlock->airControl;
runAcc.y = runAcc.y * mDataBlock->airControl;
@ -2847,7 +2951,7 @@ void Player::updateMove(const Move* move)
// Clamp acceleration.
F32 maxAcc = (mDataBlock->swimForce / getMass()) * TickSec;
if ( false && swimSpeed > maxAcc )
if ( swimSpeed > maxAcc )
swimAcc *= maxAcc / swimSpeed;
acc += swimAcc;
@ -2993,6 +3097,8 @@ void Player::updateMove(const Move* move)
}
// Container buoyancy & drag
/* Commented out until the buoyancy calculation can be reworked so that a container and
** player with the same density will result in neutral buoyancy.
if (mBuoyancy != 0)
{
// Applying buoyancy when standing still causing some jitters-
@ -3009,9 +3115,10 @@ void Player::updateMove(const Move* move)
if ( currHeight + mVelocity.z * TickSec * C > mLiquidHeight )
buoyancyForce *= M;
//mVelocity.z -= buoyancyForce;
mVelocity.z -= buoyancyForce;
}
}
*/
// Apply drag
if ( mSwimming )
@ -3318,31 +3425,38 @@ void Player::updateDamageState()
//----------------------------------------------------------------------------
void Player::updateLookAnimation(F32 dT)
void Player::updateLookAnimation(F32 dt)
{
// Calculate our interpolated head position.
Point3F renderHead = delta.head + delta.headVec * dT;
Point3F renderHead = delta.head + delta.headVec * dt;
// Adjust look pos. This assumes that the animations match
// the min and max look angles provided in the datablock.
if (mArmAnimation.thread)
{
// TG: Adjust arm position to avoid collision.
F32 tp = mControlObject? 0.5:
(renderHead.x - mArmRange.min) / mArmRange.delta;
mShapeInstance->setPos(mArmAnimation.thread,mClampF(tp,0,1));
if(mControlObject)
{
mShapeInstance->setPos(mArmAnimation.thread,0.5f);
}
else
{
F32 d = mDataBlock->maxLookAngle - mDataBlock->minLookAngle;
F32 tp = (renderHead.x - mDataBlock->minLookAngle) / d;
mShapeInstance->setPos(mArmAnimation.thread,mClampF(tp,0,1));
}
}
if (mHeadVThread)
{
F32 tp = (renderHead.x - mHeadVRange.min) / mHeadVRange.delta;
F32 d = mDataBlock->maxLookAngle - mDataBlock->minLookAngle;
F32 tp = (renderHead.x - mDataBlock->minLookAngle) / d;
mShapeInstance->setPos(mHeadVThread,mClampF(tp,0,1));
}
if (mHeadHThread)
{
F32 dt = 2 * mDataBlock->maxFreelookAngle;
F32 tp = (renderHead.z + mDataBlock->maxFreelookAngle) / dt;
F32 d = 2 * mDataBlock->maxFreelookAngle;
F32 tp = (renderHead.z + mDataBlock->maxFreelookAngle) / d;
mShapeInstance->setPos(mHeadHThread,mClampF(tp,0,1));
}
}
@ -3386,8 +3500,7 @@ void Player::updateDeathOffsets()
//----------------------------------------------------------------------------
static const U32 sPlayerConformMask = InteriorObjectType|StaticShapeObjectType|
StaticObjectType|TerrainObjectType;
static const U32 sPlayerConformMask = StaticShapeObjectType | StaticObjectType | TerrainObjectType;
static void accel(F32& from, F32 to, F32 rate)
{
@ -5259,7 +5372,7 @@ void Player::setTransform(const MatrixF& mat)
void Player::getEyeTransform(MatrixF* mat)
{
getEyeBaseTransform(mat);
getEyeBaseTransform(mat, true);
// The shape instance is animated in getEyeBaseTransform() so we're
// good here when attempting to get the eye node position on the server.
@ -5297,7 +5410,7 @@ void Player::getEyeTransform(MatrixF* mat)
}
}
void Player::getEyeBaseTransform(MatrixF* mat)
void Player::getEyeBaseTransform(MatrixF* mat, bool includeBank)
{
// Eye transform in world space. We only use the eye position
// from the animation and supply our own rotation.
@ -5313,7 +5426,19 @@ void Player::getEyeBaseTransform(MatrixF* mat)
else
zmat.identity();
pmat.mul(zmat,xmat);
if(includeBank && mDataBlock->cameraCanBank)
{
// Take mHead.y into account to bank the camera
MatrixF imat;
imat.mul(zmat, xmat);
MatrixF ymat;
ymat.set(EulerF(0.0f, mHead.y, 0.0f));
pmat.mul(imat, ymat);
}
else
{
pmat.mul(zmat,xmat);
}
F32 *dp = pmat;
@ -5340,7 +5465,7 @@ void Player::getEyeBaseTransform(MatrixF* mat)
void Player::getRenderEyeTransform(MatrixF* mat)
{
getRenderEyeBaseTransform(mat);
getRenderEyeBaseTransform(mat, true);
// Use the first image that is set to use the eye node
for (U32 i=0; i<ShapeBase::MaxMountedImages; ++i)
@ -5369,7 +5494,7 @@ void Player::getRenderEyeTransform(MatrixF* mat)
}
}
void Player::getRenderEyeBaseTransform(MatrixF* mat)
void Player::getRenderEyeBaseTransform(MatrixF* mat, bool includeBank)
{
// Eye transform in world space. We only use the eye position
// from the animation and supply our own rotation.
@ -5381,7 +5506,19 @@ void Player::getRenderEyeBaseTransform(MatrixF* mat)
else
zmat.identity();
pmat.mul(zmat,xmat);
if(includeBank && mDataBlock->cameraCanBank)
{
// Take mHead.y delta into account to bank the camera
MatrixF imat;
imat.mul(zmat, xmat);
MatrixF ymat;
ymat.set(EulerF(0.0f, delta.head.y + delta.headVec.y * delta.dt, 0.0f));
pmat.mul(imat, ymat);
}
else
{
pmat.mul(zmat,xmat);
}
F32 *dp = pmat;
@ -5539,7 +5676,7 @@ void Player::renderMountedImage( U32 imageSlot, TSRenderState &rstate, SceneRend
if (data.useEyeNode && data.eyeMountNode[imageShapeIndex] != -1)
{
MatrixF nmat;
getRenderEyeBaseTransform(&nmat);
getRenderEyeBaseTransform(&nmat, mDataBlock->mountedImagesBank);
MatrixF offsetMat = image.shapeInstance[imageShapeIndex]->mNodeTransforms[data.eyeMountNode[imageShapeIndex]];
offsetMat.affineInverse();
world.mul(nmat,offsetMat);
@ -5547,7 +5684,7 @@ void Player::renderMountedImage( U32 imageSlot, TSRenderState &rstate, SceneRend
else
{
MatrixF nmat;
getRenderEyeBaseTransform(&nmat);
getRenderEyeBaseTransform(&nmat, mDataBlock->mountedImagesBank);
world.mul(nmat,data.eyeOffset);
}
@ -5684,7 +5821,7 @@ bool Player::castRay(const Point3F &start, const Point3F &end, RayInfo* info)
F32 const *si = &start.x;
F32 const *ei = &end.x;
for (int i = 0; i < 3; i++) {
for (S32 i = 0; i < 3; i++) {
if (*si < *ei) {
if (*si > *bmax || *ei < *bmin)
return false;
@ -5866,6 +6003,11 @@ void Player::writePacketData(GameConnection *connection, BitStream *stream)
}
}
stream->write(mHead.x);
if(stream->writeFlag(mDataBlock->cameraCanBank))
{
// Include mHead.y to allow for camera banking
stream->write(mHead.y);
}
stream->write(mHead.z);
stream->write(mRot.z);
@ -5928,6 +6070,11 @@ void Player::readPacketData(GameConnection *connection, BitStream *stream)
else
pos = delta.pos;
stream->read(&mHead.x);
if(stream->readFlag())
{
// Include mHead.y to allow for camera banking
stream->read(&mHead.y);
}
stream->read(&mHead.z);
stream->read(&rot.z);
rot.x = rot.y = 0;
@ -6359,8 +6506,9 @@ DefineEngineMethod( Player, getDamageLocation, const char*, ( Point3F pos ),,
object->getDamageLocation(pos, buffer1, buffer2);
char *buff = Con::getReturnBuffer(128);
dSprintf(buff, 128, "%s %s", buffer1, buffer2);
static const U32 bufSize = 128;
char *buff = Con::getReturnBuffer(bufSize);
dSprintf(buff, bufSize, "%s %s", buffer1, buffer2);
return buff;
}
@ -6587,6 +6735,11 @@ void Player::consoleInit()
Con::addVariable("$player::vehicleDismountTrigger", TypeS32, &sVehicleDismountTrigger,
"@brief The move trigger index used to dismount player.\n\n"
"@ingroup GameObjects\n");
// ExtendedMove support
Con::addVariable("$player::extendedMoveHeadPosRotIndex", TypeS32, &smExtendedMoveHeadPosRotIndex,
"@brief The ExtendedMove position/rotation index used for head movements.\n\n"
"@ingroup GameObjects\n");
}
//--------------------------------------------------------------------------

View file

@ -385,6 +385,9 @@ public:
NumPoseBits = 3
};
/// The ExtendedMove position/rotation index used for head movements
static S32 smExtendedMoveHeadPosRotIndex;
protected:
/// Bit masks for different types of events
@ -395,16 +398,6 @@ protected:
NextFreeMask = Parent::NextFreeMask << 3
};
struct Range {
Range(F32 _min,F32 _max) {
min = _min;
max = _max;
delta = _max - _min;
};
F32 min,max;
F32 delta;
};
SimObjectPtr<ParticleEmitter> mSplashEmitter[PlayerData::NUM_SPLASH_EMITTERS];
F32 mBubbleEmitterTime;
@ -444,6 +437,9 @@ protected:
bool mUseHeadZCalc; ///< Including mHead.z in transform calculations
F32 mLastAbsoluteYaw; ///< Stores that last absolute yaw value as passed in by ExtendedMove
F32 mLastAbsolutePitch; ///< Stores that last absolute pitch value as passed in by ExtendedMove
S32 mMountPending; ///< mMountPending suppresses tickDelay countdown so players will sit until
///< their mount, or another animation, comes through (or 13 seconds elapses).
@ -502,9 +498,6 @@ protected:
TSThread* mHeadHThread;
TSThread* mRecoilThread;
TSThread* mImageStateThread;
static Range mArmRange;
static Range mHeadVRange;
static Range mHeadHRange;
/// @}
bool mInMissionArea; ///< Are we in the mission area?
@ -687,9 +680,9 @@ public:
void setTransform(const MatrixF &mat);
void getEyeTransform(MatrixF* mat);
void getEyeBaseTransform(MatrixF* mat);
void getEyeBaseTransform(MatrixF* mat, bool includeBank);
void getRenderEyeTransform(MatrixF* mat);
void getRenderEyeBaseTransform(MatrixF* mat);
void getRenderEyeBaseTransform(MatrixF* mat, bool includeBank);
void getCameraParameters(F32 *min, F32 *max, Point3F *offset, MatrixF *rot);
void getMuzzleTransform(U32 imageSlot,MatrixF* mat);
void getRenderMuzzleTransform(U32 imageSlot,MatrixF* mat);

View file

@ -126,12 +126,9 @@ IMPLEMENT_CALLBACK( ProjectileData, onCollision, void, ( Projectile* proj, Scene
"@see Projectile\n"
);
const U32 Projectile::csmStaticCollisionMask = TerrainObjectType |
InteriorObjectType |
StaticShapeObjectType;
const U32 Projectile::csmStaticCollisionMask = TerrainObjectType | StaticShapeObjectType;
const U32 Projectile::csmDynamicCollisionMask = PlayerObjectType |
VehicleObjectType;
const U32 Projectile::csmDynamicCollisionMask = PlayerObjectType | VehicleObjectType;
const U32 Projectile::csmDamageableMask = Projectile::csmDynamicCollisionMask;
@ -323,9 +320,9 @@ bool ProjectileData::preload(bool server, String &errorStr)
if (Sim::findObject(decalId, decal) == false)
Con::errorf(ConsoleLogEntry::General, "ProjectileData::preload: Invalid packet, bad datablockId(decal): %d", decalId);
String errorStr;
if( !sfxResolve( &sound, errorStr ) )
Con::errorf(ConsoleLogEntry::General, "ProjectileData::preload: Invalid packet: %s", errorStr.c_str());
String sfxErrorStr;
if( !sfxResolve( &sound, sfxErrorStr ) )
Con::errorf(ConsoleLogEntry::General, "ProjectileData::preload: Invalid packet: %s", sfxErrorStr.c_str());
if (!lightDesc && lightDescId != 0)
if (Sim::findObject(lightDescId, lightDesc) == false)
@ -553,6 +550,7 @@ S32 ProjectileData::scaleValue( S32 value, bool down )
//
Projectile::Projectile()
: mPhysicsWorld( NULL ),
mDataBlock( NULL ),
mCurrPosition( 0, 0, 0 ),
mCurrVelocity( 0, 0, 1 ),
mSourceObjectId( -1 ),
@ -700,6 +698,12 @@ bool Projectile::onAdd()
if(!Parent::onAdd())
return false;
if( !mDataBlock )
{
Con::errorf("Projectile::onAdd - Fail - Not datablock");
return false;
}
if (isServerObject())
{
ShapeBase* ptr;
@ -1014,7 +1018,7 @@ void Projectile::explode( const Point3F &p, const Point3F &n, const U32 collideT
// Client (impact) decal.
if ( mDataBlock->decal )
gDecalManager->addDecal( p, n, 0.0f, mDataBlock->decal );
gDecalManager->addDecal(p, n, mRandF(0.0f, M_2PI_F), mDataBlock->decal);
// Client object
updateSound();
@ -1109,68 +1113,67 @@ void Projectile::simulate( F32 dt )
if ( isServerObject() && ( rInfo.object->getTypeMask() & csmStaticCollisionMask ) == 0 )
setMaskBits( BounceMask );
MatrixF xform( true );
xform.setColumn( 3, rInfo.point );
setTransform( xform );
mCurrPosition = rInfo.point;
// Get the object type before the onCollision call, in case
// the object is destroyed.
U32 objectType = rInfo.object->getTypeMask();
// re-enable the collision response on the source object since
// we need to process the onCollision and explode calls
if ( disableSourceObjCollision )
mSourceObject->enableCollision();
// Ok, here is how this works:
// onCollision is called to notify the server scripts that a collision has occurred, then
// a call to explode is made to start the explosion process. The call to explode is made
// twice, once on the server and once on the client.
// The server process is responsible for two things:
// 1) setting the ExplosionMask network bit to guarantee that the client calls explode
// 2) initiate the explosion process on the server scripts
// The client process is responsible for only one thing:
// 1) drawing the appropriate explosion
// It is possible that during the processTick the server may have decided that a hit
// has occurred while the client prediction has decided that a hit has not occurred.
// In this particular scenario the client will have failed to call onCollision and
// explode during the processTick. However, the explode function will be called
// during the next packet update, due to the ExplosionMask network bit being set.
// onCollision will remain uncalled on the client however, therefore no client
// specific code should be placed inside the function!
onCollision( rInfo.point, rInfo.normal, rInfo.object );
// Next order of business: do we explode on this hit?
if ( mCurrTick > mDataBlock->armingDelay || mDataBlock->armingDelay == 0 )
{
MatrixF xform( true );
xform.setColumn( 3, rInfo.point );
setTransform( xform );
mCurrPosition = rInfo.point;
mCurrVelocity = Point3F::Zero;
// Get the object type before the onCollision call, in case
// the object is destroyed.
U32 objectType = rInfo.object->getTypeMask();
// re-enable the collision response on the source object since
// we need to process the onCollision and explode calls
if ( disableSourceObjCollision )
mSourceObject->enableCollision();
// Ok, here is how this works:
// onCollision is called to notify the server scripts that a collision has occurred, then
// a call to explode is made to start the explosion process. The call to explode is made
// twice, once on the server and once on the client.
// The server process is responsible for two things:
// 1) setting the ExplosionMask network bit to guarantee that the client calls explode
// 2) initiate the explosion process on the server scripts
// The client process is responsible for only one thing:
// 1) drawing the appropriate explosion
// It is possible that during the processTick the server may have decided that a hit
// has occurred while the client prediction has decided that a hit has not occurred.
// In this particular scenario the client will have failed to call onCollision and
// explode during the processTick. However, the explode function will be called
// during the next packet update, due to the ExplosionMask network bit being set.
// onCollision will remain uncalled on the client however, therefore no client
// specific code should be placed inside the function!
onCollision( rInfo.point, rInfo.normal, rInfo.object );
explode( rInfo.point, rInfo.normal, objectType );
}
// break out of the collision check, since we've exploded
// we don't want to mess with the position and velocity
if ( mDataBlock->isBallistic )
{
// Otherwise, this represents a bounce. First, reflect our velocity
// around the normal...
Point3F bounceVel = mCurrVelocity - rInfo.normal * (mDot( mCurrVelocity, rInfo.normal ) * 2.0);
mCurrVelocity = bounceVel;
// Add in surface friction...
Point3F tangent = bounceVel - rInfo.normal * mDot(bounceVel, rInfo.normal);
mCurrVelocity -= tangent * mDataBlock->bounceFriction;
// Now, take elasticity into account for modulating the speed of the grenade
mCurrVelocity *= mDataBlock->bounceElasticity;
// Set the new position to the impact and the bounce
// will apply on the next frame.
//F32 timeLeft = 1.0f - rInfo.t;
newPosition = oldPosition = rInfo.point + rInfo.normal * 0.05f;
}
else
{
if ( mDataBlock->isBallistic )
{
// Otherwise, this represents a bounce. First, reflect our velocity
// around the normal...
Point3F bounceVel = mCurrVelocity - rInfo.normal * (mDot( mCurrVelocity, rInfo.normal ) * 2.0);
mCurrVelocity = bounceVel;
// Add in surface friction...
Point3F tangent = bounceVel - rInfo.normal * mDot(bounceVel, rInfo.normal);
mCurrVelocity -= tangent * mDataBlock->bounceFriction;
// Now, take elasticity into account for modulating the speed of the grenade
mCurrVelocity *= mDataBlock->bounceElasticity;
// Set the new position to the impact and the bounce
// will apply on the next frame.
//F32 timeLeft = 1.0f - rInfo.t;
newPosition = oldPosition = rInfo.point + rInfo.normal * 0.05f;
}
mCurrVelocity = Point3F::Zero;
}
}
@ -1447,4 +1450,4 @@ DefineEngineMethod(Projectile, presimulate, void, (F32 seconds), (1.0f),
"@note This function is not called if the SimObject::hidden is true.")
{
object->simulate( seconds );
}
}

View file

@ -215,9 +215,9 @@ public:
void updateSound();
virtual bool calculateImpact( float simTime,
virtual bool calculateImpact( F32 simTime,
Point3F &pointOfImpact,
float &impactTime );
F32 &impactTime );
void setInitialPosition( const Point3F& pos );
void setInitialVelocity( const Point3F& vel );

View file

@ -136,11 +136,11 @@ bool ProximityMineData::preload( bool server, String& errorStr )
if ( !server )
{
// Resolve sounds
String errorStr;
if( !sfxResolve( &armingSound, errorStr ) )
Con::errorf( ConsoleLogEntry::General, "ProximityMineData::preload: Invalid packet: %s", errorStr.c_str() );
if( !sfxResolve( &triggerSound, errorStr ) )
Con::errorf( ConsoleLogEntry::General, "ProximityMineData::preload: Invalid packet: %s", errorStr.c_str() );
String sfxErrorStr;
if( !sfxResolve( &armingSound, sfxErrorStr ) )
Con::errorf( ConsoleLogEntry::General, "ProximityMineData::preload: Invalid packet: %s", sfxErrorStr.c_str() );
if( !sfxResolve( &triggerSound, sfxErrorStr ) )
Con::errorf( ConsoleLogEntry::General, "ProximityMineData::preload: Invalid packet: %s", sfxErrorStr.c_str() );
}
if ( mShape )
@ -451,7 +451,7 @@ void ProximityMine::processTick( const Move* move )
SimpleQueryList sql;
getContainer()->findObjects( triggerBox, sTriggerCollisionMask,
SimpleQueryList::insertionCallback, &sql );
for ( int i = 0; i < sql.mList.size(); i++ )
for ( S32 i = 0; i < sql.mList.size(); i++ )
{
// Detect movement in the trigger area
if ( ( sql.mList[i] == mOwner && !mDataBlock->triggerOnOwner ) ||

View file

@ -265,8 +265,8 @@ void Rigid::translateCenterOfMass(const Point3F &oldPos,const Point3F &newPos)
MatrixF oldx,newx;
oldx.setCrossProduct(oldPos);
newx.setCrossProduct(newPos);
for (int row = 0; row < 3; row++)
for (int col = 0; col < 3; col++) {
for (S32 row = 0; row < 3; row++)
for (S32 col = 0; col < 3; col++) {
F32 n = newx(row,col), o = oldx(row,col);
objectInertia(row,col) += mass * ((o * o) - (n * n));
}

View file

@ -196,11 +196,11 @@ namespace {
// Physics and collision constants
static F32 sRestTol = 0.5; // % of gravity energy to be at rest
static int sRestCount = 10; // Consecutive ticks before comming to rest
static S32 sRestCount = 10; // Consecutive ticks before comming to rest
const U32 sCollisionMoveMask = (TerrainObjectType | InteriorObjectType |
PlayerObjectType | StaticShapeObjectType | VehicleObjectType |
VehicleBlockerObjectType);
const U32 sCollisionMoveMask = ( TerrainObjectType | PlayerObjectType |
StaticShapeObjectType | VehicleObjectType |
VehicleBlockerObjectType );
const U32 sServerCollisionMask = sCollisionMoveMask; // ItemObjectType
const U32 sClientCollisionMask = sCollisionMoveMask;
@ -302,6 +302,7 @@ bool RigidShapeData::preload(bool server, String &errorStr)
if (!collisionDetails.size() || collisionDetails[0] == -1)
{
Con::errorf("RigidShapeData::preload failed: Rigid shapes must define a collision-1 detail");
errorStr = String::ToString("RigidShapeData: Couldn't load shape \"%s\"",shapeName);
return false;
}
@ -774,7 +775,8 @@ void RigidShape::processTick(const Move* move)
// Update the physics based on the integration rate
S32 count = mDataBlock->integration;
updateWorkingCollisionSet(getCollisionMask());
if (!mDisableMove)
updateWorkingCollisionSet(getCollisionMask());
for (U32 i = 0; i < count; i++)
updatePos(TickSec / count);
@ -1003,6 +1005,11 @@ void RigidShape::setTransform(const MatrixF& newMat)
mContacts.clear();
}
void RigidShape::forceClientTransform()
{
setMaskBits(ForceMoveMask);
}
//-----------------------------------------------------------------------------
@ -1134,11 +1141,11 @@ void RigidShape::updatePos(F32 dt)
void RigidShape::updateForces(F32 /*dt*/)
{
if (mDisableMove) return;
Point3F gravForce(0, 0, sRigidShapeGravity * mRigid.mass * mGravityMod);
MatrixF currTransform;
mRigid.getTransform(&currTransform);
mRigid.atRest = false;
Point3F torque(0, 0, 0);
Point3F force(0, 0, 0);
@ -1456,6 +1463,8 @@ U32 RigidShape::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
if (stream->writeFlag(mask & PositionMask))
{
stream->writeFlag(mask & ForceMoveMask);
stream->writeCompressedPoint(mRigid.linPosition);
mathWrite(*stream, mRigid.angPosition);
mathWrite(*stream, mRigid.linMomentum);
@ -1480,6 +1489,10 @@ void RigidShape::unpackUpdate(NetConnection *con, BitStream *stream)
if (stream->readFlag())
{
// Check if we need to jump to the given transform
// rather than interpolate to it.
bool forceUpdate = stream->readFlag();
mPredictionCount = sMaxPredictionTicks;
F32 speed = mRigid.linVelocity.len();
mDelta.warpRot[0] = mRigid.angPosition;
@ -1492,7 +1505,7 @@ void RigidShape::unpackUpdate(NetConnection *con, BitStream *stream)
mRigid.atRest = stream->readFlag();
mRigid.updateVelocity();
if (isProperlyAdded())
if (!forceUpdate && isProperlyAdded())
{
// Determine number of ticks to warp based on the average
// of the client and server velocities.
@ -1640,7 +1653,7 @@ void RigidShape::_renderMassAndContacts( ObjectRenderInst *ri, SceneRenderState
GFX->getDrawUtil()->drawCube( desc, Point3F(0.1f,0.1f,0.1f), mDataBlock->massCenter, ColorI(255, 255, 255), &mRenderObjToWorld );
// Collision points...
for (int i = 0; i < mCollisionList.getCount(); i++)
for (S32 i = 0; i < mCollisionList.getCount(); i++)
{
const Collision& collision = mCollisionList[i];
GFX->getDrawUtil()->drawCube( desc, Point3F(0.05f,0.05f,0.05f), collision.point, ColorI(0, 0, 255) );
@ -1648,7 +1661,7 @@ void RigidShape::_renderMassAndContacts( ObjectRenderInst *ri, SceneRenderState
// Render the normals as one big batch...
PrimBuild::begin(GFXLineList, mCollisionList.getCount() * 2);
for (int i = 0; i < mCollisionList.getCount(); i++)
for (S32 i = 0; i < mCollisionList.getCount(); i++)
{
const Collision& collision = mCollisionList[i];
@ -1710,3 +1723,12 @@ DefineEngineMethod( RigidShape, freezeSim, void, (bool isFrozen),,
{
object->freezeSim(isFrozen);
}
DefineEngineMethod( RigidShape, forceClientTransform, void, (),,
"@brief Forces the client to jump to the RigidShape's transform rather then warp to it.\n\n")
{
if(object->isServerObject())
{
object->forceClientTransform();
}
}

View file

@ -152,10 +152,11 @@ class RigidShape: public ShapeBase
WheelCollision = BIT(1),
};
enum MaskBits {
PositionMask = Parent::NextFreeMask << 0,
EnergyMask = Parent::NextFreeMask << 1,
FreezeMask = Parent::NextFreeMask << 2,
NextFreeMask = Parent::NextFreeMask << 3
PositionMask = Parent::NextFreeMask << 0,
EnergyMask = Parent::NextFreeMask << 1,
FreezeMask = Parent::NextFreeMask << 2,
ForceMoveMask = Parent::NextFreeMask << 3,
NextFreeMask = Parent::NextFreeMask << 4
};
void updateDustTrail( F32 dt );
@ -194,7 +195,7 @@ class RigidShape: public ShapeBase
CollisionList mContacts;
Rigid mRigid;
ShapeBaseConvex mConvex;
int restCount;
S32 restCount;
SimObjectPtr<ParticleEmitter> mDustEmitterList[RigidShapeData::VC_NUM_DUST_EMITTERS];
SimObjectPtr<ParticleEmitter> mSplashEmitterList[RigidShapeData::VC_NUM_SPLASH_EMITTERS];
@ -283,6 +284,10 @@ public:
/// @param impulse Impulse vector to apply.
void applyImpulse(const Point3F &r, const Point3F &impulse);
/// Forces the client to jump to the RigidShape's transform rather
/// then warp to it.
void forceClientTransform();
void getCameraParameters(F32 *min, F32* max, Point3F* offset, MatrixF* rot);
void getCameraTransform(F32* pos, MatrixF* mat);
///@}

View file

@ -114,11 +114,12 @@ IMPLEMENT_CALLBACK( ShapeBaseData, onTrigger, void, ( ShapeBase* obj, S32 index,
"@param index Index of the trigger that changed\n"
"@param state New state of the trigger\n" );
IMPLEMENT_CALLBACK( ShapeBaseData, onEndSequence, void, ( ShapeBase* obj, S32 slot ), ( obj, slot ),
IMPLEMENT_CALLBACK(ShapeBaseData, onEndSequence, void, (ShapeBase* obj, S32 slot, const char* name), (obj, slot, name),
"@brief Called when a thread playing a non-cyclic sequence reaches the end of the "
"sequence.\n\n"
"@param obj The ShapeBase object\n"
"@param slot Thread slot that finished playing\n" );
"@param slot Thread slot that finished playing\n"
"@param name Thread name that finished playing\n");
IMPLEMENT_CALLBACK( ShapeBaseData, onForceUncloak, void, ( ShapeBase* obj, const char* reason ), ( obj, reason ),
"@brief Called when the object is forced to uncloak.\n\n"
@ -171,6 +172,8 @@ ShapeBaseData::ShapeBaseData()
cameraDefaultFov( 75.0f ),
cameraMinFov( 5.0f ),
cameraMaxFov( 120.f ),
cameraCanBank( false ),
mountedImagesBank( false ),
isInvincible( false ),
renderWhenDestroyed( true ),
debris( NULL ),
@ -304,7 +307,10 @@ bool ShapeBaseData::preload(bool server, String &errorStr)
Torque::FS::FileNodeRef fileRef = Torque::FS::GetFileNode(mShape.getPath());
if (!fileRef)
{
errorStr = String::ToString("ShapeBaseData: Couldn't load shape \"%s\"",shapeName);
return false;
}
if(server)
mCRC = fileRef->getChecksum();
@ -544,6 +550,10 @@ void ShapeBaseData::initPersistFields()
"The minimum camera vertical FOV allowed in degrees." );
addField( "cameraMaxFov", TypeF32, Offset(cameraMaxFov, ShapeBaseData),
"The maximum camera vertical FOV allowed in degrees." );
addField( "cameraCanBank", TypeBool, Offset(cameraCanBank, ShapeBaseData),
"If the derrived class supports it, allow the camera to bank." );
addField( "mountedImagesBank", TypeBool, Offset(mountedImagesBank, ShapeBaseData),
"Do mounted images bank along with the camera?" );
addField( "firstPersonOnly", TypeBool, Offset(firstPersonOnly, ShapeBaseData),
"Flag controlling whether the view from this object is first person "
"only." );
@ -622,7 +632,7 @@ DefineEngineMethod( ShapeBaseData, checkDeployPos, bool, ( TransformF txfm ),,
polyList.mPlaneList[i] = temp;
}
if (gServerContainer.buildPolyList(PLC_Collision, wBox, InteriorObjectType | StaticShapeObjectType, &polyList))
if (gServerContainer.buildPolyList(PLC_Collision, wBox, StaticShapeObjectType, &polyList))
return false;
return true;
}
@ -689,6 +699,8 @@ void ShapeBaseData::packData(BitStream* stream)
stream->write(cameraMinFov);
if(stream->writeFlag(cameraMaxFov != gShapeBaseDataProto.cameraMaxFov))
stream->write(cameraMaxFov);
stream->writeFlag(cameraCanBank);
stream->writeFlag(mountedImagesBank);
stream->writeString( debrisShapeName );
stream->writeFlag(observeThroughObject);
@ -788,6 +800,9 @@ void ShapeBaseData::unpackData(BitStream* stream)
else
cameraMaxFov = gShapeBaseDataProto.cameraMaxFov;
cameraCanBank = stream->readFlag();
mountedImagesBank = stream->readFlag();
debrisShapeName = stream->readSTString();
observeThroughObject = stream->readFlag();
@ -887,17 +902,9 @@ ShapeBase::ShapeBase()
mCloakLevel( 0.0f ),
mDamageFlash( 0.0f ),
mWhiteOut( 0.0f ),
mInvincibleEffect( 0.0f ),
mInvincibleDelta( 0.0f ),
mInvincibleCount( 0.0f ),
mInvincibleSpeed( 0.0f ),
mInvincibleTime( 0.0f ),
mInvincibleFade( 0.1f ),
mInvincibleOn( false ),
mIsControlled( false ),
mConvexList( new Convex ),
mCameraFov( 90.0f ),
mShieldNormal( 0.0f, 0.0f, 1.0f ),
mFadeOut( true ),
mFading( false ),
mFadeVal( 1.0f ),
@ -925,7 +932,6 @@ ShapeBase::ShapeBase()
for (i = 0; i < MaxScriptThreads; i++) {
mScriptThread[i].sequence = -1;
mScriptThread[i].thread = 0;
mScriptThread[i].sound = 0;
mScriptThread[i].state = Thread::Stop;
mScriptThread[i].atEnd = false;
mScriptThread[i].timescale = 1.f;
@ -947,6 +953,7 @@ ShapeBase::~ShapeBase()
if( mShapeInstance && (mShapeInstance->getDebrisRefCount() == 0) )
{
delete mShapeInstance;
mShapeInstance = NULL;
}
CollisionTimeout* ptr = mTimeoutList;
@ -1270,7 +1277,7 @@ void ShapeBase::processTick(const Move* move)
{
mMoveMotion = true;
}
for (int i = 0; i < MaxMountedImages; i++)
for (S32 i = 0; i < MaxMountedImages; i++)
{
setImageMotionState(i, mMoveMotion);
}
@ -1293,7 +1300,7 @@ void ShapeBase::processTick(const Move* move)
// Advance images
if (isServerObject())
{
for (int i = 0; i < MaxMountedImages; i++)
for (S32 i = 0; i < MaxMountedImages; i++)
{
if (mMountedImageList[i].dataBlock)
updateImageState(i, TickSec);
@ -1335,7 +1342,7 @@ void ShapeBase::advanceTime(F32 dt)
// advanced at framerate.
advanceThreads(dt);
updateAudioPos();
for (int i = 0; i < MaxMountedImages; i++)
for (S32 i = 0; i < MaxMountedImages; i++)
if (mMountedImageList[i].dataBlock)
{
updateImageState(i, dt);
@ -1370,9 +1377,6 @@ void ShapeBase::advanceTime(F32 dt)
mCloakLevel = 0.0;
}
}
if(mInvincibleOn)
updateInvincibleEffect(dt);
if(mFading)
{
mFadeElapsedTime += dt;
@ -1872,10 +1876,10 @@ Point3F ShapeBase::getAIRepairPoint()
void ShapeBase::getEyeTransform(MatrixF* mat)
{
getEyeBaseTransform(mat);
getEyeBaseTransform(mat, true);
}
void ShapeBase::getEyeBaseTransform(MatrixF* mat)
void ShapeBase::getEyeBaseTransform(MatrixF* mat, bool includeBank)
{
// Returns eye to world space transform
S32 eyeNode = mDataBlock->eyeNode;
@ -1887,10 +1891,10 @@ void ShapeBase::getEyeBaseTransform(MatrixF* mat)
void ShapeBase::getRenderEyeTransform(MatrixF* mat)
{
getRenderEyeBaseTransform(mat);
getRenderEyeBaseTransform(mat, true);
}
void ShapeBase::getRenderEyeBaseTransform(MatrixF* mat)
void ShapeBase::getRenderEyeBaseTransform(MatrixF* mat, bool includeBank)
{
// Returns eye to world space transform
S32 eyeNode = mDataBlock->eyeNode;
@ -1975,119 +1979,6 @@ void ShapeBase::getCameraTransform(F32* pos,MatrixF* mat)
mat->mul( gCamFXMgr.getTrans() );
}
// void ShapeBase::getCameraTransform(F32* pos,MatrixF* mat)
// {
// // Returns camera to world space transform
// // Handles first person / third person camera position
// if (isServerObject() && mShapeInstance)
// mShapeInstance->animateNodeSubtrees(true);
// if (*pos != 0) {
// F32 min,max;
// Point3F offset;
// MatrixF eye,rot;
// getCameraParameters(&min,&max,&offset,&rot);
// getRenderEyeTransform(&eye);
// mat->mul(eye,rot);
// // Use the eye transform to orient the camera
// VectorF vp,vec;
// vp.x = vp.z = 0;
// vp.y = -(max - min) * *pos;
// eye.mulV(vp,&vec);
// // Use the camera node's pos.
// Point3F osp,sp;
// if (mDataBlock->cameraNode != -1) {
// mShapeInstance->mNodeTransforms[mDataBlock->cameraNode].getColumn(3,&osp);
// getRenderTransform().mulP(osp,&sp);
// }
// else
// getRenderTransform().getColumn(3,&sp);
// // Make sure we don't extend the camera into anything solid
// Point3F ep = sp + vec;
// ep += offset;
// disableCollision();
// if (isMounted())
// getObjectMount()->disableCollision();
// RayInfo collision;
// if (mContainer->castRay(sp,ep,(0xFFFFFFFF & ~(WaterObjectType|ForceFieldObjectType|GameBaseObjectType|DefaultObjectType)),&collision)) {
// *pos = collision.t *= 0.9;
// if (*pos == 0)
// eye.getColumn(3,&ep);
// else
// ep = sp + vec * *pos;
// }
// mat->setColumn(3,ep);
// if (isMounted())
// getObjectMount()->enableCollision();
// enableCollision();
// }
// else
// {
// getRenderEyeTransform(mat);
// }
// }
// void ShapeBase::getRenderCameraTransform(F32* pos,MatrixF* mat)
// {
// // Returns camera to world space transform
// // Handles first person / third person camera position
// if (isServerObject() && mShapeInstance)
// mShapeInstance->animateNodeSubtrees(true);
// if (*pos != 0) {
// F32 min,max;
// Point3F offset;
// MatrixF eye,rot;
// getCameraParameters(&min,&max,&offset,&rot);
// getRenderEyeTransform(&eye);
// mat->mul(eye,rot);
// // Use the eye transform to orient the camera
// VectorF vp,vec;
// vp.x = vp.z = 0;
// vp.y = -(max - min) * *pos;
// eye.mulV(vp,&vec);
// // Use the camera node's pos.
// Point3F osp,sp;
// if (mDataBlock->cameraNode != -1) {
// mShapeInstance->mNodeTransforms[mDataBlock->cameraNode].getColumn(3,&osp);
// getRenderTransform().mulP(osp,&sp);
// }
// else
// getRenderTransform().getColumn(3,&sp);
// // Make sure we don't extend the camera into anything solid
// Point3F ep = sp + vec;
// ep += offset;
// disableCollision();
// if (isMounted())
// getObjectMount()->disableCollision();
// RayInfo collision;
// if (mContainer->castRay(sp,ep,(0xFFFFFFFF & ~(WaterObjectType|ForceFieldObjectType|GameBaseObjectType|DefaultObjectType)),&collision)) {
// *pos = collision.t *= 0.9;
// if (*pos == 0)
// eye.getColumn(3,&ep);
// else
// ep = sp + vec * *pos;
// }
// mat->setColumn(3,ep);
// if (isMounted())
// getObjectMount()->enableCollision();
// enableCollision();
// }
// else
// {
// getRenderEyeTransform(mat);
// }
// }
void ShapeBase::getCameraParameters(F32 *min,F32* max,Point3F* off,MatrixF* rot)
{
*min = mDataBlock->cameraMinDist;
@ -2141,52 +2032,6 @@ bool ShapeBase::useObjsEyePoint() const
return mDataBlock->useEyePoint;
}
//----------------------------------------------------------------------------
F32 ShapeBase::getInvincibleEffect() const
{
return mInvincibleEffect;
}
void ShapeBase::setupInvincibleEffect(F32 time, F32 speed)
{
if(isClientObject())
{
mInvincibleCount = mInvincibleTime = time;
mInvincibleSpeed = mInvincibleDelta = speed;
mInvincibleEffect = 0.0f;
mInvincibleOn = true;
mInvincibleFade = 1.0f;
}
else
{
mInvincibleTime = time;
mInvincibleSpeed = speed;
setMaskBits(InvincibleMask);
}
}
void ShapeBase::updateInvincibleEffect(F32 dt)
{
if(mInvincibleCount > 0.0f )
{
if(mInvincibleEffect >= ((0.3 * mInvincibleFade) + 0.05f) && mInvincibleDelta > 0.0f)
mInvincibleDelta = -mInvincibleSpeed;
else if(mInvincibleEffect <= 0.05f && mInvincibleDelta < 0.0f)
{
mInvincibleDelta = mInvincibleSpeed;
mInvincibleFade = mInvincibleCount / mInvincibleTime;
}
mInvincibleEffect += mInvincibleDelta;
mInvincibleCount -= dt;
}
else
{
mInvincibleEffect = 0.0f;
mInvincibleOn = false;
}
}
//----------------------------------------------------------------------------
void ShapeBase::setVelocity(const VectorF&)
{
@ -2228,7 +2073,7 @@ void ShapeBase::stopAudio(U32 slot)
void ShapeBase::updateServerAudio()
{
// Timeout non-looping sounds
for (int i = 0; i < MaxSoundThreads; i++) {
for (S32 i = 0; i < MaxSoundThreads; i++) {
Sound& st = mSoundThread[i];
if (st.play && st.timeout && st.timeout < Sim::getCurrentTime()) {
clearMaskBits(SoundMaskN << i);
@ -2268,7 +2113,7 @@ void ShapeBase::updateAudioState(Sound& st)
void ShapeBase::updateAudioPos()
{
for (int i = 0; i < MaxSoundThreads; i++)
for (S32 i = 0; i < MaxSoundThreads; i++)
{
SFXSource* source = mSoundThread[i].sound;
if ( source )
@ -2310,14 +2155,13 @@ bool ShapeBase::setThreadSequence(U32 slot, S32 seq, bool reset)
if (reset) {
st.state = Thread::Play;
st.atEnd = false;
st.timescale = 1.f;
st.position = 0.f;
st.timescale = 1.f;
st.position = 0.f;
}
if (mShapeInstance) {
if (!st.thread)
st.thread = mShapeInstance->addThread();
mShapeInstance->setSequence(st.thread,seq,0);
stopThreadSound(st);
mShapeInstance->setSequence(st.thread,seq,st.position);
updateThread(st);
}
return true;
@ -2332,19 +2176,12 @@ void ShapeBase::updateThread(Thread& st)
case Thread::Stop:
{
mShapeInstance->setTimeScale( st.thread, 1.f );
mShapeInstance->setPos( st.thread, ( st.timescale > 0.f ) ? 0.0f : 1.0f );
mShapeInstance->setPos( st.thread, ( st.timescale > 0.f ) ? 1.0f : 0.0f );
} // Drop through to pause state
case Thread::Pause:
{
if ( st.position != -1.f )
{
mShapeInstance->setTimeScale( st.thread, 1.f );
mShapeInstance->setPos( st.thread, st.position );
}
mShapeInstance->setTimeScale( st.thread, 0.f );
stopThreadSound( st );
} break;
case Thread::Play:
@ -2354,7 +2191,6 @@ void ShapeBase::updateThread(Thread& st)
mShapeInstance->setTimeScale(st.thread,1);
mShapeInstance->setPos( st.thread, ( st.timescale > 0.f ) ? 1.0f : 0.0f );
mShapeInstance->setTimeScale(st.thread,0);
stopThreadSound(st);
st.state = Thread::Stop;
}
else
@ -2366,16 +2202,11 @@ void ShapeBase::updateThread(Thread& st)
}
mShapeInstance->setTimeScale(st.thread, st.timescale );
if (!st.sound)
{
startSequenceSound(st);
}
}
} break;
case Thread::Destroy:
{
stopThreadSound(st);
st.atEnd = true;
st.sequence = -1;
if(st.thread)
@ -2483,19 +2314,6 @@ bool ShapeBase::setThreadTimeScale( U32 slot, F32 timeScale )
return false;
}
void ShapeBase::stopThreadSound(Thread& thread)
{
if (thread.sound) {
}
}
void ShapeBase::startSequenceSound(Thread& thread)
{
if (!isGhost() || !thread.thread)
return;
stopThreadSound(thread);
}
void ShapeBase::advanceThreads(F32 dt)
{
for (U32 i = 0; i < MaxScriptThreads; i++) {
@ -2507,7 +2325,7 @@ void ShapeBase::advanceThreads(F32 dt)
st.atEnd = true;
updateThread(st);
if (!isGhost()) {
mDataBlock->onEndSequence_callback( this, i );
mDataBlock->onEndSequence_callback(this, i, this->getThreadSequenceName(i));
}
}
@ -2516,6 +2334,7 @@ void ShapeBase::advanceThreads(F32 dt)
if(st.thread)
{
mShapeInstance->advanceTime(dt,st.thread);
st.position = mShapeInstance->getPos(st.thread);
}
}
}
@ -2582,7 +2401,7 @@ void ShapeBase::_prepRenderImage( SceneRenderState *state,
return;
// We don't need to render if all the meshes are forced hidden.
if ( mMeshHidden.testAll() )
if ( mMeshHidden.getSize() > 0 && mMeshHidden.testAll() )
return;
// If we're rendering shadows don't render the mounted
@ -3090,8 +2909,7 @@ U32 ShapeBase::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
}
if(!stream->writeFlag(mask & (NameMask | DamageMask | SoundMask | MeshHiddenMask |
ThreadMask | ImageMask | CloakMask | InvincibleMask |
ShieldMask | SkinMask)))
ThreadMask | ImageMask | CloakMask | SkinMask)))
return retMask;
if (stream->writeFlag(mask & DamageMask)) {
@ -3101,7 +2919,7 @@ U32 ShapeBase::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
}
if (stream->writeFlag(mask & ThreadMask)) {
for (int i = 0; i < MaxScriptThreads; i++) {
for (S32 i = 0; i < MaxScriptThreads; i++) {
Thread& st = mScriptThread[i];
if (stream->writeFlag( (st.sequence != -1 || st.state == Thread::Destroy) && (mask & (ThreadMaskN << i)) ) ) {
stream->writeInt(st.sequence,ThreadSequenceBits);
@ -3114,7 +2932,7 @@ U32 ShapeBase::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
}
if (stream->writeFlag(mask & SoundMask)) {
for (int i = 0; i < MaxSoundThreads; i++) {
for (S32 i = 0; i < MaxSoundThreads; i++) {
Sound& st = mSoundThread[i];
if (stream->writeFlag(mask & (SoundMaskN << i)))
if (stream->writeFlag(st.play))
@ -3124,7 +2942,7 @@ U32 ShapeBase::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
}
if (stream->writeFlag(mask & ImageMask)) {
for (int i = 0; i < MaxMountedImages; i++)
for (S32 i = 0; i < MaxMountedImages; i++)
if (stream->writeFlag(mask & (ImageMaskN << i))) {
MountedImage& image = mMountedImageList[i];
if (stream->writeFlag(image.dataBlock))
@ -3146,9 +2964,9 @@ U32 ShapeBase::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
stream->writeFlag(image.triggerDown);
stream->writeFlag(image.altTriggerDown);
for (U32 i=0; i<ShapeBaseImageData::MaxGenericTriggers; ++i)
for (U32 j=0; j<ShapeBaseImageData::MaxGenericTriggers; ++j)
{
stream->writeFlag(image.genericTrigger[i]);
stream->writeFlag(image.genericTrigger[j]);
}
stream->writeInt(image.fireCount,3);
@ -3161,7 +2979,7 @@ U32 ShapeBase::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
}
// Group some of the uncommon stuff together.
if (stream->writeFlag(mask & (NameMask | ShieldMask | CloakMask | InvincibleMask | SkinMask | MeshHiddenMask ))) {
if (stream->writeFlag(mask & (NameMask | CloakMask | SkinMask | MeshHiddenMask ))) {
if (stream->writeFlag(mask & CloakMask))
{
@ -3182,14 +3000,6 @@ U32 ShapeBase::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
if (stream->writeFlag(mask & NameMask)) {
con->packNetStringHandleU(stream, mShapeNameHandle);
}
if (stream->writeFlag(mask & ShieldMask)) {
stream->writeNormalVector(mShieldNormal, ShieldNormalBits);
stream->writeFloat( getEnergyValue(), EnergyLevelBits );
}
if (stream->writeFlag(mask & InvincibleMask)) {
stream->write(mInvincibleTime);
stream->write(mInvincibleSpeed);
}
if ( stream->writeFlag( mask & MeshHiddenMask ) )
stream->writeBits( mMeshHidden );
@ -3225,9 +3035,9 @@ void ShapeBase::unpackUpdate(NetConnection *con, BitStream *stream)
if (stream->readFlag()) {
Thread& st = mScriptThread[i];
U32 seq = stream->readInt(ThreadSequenceBits);
st.state = stream->readInt(2);
stream->read( &st.timescale );
stream->read( &st.position );
st.state = Thread::State(stream->readInt(2));
stream->read( &st.timescale );
stream->read( &st.position );
st.atEnd = stream->readFlag();
if (st.sequence != seq && st.state != Thread::Destroy)
setThreadSequence(i,seq,false);
@ -3259,7 +3069,7 @@ void ShapeBase::unpackUpdate(NetConnection *con, BitStream *stream)
// Mounted Images
if (stream->readFlag()) {
for (int i = 0; i < MaxMountedImages; i++) {
for (S32 i = 0; i < MaxMountedImages; i++) {
if (stream->readFlag()) {
MountedImage& image = mMountedImageList[i];
ShapeBaseImageData* imageData = 0;
@ -3291,14 +3101,14 @@ void ShapeBase::unpackUpdate(NetConnection *con, BitStream *stream)
image.triggerDown = stream->readFlag();
image.altTriggerDown = stream->readFlag();
for (U32 i=0; i<ShapeBaseImageData::MaxGenericTriggers; ++i)
for (U32 j=0; j<ShapeBaseImageData::MaxGenericTriggers; ++j)
{
image.genericTrigger[i] = stream->readFlag();
image.genericTrigger[j] = stream->readFlag();
}
int count = stream->readInt(3);
int altCount = stream->readInt(3);
int reloadCount = stream->readInt(3);
S32 count = stream->readInt(3);
S32 altCount = stream->readInt(3);
S32 reloadCount = stream->readInt(3);
bool datablockChange = image.dataBlock != imageData;
if (datablockChange || (image.skinNameHandle != skinDesiredNameHandle))
@ -3431,25 +3241,6 @@ void ShapeBase::unpackUpdate(NetConnection *con, BitStream *stream)
if (stream->readFlag()) { // NameMask
mShapeNameHandle = con->unpackNetStringHandleU(stream);
}
if(stream->readFlag()) // ShieldMask
{
// Cloaking, Shield, and invul masking
Point3F shieldNormal;
stream->readNormalVector(&shieldNormal, ShieldNormalBits);
// CodeReview [bjg 4/6/07] This is our energy level - why aren't we storing it? Was in a
// local variable called energyPercent.
stream->readFloat(EnergyLevelBits);
}
if (stream->readFlag())
{
// InvincibleMask
F32 time, speed;
stream->read(&time);
stream->read(&speed);
setupInvincibleEffect(time, speed);
}
if ( stream->readFlag() ) // MeshHiddenMask
{
@ -3730,7 +3521,7 @@ void ShapeBase::reSkin()
Vector<String> skins;
String(mSkinNameHandle.getString()).split( ";", skins );
for (int i = 0; i < skins.size(); i++)
for (S32 i = 0; i < skins.size(); i++)
{
String oldSkin( mAppliedSkinName.c_str() );
String newSkin( skins[i] );
@ -4601,6 +4392,11 @@ DefineEngineMethod( ShapeBase, isEnabled, bool, (),,
return object->getDamageState() == ShapeBase::Enabled;
}
DefineEngineMethod(ShapeBase, blowUp, void, (),, "@brief Explodes an object into pieces.")
{
object->blowUp();
}
DefineEngineMethod( ShapeBase, applyDamage, void, ( F32 amount ),,
"@brief Increment the current damage level by the specified amount.\n\n"
@ -4809,18 +4605,6 @@ DefineEngineMethod( ShapeBase, setCameraFov, void, ( F32 fov ),,
object->setCameraFov( fov );
}
DefineEngineMethod( ShapeBase, setInvincibleMode, void, ( F32 time, F32 speed ),,
"@brief Setup the invincible effect.\n\n"
"This effect is used for HUD feedback to the user that they are invincible.\n"
"@note Currently not implemented\n"
"@param time duration in seconds for the invincible effect\n"
"@param speed speed at which the invincible effect progresses\n" )
{
object->setupInvincibleEffect( time, speed );
}
DefineEngineMethod( ShapeBase, startFade, void, ( S32 time, S32 delay, bool fadeOut ),,
"@brief Fade the object in or out without removing it from the scene.\n\n"
@ -5038,7 +4822,7 @@ DefineEngineMethod( ShapeBase, dumpMeshVisibility, void, (),,
#endif // #ifndef TORQUE_SHIPPING
//------------------------------------------------------------------------
//These functions are duplicated in tsStatic, shapeBase, and interiorInstance.
//These functions are duplicated in tsStatic and shapeBase.
//They each function a little differently; but achieve the same purpose of gathering
//target names/counts without polluting simObject.
@ -5127,8 +4911,8 @@ DefineEngineMethod( ShapeBase, changeMaterial, void, ( const char* mapTo, Materi
newMat->mMapTo = mapTo;
// Map the material in the in the matmgr
MATMGR->mapMaterial( mapTo, newMat->mMapTo );
// Map the material by name in the matmgr
MATMGR->mapMaterial( mapTo, newMat->getName() );
// Replace instances with the new material being traded in. For ShapeBase
// class we have to update the server/client objects separately so both

View file

@ -578,6 +578,12 @@ public:
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
/// @{
@ -642,7 +648,7 @@ public:
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 ) );
DECLARE_CALLBACK(void, onEndSequence, (ShapeBase* obj, S32 slot, const char* name));
DECLARE_CALLBACK( void, onForceUncloak, ( ShapeBase* obj, const char* reason ) );
/// @}
};
@ -683,7 +689,6 @@ public:
MaxMountedImages = 4, ///< Should be a power of 2
MaxImageEmitters = 3,
NumImageBits = 3,
ShieldNormalBits = 8,
CollisionTimeoutValue = 250 ///< Timeout in ms.
};
@ -724,12 +729,9 @@ protected:
Play, Stop, Pause, Destroy
};
TSThread* thread; ///< Pointer to 3space data.
U32 state; ///< State of the thread
///
/// @see Thread::State
State state; ///< State of the thread
S32 sequence; ///< The animation sequence which is running in this thread.
F32 timescale; ///< Timescale
U32 sound; ///< Handle to sound.
F32 timescale; ///< Timescale
bool atEnd; ///< Are we at the end of this thread?
F32 position;
};
@ -737,17 +739,6 @@ protected:
/// @}
/// @name Invincibility
/// @{
F32 mInvincibleCount;
F32 mInvincibleTime;
F32 mInvincibleSpeed;
F32 mInvincibleDelta;
F32 mInvincibleEffect;
F32 mInvincibleFade;
bool mInvincibleOn;
/// @}
/// @name Motion
/// @{
bool mMoveMotion; ///< Indicates that a Move has come in requesting x, y or z motion
@ -912,9 +903,6 @@ protected:
bool mFlipFadeVal;
/// Last shield direction (cur. unused)
Point3F mShieldNormal;
/// Camera shake caused by weapon fire.
CameraShake *mWeaponCamShake;
@ -1115,7 +1103,6 @@ protected:
virtual void ejectShellCasing( U32 imageSlot );
virtual void updateDamageLevel();
virtual void updateDamageState();
virtual void blowUp();
virtual void onImpact(SceneObject* obj, VectorF vec);
virtual void onImpact(VectorF vec);
/// @}
@ -1151,11 +1138,9 @@ public:
DamageMask = Parent::NextFreeMask << 1,
NoWarpMask = Parent::NextFreeMask << 2,
CloakMask = Parent::NextFreeMask << 3,
ShieldMask = Parent::NextFreeMask << 4,
InvincibleMask = Parent::NextFreeMask << 5,
SkinMask = Parent::NextFreeMask << 6,
MeshHiddenMask = Parent::NextFreeMask << 7,
SoundMaskN = Parent::NextFreeMask << 8, ///< Extends + MaxSoundThreads bits
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
@ -1301,6 +1286,9 @@ public:
/// Returns the recharge rate
F32 getRechargeRate() { return mRechargeRate; }
/// Makes the shape explode.
virtual void blowUp();
/// @}
/// @name Script sounds
@ -1363,14 +1351,6 @@ public:
/// @param timescale Timescale
bool setThreadTimeScale( U32 slot, F32 timeScale );
/// 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);
@ -1618,7 +1598,7 @@ public:
/// 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);
virtual void getEyeBaseTransform(MatrixF* mat, bool includeBank);
/// The retraction transform is the muzzle transform in world space.
///
@ -1671,7 +1651,7 @@ public:
virtual void getRenderMuzzleVector(U32 imageSlot,VectorF* vec);
virtual void getRenderMuzzlePoint(U32 imageSlot,Point3F* pos);
virtual void getRenderEyeTransform(MatrixF* mat);
virtual void getRenderEyeBaseTransform(MatrixF* mat);
virtual void getRenderEyeBaseTransform(MatrixF* mat, bool includeBank);
/// @}
@ -1694,26 +1674,6 @@ public:
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
/// @{

View file

@ -203,7 +203,7 @@ ShapeBaseImageData::ShapeBaseImageData()
scriptAnimTransitionTime = 0.25f;
//
for (int i = 0; i < MaxStates; i++) {
for (S32 i = 0; i < MaxStates; i++) {
stateName[i] = 0;
stateTransitionLoaded[i] = 0;
@ -462,7 +462,10 @@ bool ShapeBaseImageData::preload(bool server, String &errorStr)
Torque::FS::FileNodeRef fileRef = Torque::FS::GetFileNode(shape[i].getPath());
if (!fileRef)
{
errorStr = String::ToString("ShapeBaseImageData: Couldn't load shape \"%s\"",name);
return false;
}
if(server)
{
@ -686,10 +689,6 @@ void ShapeBaseImageData::initPersistFields()
"@see eyeOffset\n\n"
"@see animateOnServer\n\n");
addField( "correctMuzzleVector", TypeBool, Offset(correctMuzzleVector, ShapeBaseImageData),
"@brief Flag to adjust the aiming vector to the eye's LOS point.\n\n"
"@see ShapeBase::getMuzzleVector()" );
addField( "correctMuzzleVector", TypeBool, Offset(correctMuzzleVector, ShapeBaseImageData),
"@brief Flag to adjust the aiming vector to the eye's LOS point when in 1st person view.\n\n"
"@see ShapeBase::getMuzzleVector()" );
@ -1861,7 +1860,7 @@ void ShapeBase::getImageTransform(U32 imageSlot,MatrixF* mat)
// We need to animate, even on the server, to make sure the nodes are in the correct location.
image.shapeInstance[shapeIndex]->animate();
getEyeBaseTransform(&nmat);
getEyeBaseTransform(&nmat, mDataBlock->mountedImagesBank);
MatrixF mountTransform = image.shapeInstance[shapeIndex]->mNodeTransforms[data.eyeMountNode[shapeIndex]];
@ -1900,7 +1899,7 @@ void ShapeBase::getImageTransform(U32 imageSlot,S32 node,MatrixF* mat)
image.shapeInstance[shapeIndex]->animate();
MatrixF emat;
getEyeBaseTransform(&emat);
getEyeBaseTransform(&emat, mDataBlock->mountedImagesBank);
MatrixF mountTransform = image.shapeInstance[shapeIndex]->mNodeTransforms[data.eyeMountNode[shapeIndex]];
mountTransform.affineInverse();
@ -1985,7 +1984,7 @@ void ShapeBase::getRenderImageTransform( U32 imageSlot, MatrixF* mat, bool noEye
MatrixF nmat;
if ( data.useEyeNode && isFirstPerson() && data.eyeMountNode[shapeIndex] != -1 ) {
getRenderEyeBaseTransform(&nmat);
getRenderEyeBaseTransform(&nmat, mDataBlock->mountedImagesBank);
MatrixF mountTransform = image.shapeInstance[shapeIndex]->mNodeTransforms[data.eyeMountNode[shapeIndex]];
@ -2023,7 +2022,7 @@ void ShapeBase::getRenderImageTransform(U32 imageSlot,S32 node,MatrixF* mat)
if ( data.useEyeNode && isFirstPerson() && data.eyeMountNode[shapeIndex] != -1 )
{
MatrixF emat;
getRenderEyeBaseTransform(&emat);
getRenderEyeBaseTransform(&emat, mDataBlock->mountedImagesBank);
MatrixF mountTransform = image.shapeInstance[shapeIndex]->mNodeTransforms[data.eyeMountNode[shapeIndex]];
mountTransform.affineInverse();
@ -3061,7 +3060,7 @@ TICKAGAIN:
if (image.spinThread[i])
{
float timeScale;
F32 timeScale;
switch (stateData.spin)
{
@ -3092,7 +3091,10 @@ TICKAGAIN:
}
if ( image.rDT > 0.0f && image.delayTime > 0.0f && imageData.useRemainderDT && dt != 0.0f )
{
dt = image.rDT;
goto TICKAGAIN;
}
}
@ -3259,7 +3261,7 @@ void ShapeBase::submitLights( LightManager *lm, bool staticLighting )
{
S32 elapsed = Sim::getCurrentTime() - image.lightStart;
if ( elapsed > imageData->lightDuration )
return;
continue;
intensity = ( 1.0 - (F32)elapsed / (F32)imageData->lightDuration ) * imageData->lightBrightness;
break;
}

View file

@ -188,7 +188,7 @@ bool Trigger::castRay(const Point3F &start, const Point3F &end, RayInfo* info)
F32 const *si = &start.x;
F32 const *ei = &end.x;
for (int i = 0; i < 3; i++)
for (S32 i = 0; i < 3; i++)
{
if (*si < *ei)
{
@ -259,12 +259,14 @@ ConsoleGetType( TypeTriggerPolyhedron )
AssertFatal(currVec == 3, "Internal error: Bad trigger polyhedron");
// Build output string.
char* retBuf = Con::getReturnBuffer(1024);
dSprintf(retBuf, 1023, "%7.7f %7.7f %7.7f %7.7f %7.7f %7.7f %7.7f %7.7f %7.7f %7.7f %7.7f %7.7f",
static const U32 bufSize = 1024;
char* retBuf = Con::getReturnBuffer(bufSize);
dSprintf(retBuf, bufSize, "%7.7f %7.7f %7.7f %7.7f %7.7f %7.7f %7.7f %7.7f %7.7f %7.7f %7.7f %7.7f",
origin.x, origin.y, origin.z,
vecs[0].x, vecs[0].y, vecs[0].z,
vecs[2].x, vecs[2].y, vecs[2].z,
vecs[1].x, vecs[1].y, vecs[1].z);
return retBuf;
}

View file

@ -49,6 +49,8 @@
#include "materials/materialFeatureTypes.h"
#include "console/engineAPI.h"
using namespace Torque;
extern bool gEditingMission;
IMPLEMENT_CO_NETOBJECT_V1(TSStatic);
@ -440,7 +442,7 @@ void TSStatic::reSkin()
Vector<String> skins;
String(mSkinNameHandle.getString()).split( ";", skins );
for (int i = 0; i < skins.size(); i++)
for (S32 i = 0; i < skins.size(); i++)
{
String oldSkin( mAppliedSkinName.c_str() );
String newSkin( skins[i] );
@ -523,7 +525,7 @@ void TSStatic::prepRenderImage( SceneRenderState* state )
Frustum culler;
if ( mMeshCulling )
{
culler = state->getFrustum();
culler = state->getCullingFrustum();
MatrixF xfm( true );
xfm.scale( Point3F::One / getScale() );
xfm.mul( getRenderWorldTransform() );
@ -1036,7 +1038,7 @@ void TSStaticPolysoupConvex::getFeatures(const MatrixF& mat,const VectorF& n, Co
}
//------------------------------------------------------------------------
//These functions are duplicated in tsStatic, shapeBase, and interiorInstance.
//These functions are duplicated in tsStatic and shapeBase.
//They each function a little differently; but achieve the same purpose of gathering
//target names/counts without polluting simObject.
@ -1120,8 +1122,8 @@ DefineEngineMethod( TSStatic, changeMaterial, void, ( const char* mapTo, Materia
newMat->mMapTo = mapTo;
// Map the material in the in the matmgr
MATMGR->mapMaterial( mapTo, newMat->mMapTo );
// Map the material by name in the matmgr
MATMGR->mapMaterial( mapTo, newMat->getName() );
// Replace instances with the new material being traded in. Lets make sure that we only
// target the specific targets per inst, this is actually doing more than we thought

View file

@ -37,7 +37,6 @@ static U32 sScanTypeMask = PlayerObjectType |
VehicleObjectType;
static U32 sAimTypeMask = TerrainObjectType |
InteriorObjectType |
WaterObjectType |
PlayerObjectType |
StaticShapeObjectType |
@ -100,7 +99,7 @@ AITurretShapeData::AITurretShapeData()
weaponLeadVelocity = 0;
for (int i = 0; i < MaxStates; i++) {
for (S32 i = 0; i < MaxStates; i++) {
stateName[i] = 0;
stateTransitionAtRest[i] = 0;
stateTransitionNotAtRest[i] = 0;

View file

@ -40,7 +40,7 @@ static F32 sMinWarpTicks = 0.5 ; // Fraction of tick at which instant war
static S32 sMaxWarpTicks = 3; // Max warp duration in ticks
const U32 sClientCollisionMask = (TerrainObjectType |
InteriorObjectType | StaticShapeObjectType |
StaticShapeObjectType |
VehicleObjectType);
const U32 sServerCollisionMask = (sClientCollisionMask);
@ -1270,7 +1270,7 @@ void TurretShape::getImageTransform(U32 imageSlot,S32 node,MatrixF* mat)
image.shapeInstance[shapeIndex]->animate();
MatrixF emat;
getEyeBaseTransform(&emat);
getEyeBaseTransform(&emat, mDataBlock->mountedImagesBank);
MatrixF mountTransform = image.shapeInstance[shapeIndex]->mNodeTransforms[data.eyeMountNode[shapeIndex]];
mountTransform.affineInverse();
@ -1318,7 +1318,7 @@ void TurretShape::getRenderImageTransform(U32 imageSlot,S32 node,MatrixF* mat)
if ( data.useEyeNode && isFirstPerson() && data.eyeMountNode[shapeIndex] != -1 )
{
MatrixF emat;
getRenderEyeBaseTransform(&emat);
getRenderEyeBaseTransform(&emat, mDataBlock->mountedImagesBank);
MatrixF mountTransform = image.shapeInstance[shapeIndex]->mNodeTransforms[data.eyeMountNode[shapeIndex]];
mountTransform.affineInverse();

View file

@ -43,10 +43,10 @@
//----------------------------------------------------------------------------
const static U32 sCollisionMoveMask = ( TerrainObjectType | InteriorObjectType |
WaterObjectType | PlayerObjectType |
StaticShapeObjectType | VehicleObjectType |
VehicleBlockerObjectType );
const static U32 sCollisionMoveMask = ( TerrainObjectType | WaterObjectType |
PlayerObjectType | StaticShapeObjectType |
VehicleObjectType | VehicleBlockerObjectType );
static U32 sServerCollisionMask = sCollisionMoveMask; // ItemObjectType
static U32 sClientCollisionMask = sCollisionMoveMask;

View file

@ -73,9 +73,9 @@ namespace {
const U32 sIntergrationsPerTick = 1;
const F32 sHoverVehicleGravity = -20;
const U32 sCollisionMoveMask = (TerrainObjectType | InteriorObjectType |
PlayerObjectType | StaticShapeObjectType |
VehicleObjectType | VehicleBlockerObjectType);
const U32 sCollisionMoveMask = (TerrainObjectType | PlayerObjectType |
StaticShapeObjectType | VehicleObjectType |
VehicleBlockerObjectType);
const U32 sServerCollisionMask = sCollisionMoveMask; // ItemObjectType
const U32 sClientCollisionMask = sCollisionMoveMask;
@ -724,7 +724,7 @@ void HoverVehicle::updateForces(F32 /*dt*/)
for (j = 0; j < 2; j++) {
if (getContainer()->castRay(stabPoints[j].wsPoint, stabPoints[j].wsPoint + stabPoints[j].wsExtension * 2.0,
TerrainObjectType |
InteriorObjectType | WaterObjectType, &rinfo))
WaterObjectType, &rinfo))
{
reallyFloating = false;

View file

@ -69,7 +69,7 @@ const F32 sVehicleGravity = -20;
// Physics and collision constants
static F32 sRestTol = 0.5; // % of gravity energy to be at rest
static int sRestCount = 10; // Consecutive ticks before comming to rest
static S32 sRestCount = 10; // Consecutive ticks before comming to rest
} // namespace {}
@ -172,6 +172,10 @@ VehicleData::VehicleData()
jetEnergyDrain = 0.8f;
minJetEnergy = 1;
steeringReturn = 0.0f;
steeringReturnSpeedScale = 0.01f;
powerSteering = false;
for (S32 i = 0; i < Body::MaxSounds; i++)
body.sound[i] = 0;
@ -214,6 +218,7 @@ bool VehicleData::preload(bool server, String &errorStr)
if (!collisionDetails.size() || collisionDetails[0] == -1)
{
Con::errorf("VehicleData::preload failed: Vehicle models must define a collision-1 detail");
errorStr = String::ToString("VehicleData: Couldn't load shape \"%s\"",shapeName);
return false;
}
@ -292,6 +297,10 @@ void VehicleData::packData(BitStream* stream)
stream->write(jetEnergyDrain);
stream->write(minJetEnergy);
stream->write(steeringReturn);
stream->write(steeringReturnSpeedScale);
stream->writeFlag(powerSteering);
stream->writeFlag(cameraRoll);
stream->write(cameraLag);
stream->write(cameraDecay);
@ -333,14 +342,14 @@ void VehicleData::packData(BitStream* stream)
}
}
for (int j = 0; j < VC_NUM_DAMAGE_EMITTER_AREAS; j++)
for (S32 j = 0; j < VC_NUM_DAMAGE_EMITTER_AREAS; j++)
{
stream->write( damageEmitterOffset[j].x );
stream->write( damageEmitterOffset[j].y );
stream->write( damageEmitterOffset[j].z );
}
for (int k = 0; k < VC_NUM_DAMAGE_LEVELS; k++)
for (S32 k = 0; k < VC_NUM_DAMAGE_LEVELS; k++)
{
stream->write( damageLevelTolerance[k] );
}
@ -384,6 +393,10 @@ void VehicleData::unpackData(BitStream* stream)
stream->read(&jetEnergyDrain);
stream->read(&minJetEnergy);
stream->read(&steeringReturn);
stream->read(&steeringReturnSpeedScale);
powerSteering = stream->readFlag();
cameraRoll = stream->readFlag();
stream->read(&cameraLag);
stream->read(&cameraDecay);
@ -428,14 +441,14 @@ void VehicleData::unpackData(BitStream* stream)
}
}
for( int j=0; j<VC_NUM_DAMAGE_EMITTER_AREAS; j++ )
for( S32 j=0; j<VC_NUM_DAMAGE_EMITTER_AREAS; j++ )
{
stream->read( &damageEmitterOffset[j].x );
stream->read( &damageEmitterOffset[j].y );
stream->read( &damageEmitterOffset[j].z );
}
for( int k=0; k<VC_NUM_DAMAGE_LEVELS; k++ )
for( S32 k=0; k<VC_NUM_DAMAGE_LEVELS; k++ )
{
stream->read( &damageLevelTolerance[k] );
}
@ -462,6 +475,13 @@ void VehicleData::initPersistFields()
addField( "minJetEnergy", TypeF32, Offset(minJetEnergy, VehicleData),
"Minimum vehicle energy level to begin jetting." );
addField( "steeringReturn", TypeF32, Offset(steeringReturn, VehicleData),
"Rate at which the vehicle's steering returns to forwards when it is moving." );
addField( "steeringReturnSpeedScale", TypeF32, Offset(steeringReturnSpeedScale, VehicleData),
"Amount of effect the vehicle's speed has on its rate of steering return." );
addField( "powerSteering", TypeBool, Offset(powerSteering, VehicleData),
"If true, steering does not auto-centre while the vehicle is being steered by its driver." );
addField( "massCenter", TypePoint3F, Offset(massCenter, VehicleData),
"Defines the vehicle's center of mass (offset from the origin of the model)." );
addField( "massBox", TypePoint3F, Offset(massBox, VehicleData),
@ -699,7 +719,7 @@ bool Vehicle::onAdd()
{
if( mDataBlock->dustEmitter )
{
for( int i=0; i<VehicleData::VC_NUM_DUST_EMITTERS; i++ )
for( S32 i=0; i<VehicleData::VC_NUM_DUST_EMITTERS; i++ )
{
mDustEmitterList[i] = new ParticleEmitter;
mDustEmitterList[i]->onNewDataBlock( mDataBlock->dustEmitter, false );
@ -1085,6 +1105,22 @@ void Vehicle::updateMove(const Move* move)
mSteering.y = 0;
}
// Steering return
if(mDataBlock->steeringReturn > 0.0f &&
(!mDataBlock->powerSteering || (move->yaw == 0.0f && move->pitch == 0.0f)))
{
Point2F returnAmount(mSteering.x * mDataBlock->steeringReturn * TickSec,
mSteering.y * mDataBlock->steeringReturn * TickSec);
if(mDataBlock->steeringReturnSpeedScale > 0.0f)
{
Point3F vel;
mWorldToObj.mulV(getVelocity(), &vel);
returnAmount += Point2F(mSteering.x * vel.y * mDataBlock->steeringReturnSpeedScale * TickSec,
mSteering.y * vel.y * mDataBlock->steeringReturnSpeedScale * TickSec);
}
mSteering -= returnAmount;
}
// Jetting flag
if (move->trigger[3]) {
if (!mJetting && getEnergyLevel() >= mDataBlock->minJetEnergy)
@ -1769,7 +1805,7 @@ void Vehicle::updateDamageSmoke( F32 dt )
F32 damagePercent = mDamage / mDataBlock->maxDamage;
if( damagePercent >= mDataBlock->damageLevelTolerance[j] )
{
for( int i=0; i<mDataBlock->numDmgEmitterAreas; i++ )
for( S32 i=0; i<mDataBlock->numDmgEmitterAreas; i++ )
{
MatrixF trans = getTransform();
Point3F offset = mDataBlock->damageEmitterOffset[i];
@ -1900,7 +1936,7 @@ void Vehicle::_renderMassAndContacts( ObjectRenderInst *ri, SceneRenderState *st
GFX->getDrawUtil()->drawCube(desc, Point3F(0.1f,0.1f,0.1f),mDataBlock->massCenter, ColorI(255, 255, 255), &mRenderObjToWorld);
// Now render all the contact points.
for (int i = 0; i < mCollisionList.getCount(); i++)
for (S32 i = 0; i < mCollisionList.getCount(); i++)
{
const Collision& collision = mCollisionList[i];
GFX->getDrawUtil()->drawCube(desc, Point3F(0.05f,0.05f,0.05f),collision.point, ColorI(0, 0, 255));
@ -1908,7 +1944,7 @@ void Vehicle::_renderMassAndContacts( ObjectRenderInst *ri, SceneRenderState *st
// Finally render the normals as one big batch.
PrimBuild::begin(GFXLineList, mCollisionList.getCount() * 2);
for (int i = 0; i < mCollisionList.getCount(); i++)
for (S32 i = 0; i < mCollisionList.getCount(); i++)
{
const Collision& collision = mCollisionList[i];
PrimBuild::color3f(1, 1, 1);

View file

@ -107,6 +107,10 @@ struct VehicleData: public ShapeBaseData
F32 jetEnergyDrain; ///< Energy drain/tick
F32 minJetEnergy;
F32 steeringReturn;
F32 steeringReturnSpeedScale;
bool powerSteering;
ParticleEmitterData * dustEmitter;
S32 dustID;
F32 triggerDustHeight; ///< height vehicle has to be under to kick up dust
@ -198,7 +202,7 @@ class Vehicle: public ShapeBase
CollisionList mContacts;
Rigid mRigid;
ShapeBaseConvex mConvex;
int restCount;
S32 restCount;
SimObjectPtr<ParticleEmitter> mDustEmitterList[VehicleData::VC_NUM_DUST_EMITTERS];
SimObjectPtr<ParticleEmitter> mDamageEmitterList[VehicleData::VC_NUM_DAMAGE_EMITTERS];

View file

@ -71,6 +71,12 @@ bool VehicleBlocker::onAdd()
mObjBox.minExtents.set(-mDimensions.x, -mDimensions.y, 0);
mObjBox.maxExtents.set( mDimensions.x, mDimensions.y, mDimensions.z);
if( !mObjBox.isValidBox() )
{
Con::errorf("VehicleBlocker::onAdd - Fail - No valid object box");
return false;
}
resetWorldBox();
setRenderTransform(mObjToWorld);

View file

@ -47,12 +47,12 @@
#include "lighting/lightQuery.h"
// Collision masks are used to determin what type of objects the
// Collision masks are used to determine what type of objects the
// wheeled vehicle will collide with.
static U32 sClientCollisionMask =
TerrainObjectType | InteriorObjectType |
PlayerObjectType | StaticShapeObjectType |
VehicleObjectType | VehicleBlockerObjectType;
TerrainObjectType | PlayerObjectType |
StaticShapeObjectType | VehicleObjectType |
VehicleBlockerObjectType;
// Gravity constant
static F32 sWheeledVehicleGravity = -20;

View file

@ -23,10 +23,6 @@
#ifndef _AUTH_H_
#define _AUTH_H_
#ifndef _EVENT_H_
#include "platform/event.h"
#endif
/// Formerly contained a certificate, showing that something was valid.
class Auth2Certificate
{

View file

@ -241,6 +241,16 @@ void StandardMainLoop::init()
DebugOutputConsumer::init();
#endif
// init Filesystem first, so we can actually log errors for all components that follow
Platform::FS::InstallFileSystems(); // install all drives for now until we have everything using the volume stuff
Platform::FS::MountDefaults();
// Set our working directory.
Torque::FS::SetCwd( "game:/" );
// Set our working directory.
Platform::setCurrentDirectory( Platform::getMainDotCsDir() );
Processor::init();
Math::init();
Platform::init(); // platform specific initialization
@ -291,6 +301,9 @@ void StandardMainLoop::init()
tm = new TimeManager;
tm->timeEvent.notify(&::processTimeEvent);
// Start up the Input Event Manager
INPUTMGR->start();
Sampler::init();
// Hook in for UDP notification
@ -307,6 +320,9 @@ void StandardMainLoop::init()
void StandardMainLoop::shutdown()
{
// Stop the Input Event Manager
INPUTMGR->stop();
delete tm;
preShutdown();
@ -380,15 +396,6 @@ bool StandardMainLoop::handleCommandLine( S32 argc, const char **argv )
for (i = 0; i < argc; i++)
Con::setVariable(avar("Game::argv%d", i), argv[i]);
Platform::FS::InstallFileSystems(); // install all drives for now until we have everything using the volume stuff
Platform::FS::MountDefaults();
// Set our working directory.
Torque::FS::SetCwd( "game:/" );
// Set our working directory.
Platform::setCurrentDirectory( Platform::getMainDotCsDir() );
#ifdef TORQUE_PLAYER
if(argc > 2 && dStricmp(argv[1], "-project") == 0)
{

View file

@ -23,7 +23,6 @@
#include "app/net/httpObject.h"
#include "platform/platform.h"
#include "platform/event.h"
#include "core/stream/fileStream.h"
#include "console/simBase.h"
#include "console/consoleInternal.h"
@ -299,7 +298,7 @@ void HTTPObject::onDisconnect()
Parent::onDisconnect();
}
bool HTTPObject::processLine(U8 *line)
bool HTTPObject::processLine(UTF8 *line)
{
if(mParseState == ParsingStatusLine)
{

View file

@ -72,7 +72,7 @@ public:
virtual void onConnected();
virtual void onConnectFailed();
virtual void onDisconnect();
bool processLine(U8 *line);
bool processLine(UTF8 *line);
DECLARE_CONOBJECT(HTTPObject);
};

View file

@ -31,27 +31,14 @@
#include "sim/netObject.h"
#include "app/net/serverQuery.h"
#include "console/engineAPI.h"
#include <vector>
#include "net.h"
//----------------------------------------------------------------
// remote procedure call console functions
//----------------------------------------------------------------
class RemoteCommandEvent : public NetEvent
{
public:
typedef NetEvent Parent;
enum {
MaxRemoteCommandArgs = 20,
CommandArgsBits = 5
};
private:
S32 mArgc;
char *mArgv[MaxRemoteCommandArgs + 1];
NetStringHandle mTagv[MaxRemoteCommandArgs + 1];
static char mBuf[1024];
public:
RemoteCommandEvent(S32 argc=0, const char **argv=NULL, NetConnection *conn = NULL)
RemoteCommandEvent::RemoteCommandEvent(S32 argc, const char **argv, NetConnection *conn)
{
mArgc = argc;
for(S32 i = 0; i < argc; i++)
@ -73,7 +60,7 @@ public:
}
#ifdef TORQUE_DEBUG_NET
const char *getDebugName()
const char *RemoteCommandEvent::getDebugName()
{
static char buffer[256];
dSprintf(buffer, sizeof(buffer), "%s [%s]", getClassName(), mTagv[1].isValidString() ? mTagv[1].getString() : "--unknown--" );
@ -81,13 +68,13 @@ public:
}
#endif
~RemoteCommandEvent()
RemoteCommandEvent::~RemoteCommandEvent()
{
for(S32 i = 0; i < mArgc; i++)
dFree(mArgv[i+1]);
}
virtual void pack(NetConnection* conn, BitStream *bstream)
void RemoteCommandEvent::pack(NetConnection* conn, BitStream *bstream)
{
bstream->writeInt(mArgc, CommandArgsBits);
// write it out reversed... why?
@ -98,12 +85,12 @@ public:
conn->packString(bstream, mArgv[i+1]);
}
virtual void write(NetConnection* conn, BitStream *bstream)
void RemoteCommandEvent::write(NetConnection* conn, BitStream *bstream)
{
pack(conn, bstream);
}
virtual void unpack(NetConnection* conn, BitStream *bstream)
void RemoteCommandEvent::unpack(NetConnection* conn, BitStream *bstream)
{
mArgc = bstream->readInt(CommandArgsBits);
@ -115,7 +102,7 @@ public:
}
}
virtual void process(NetConnection *conn)
void RemoteCommandEvent::process(NetConnection *conn)
{
static char idBuf[10];
@ -165,8 +152,52 @@ public:
}
}
DECLARE_CONOBJECT(RemoteCommandEvent);
};
void RemoteCommandEvent::sendRemoteCommand(NetConnection *conn, S32 argc, const char **argv)
{
if(U8(argv[0][0]) != StringTagPrefixByte)
{
Con::errorf(ConsoleLogEntry::Script, "Remote Command Error - command must be a tag.");
return;
}
S32 i;
for(i = argc - 1; i >= 0; i--)
{
if(argv[i][0] != 0)
break;
argc = i;
}
for(i = 0; i < argc; i++)
conn->validateSendString(argv[i]);
RemoteCommandEvent *cevt = new RemoteCommandEvent(argc, argv, conn);
conn->postNetEvent(cevt);
}
const char* RemoteCommandEvent::getTaggedString(const char* tag)
{
const char *indexPtr = tag;
if (*indexPtr == StringTagPrefixByte)
indexPtr++;
return gNetStringTable->lookupString(dAtoi(indexPtr));
}
void RemoteCommandEvent::removeTaggedString(S32 tag)
{
if (tag)
gNetStringTable->removeString(tag, true);
}
const char* RemoteCommandEvent::addTaggedString(const char* str)
{
NetStringHandle s(str);
gNetStringTable->incStringRefScript(s.getIndex());
char *ret = Con::getReturnBuffer(10);
ret[0] = StringTagPrefixByte;
dSprintf(ret + 1, 9, "%d", s.getIndex());
return ret;
}
char RemoteCommandEvent::mBuf[1024];
IMPLEMENT_CO_NETEVENT_V1(RemoteCommandEvent);
@ -176,30 +207,13 @@ ConsoleDocClass( RemoteCommandEvent,
"Not intended for game development, for exposing ConsoleFunctions (such as commandToClient) only.\n\n"
"@internal");
static void sendRemoteCommand(NetConnection *conn, S32 argc, const char **argv)
{
if(U8(argv[0][0]) != StringTagPrefixByte)
{
Con::errorf(ConsoleLogEntry::Script, "Remote Command Error - command must be a tag.");
return;
}
S32 i;
for(i = argc - 1; i >= 0; i--)
{
if(argv[i][0] != 0)
break;
argc = i;
}
for(i = 0; i < argc; i++)
conn->validateSendString(argv[i]);
RemoteCommandEvent *cevt = new RemoteCommandEvent(argc, argv, conn);
conn->postNetEvent(cevt);
}
ConsoleFunctionGroupBegin( Net, "Functions for use with the network; tagged strings and remote commands.");
ConsoleFunction( commandToServer, void, 2, RemoteCommandEvent::MaxRemoteCommandArgs + 1, "(string func, ...)"
"@brief Send a command to the server.\n\n"
"@brief Send a command to the server.\n\n"
"@param func Name of the server command being called\n"
"@param ... Various parameters being passed to server command\n\n"
@ -237,9 +251,8 @@ ConsoleFunction( commandToServer, void, 2, RemoteCommandEvent::MaxRemoteCommandA
NetConnection *conn = NetConnection::getConnectionToServer();
if(!conn)
return;
StringStackWrapper args(argc - 1, argv + 1);
sendRemoteCommand(conn, args.count(), args);
RemoteCommandEvent::sendRemoteCommand(conn, args.count(), args);
}
ConsoleFunction( commandToClient, void, 3, RemoteCommandEvent::MaxRemoteCommandArgs + 2, "(NetConnection client, string func, ...)"
@ -277,11 +290,14 @@ ConsoleFunction( commandToClient, void, 3, RemoteCommandEvent::MaxRemoteCommandA
if(!Sim::findObject(argv[1], conn))
return;
StringStackWrapper args(argc - 2, argv + 2);
sendRemoteCommand(conn, args.count(), args);
RemoteCommandEvent::sendRemoteCommand(conn, args.count(), args);
}
ConsoleFunction(removeTaggedString, void, 2, 2, "(int tag)"
DefineEngineFunction(removeTaggedString, void, (S32 tag), (-1),
"@brief Remove a tagged string from the Net String Table\n\n"
"@param tag The tag associated with the string\n\n"
@ -290,11 +306,12 @@ ConsoleFunction(removeTaggedString, void, 2, 2, "(int tag)"
"@see addTaggedString()\n"
"@see getTaggedString()\n"
"@ingroup Networking\n")
{
gNetStringTable->removeString(dAtoi(((const char*)argv[1])+1), true);
}
{
RemoteCommandEvent::removeTaggedString(tag);
}
ConsoleFunction( addTaggedString, const char*, 2, 2, "(string str)"
DefineEngineFunction(addTaggedString, const char* , (const char* str), (""),
"@brief Use the addTaggedString function to tag a new string and add it to the NetStringTable\n\n"
"@param str The string to be tagged and placed in the NetStringTable. Tagging ignores case, "
@ -306,17 +323,12 @@ ConsoleFunction( addTaggedString, const char*, 2, 2, "(string str)"
"@see removeTaggedString()\n"
"@see getTaggedString()\n"
"@ingroup Networking\n")
{
NetStringHandle s((const char*)argv[1]);
gNetStringTable->incStringRefScript(s.getIndex());
{
return RemoteCommandEvent::addTaggedString(str);
}
char *ret = Con::getReturnBuffer(10);
ret[0] = StringTagPrefixByte;
dSprintf(ret + 1, 9, "%d", s.getIndex());
return ret;
}
ConsoleFunction( getTaggedString, const char*, 2, 2, "(int tag)"
DefineEngineFunction(getTaggedString, const char* , (const char *tag), (""),
"@brief Use the getTaggedString function to convert a tag to a string.\n\n"
"This is not the same as detag() which can only be used within the context "
@ -331,12 +343,11 @@ ConsoleFunction( getTaggedString, const char*, 2, 2, "(int tag)"
"@see addTaggedString()\n"
"@see removeTaggedString()\n"
"@ingroup Networking\n")
{
const char *indexPtr = argv[1];
if (*indexPtr == StringTagPrefixByte)
indexPtr++;
return gNetStringTable->lookupString(dAtoi(indexPtr));
}
{
return RemoteCommandEvent::getTaggedString(tag);
}
ConsoleFunction( buildTaggedString, const char*, 2, 11, "(string format, ...)"
"@brief Build a string using the specified tagged string format.\n\n"
@ -373,10 +384,11 @@ ConsoleFunction( buildTaggedString, const char*, 2, 11, "(string format, ...)"
if (*indexPtr == StringTagPrefixByte)
indexPtr++;
const char *fmtString = gNetStringTable->lookupString(dAtoi(indexPtr));
char *strBuffer = Con::getReturnBuffer(512);
static const U32 bufSize = 512;
char *strBuffer = Con::getReturnBuffer(bufSize);
const char *fmtStrPtr = fmtString;
char *strBufPtr = strBuffer;
S32 strMaxLength = 511;
S32 strMaxLength = bufSize - 1;
if (!fmtString)
goto done;

View file

@ -0,0 +1,59 @@
#ifndef _NET_H_
#define _NET_H_
#include "platform/platform.h"
#include "core/dnet.h"
#include "core/idGenerator.h"
#include "core/stream/bitStream.h"
#include "console/simBase.h"
#include "console/console.h"
#include "console/consoleTypes.h"
#include "sim/netConnection.h"
#include "sim/netObject.h"
#include "app/net/serverQuery.h"
#include "console/engineAPI.h"
class RemoteCommandEvent : public NetEvent
{
public:
typedef NetEvent Parent;
enum {
MaxRemoteCommandArgs = 20,
CommandArgsBits = 5
};
private:
S32 mArgc;
char *mArgv[MaxRemoteCommandArgs + 1];
NetStringHandle mTagv[MaxRemoteCommandArgs + 1];
static char mBuf[1024];
public:
RemoteCommandEvent(S32 argc=0, const char **argv=NULL, NetConnection *conn = NULL);
#ifdef TORQUE_DEBUG_NET
const char *getDebugName();
#endif
~RemoteCommandEvent();
virtual void pack(NetConnection* conn, BitStream *bstream);
virtual void write(NetConnection* conn, BitStream *bstream);
virtual void unpack(NetConnection* conn, BitStream *bstream);
virtual void process(NetConnection *conn);
static void sendRemoteCommand(NetConnection *conn, S32 argc, const char **argv);
static void removeTaggedString(S32);
static const char* addTaggedString(const char* str);
static const char* getTaggedString(const char* tag);
DECLARE_CONOBJECT(RemoteCommandEvent);
};
#endif

View file

@ -22,7 +22,6 @@
#include "platform/platform.h"
#include "console/simBase.h"
#include "platform/event.h"
#include "sim/netConnection.h"
#include "core/stream/bitStream.h"
#include "sim/netObject.h"

View file

@ -96,7 +96,6 @@
#include "app/net/serverQuery.h"
#include "platform/platform.h"
#include "platform/event.h"
#include "core/dnet.h"
#include "core/util/tVector.h"
#include "core/stream/bitStream.h"

View file

@ -26,9 +26,6 @@
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#endif
#ifndef _EVENT_H_
#include "platform/event.h"
#endif
#ifndef _BITSET_H_
#include "core/bitSet.h"
#endif

View file

@ -23,7 +23,6 @@
#include "app/net/tcpObject.h"
#include "platform/platform.h"
#include "platform/event.h"
#include "console/simBase.h"
#include "console/consoleInternal.h"
#include "core/strings/stringUnit.h"
@ -422,7 +421,7 @@ DefineEngineMethod(TCPObject, send, void, (const char *data),,
object->send( (const U8*)data, dStrlen(data) );
}
DefineEngineMethod(TCPObject, listen, void, (int port),,
DefineEngineMethod(TCPObject, listen, void, (U32 port),,
"@brief Start listening on the specified port for connections.\n\n"
"This method starts a listener which looks for incoming TCP connections to a port. "

View file

@ -25,23 +25,35 @@
#include "console/console.h"
static const U32 csgVersionNumber = TORQUE_GAME_ENGINE;
static const U32 appVersionNumber = TORQUE_APP_VERSION;
U32 getVersionNumber()
{
return csgVersionNumber;
}
U32 getAppVersionNumber()
{
return appVersionNumber;
}
const char* getVersionString()
{
return TORQUE_GAME_ENGINE_VERSION_STRING;
}
const char* getAppVersionString()
{
return TORQUE_APP_VERSION_STRING;
}
/// TGE 0001
/// TGEA 0002
/// TGB 0003
/// TGEA 360 0004
/// TGE WII 0005
/// Torque 3D 0006
/// Torque 3D MIT 0007
const char* getEngineProductString()
{
@ -62,7 +74,9 @@ const char* getEngineProductString()
return "Torque for Wii";
case 0006:
return "Torque 3D";
case 0007:
return "Torque 3D MIT";
default:
return "Torque Engine";
};
@ -77,18 +91,31 @@ const char* getCompileTimeString()
ConsoleFunctionGroupBegin( CompileInformation, "Functions to get version information about the current executable." );
ConsoleFunction( getVersionNumber, S32, 1, 1, "Get the version of the build, as a string.\n\n"
ConsoleFunction( getVersionNumber, S32, 1, 1, "Get the version of the engine build, as a string.\n\n"
"@ingroup Debugging")
{
return getVersionNumber();
}
ConsoleFunction( getVersionString, const char*, 1, 1, "Get the version of the build, as a string.\n\n"
ConsoleFunction( getAppVersionNumber, S32, 1, 1, "Get the version of the application build, as a string.\n\n"
"@ingroup Debugging")
{
return getAppVersionNumber();
}
ConsoleFunction( getVersionString, const char*, 1, 1, "Get the version of the engine build, as a human readable string.\n\n"
"@ingroup Debugging")
{
return getVersionString();
}
ConsoleFunction( getAppVersionString, const char*, 1, 1, "Get the version of the aplication, as a human readable string.\n\n"
"@ingroup Debugging")
{
return getAppVersionString();
}
ConsoleFunction( getEngineName, const char*, 1, 1, "Get the name of the engine product that this is running from, as a string.\n\n"
"@ingroup Debugging")
{

View file

@ -23,23 +23,41 @@
#ifndef _VERSION_H_
#define _VERSION_H_
/// Since we can build different engine "products" out of the same
/// base engine source we need a way to differentiate which product
/// this particular game is using.
///
/// TGE 0001
/// TGEA 0002
/// TGB 0003
/// TGEA 360 0004
/// TGE WII 0005
/// Torque 3D 0006
/// Torque 3D MIT 0007
#define TORQUE_ENGINE_PRODUCT 0007
/// This is our global version number for the engine source code that
/// we are using. See <game>/source/torqueConfig.h for the game's source
/// 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.
#define TORQUE_GAME_ENGINE 1100
#define TORQUE_GAME_ENGINE 3610
/// Human readable engine version string.
#define TORQUE_GAME_ENGINE_VERSION_STRING "2011"
#define TORQUE_GAME_ENGINE_VERSION_STRING "3.6.1"
/// Gets the specified 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();
/// Gets the version number in string form
/// Gets the engine version number in a human readable form
const char* getVersionString();
/// Gets the engine product name in string form
const char* getEngineProductString();
/// Gets the compile date and time
const char* getCompileTimeString();
/// Gets the application version number. The version number is specified as a global in torqueConfig.h
U32 getAppVersionNumber();
/// Gets the human readable application version string.
const char* getAppVersionString();
#endif

View file

@ -43,7 +43,7 @@ extern "C" {
return so->getClassName();
}
void *SimObject_GetFieldList(SimObject *so, int &outNumFields)
void *SimObject_GetFieldList(SimObject *so, S32 &outNumFields)
{
const AbstractClassRep::FieldList &fl = so->getFieldList();
outNumFields = fl.size();

View file

@ -29,7 +29,7 @@
// External scripting cinterface, suitable for import into any scripting system which support "C" interfaces (C#, Python, Lua, Java, etc)
#ifdef TORQUE_OS_WIN32
#ifdef TORQUE_OS_WIN
#include "windowManager/win32/win32Window.h"
#include "windowManager/win32/winDispatch.h"
#endif
@ -164,7 +164,7 @@ extern "C" {
return false;
}
void script_simobject_setfield_int(U32 objectId, const char* fieldName, int v)
void script_simobject_setfield_int(U32 objectId, const char* fieldName, S32 v)
{
SimObject *object = Sim::findObject( objectId );
if( object )
@ -223,7 +223,7 @@ extern "C" {
{
// maxArgs improper on a number of console function/methods
if (argc < entry->mMinArgs)// || argc > entry->mMaxArgs)
return "";
return false;
SimObject* o = NULL;
@ -231,7 +231,7 @@ extern "C" {
{
o = Sim::findObject(dAtoi(argv[1]));
if (!o)
return "";
return false;
}
StringStackConsoleWrapper args(argc, argv);
@ -296,12 +296,12 @@ extern "C" {
entry->cb.mVoidCallbackFunc(o, args.count(), args);
}
int script_simobject_get_id(SimObject* so)
S32 script_simobject_get_id(SimObject* so)
{
return so->getId();
}
int script_simobject_find(const char* classname, const char* name)
S32 script_simobject_find(const char* classname, const char* name)
{
SimObject *object;
if( Sim::findObject( name, object ) )
@ -388,9 +388,9 @@ extern "C" {
}
#ifdef TORQUE_OS_WIN32
#ifdef TORQUE_OS_WIN
void script_input_event(int type, int value1, int value2)
void script_input_event(S32 type, S32 value1, S32 value2)
{
if (PlatformWindowManager::get() && PlatformWindowManager::get()->getFirstWindow())
{

View file

@ -29,7 +29,7 @@
#include "windowManager/platformWindow.h"
#include "windowManager/platformWindowMgr.h"
#ifdef TORQUE_OS_WIN32
#ifdef TORQUE_OS_WIN
#include "windowManager/win32/win32Window.h"
#include "windowManager/win32/winDispatch.h"
extern void createFontInit(void);
@ -37,7 +37,7 @@ extern void createFontShutdown(void);
#endif
#if defined( TORQUE_MINIDUMP ) && defined( TORQUE_RELEASE )
extern INT CreateMiniDump(LPEXCEPTION_POINTERS ExceptionInfo);
extern S32 CreateMiniDump(LPEXCEPTION_POINTERS ExceptionInfo);
#endif
static HashTable<StringTableEntry,StringTableEntry> gSecureScript;
@ -47,7 +47,7 @@ static HashTable<StringTableEntry,StringTableEntry> gSecureScript;
// ObjC hooks for shared library support
// See: macMain.mm
void torque_mac_engineinit(int argc, const char **argv);
void torque_mac_engineinit(S32 argc, const char **argv);
void torque_mac_enginetick();
void torque_mac_engineshutdown();
@ -64,7 +64,7 @@ extern "C" {
}
// initialize Torque 3D including argument handling
int torque_engineinit(S32 argc, const char **argv)
S32 torque_engineinit(S32 argc, const char **argv)
{
#if defined( TORQUE_MINIDUMP ) && defined( TORQUE_RELEASE )
@ -105,7 +105,7 @@ extern "C" {
}
// tick Torque 3D's main loop
int torque_enginetick()
S32 torque_enginetick()
{
#if defined( TORQUE_MINIDUMP ) && defined( TORQUE_RELEASE )
@ -139,7 +139,7 @@ extern "C" {
}
// shutdown the engine
int torque_engineshutdown()
S32 torque_engineshutdown()
{
#if defined( TORQUE_MINIDUMP ) && defined( TORQUE_RELEASE )
@ -181,7 +181,7 @@ extern "C" {
}
int torque_getconsolebool(const char* name)
S32 torque_getconsolebool(const char* name)
{
return Con::getBoolVariable(name);
}
@ -307,7 +307,7 @@ extern "C" {
Namespace::Entry* entry = GetEntry(nameSpace, name);
if (!entry)
return "";
return false;
StringStackConsoleWrapper args(argc, argv);
return entry->cb.mBoolCallbackFunc(NULL, args.count(), args);
@ -421,7 +421,7 @@ extern "C" {
PlatformWindowManager::get()->getFirstWindow()->setSize(Point2I(width,height));
}
#ifdef TORQUE_OS_WIN32
#ifdef TORQUE_OS_WIN
// retrieve the hwnd of our render window
void* torque_gethwnd()
{
@ -474,9 +474,10 @@ ConsoleFunction(testJavaScriptBridge, const char *, 4, 4, "testBridge(arg1, arg2
if (dStrcmp(jret,"42"))
failed = 3;
char *ret = Con::getReturnBuffer(256);
static const U32 bufSize = 256;
char *ret = Con::getReturnBuffer(bufSize);
dSprintf(ret, 256, "%i", failed);
dSprintf(ret, bufSize, "%i", failed);
return ret;
}

View file

@ -96,7 +96,7 @@ public:
}
// Accessors
int getCount() const { return mCount; }
S32 getCount() const { return mCount; }
F32 getTime() const { return mT; }
F32 getMaxHeight() const { return mMaxHeight; }

View file

@ -83,7 +83,6 @@ enum ConvexType {
TSConvexType,
BoxConvexType,
TerrainConvexType,
InteriorConvexType,
ShapeBaseConvexType,
TSStaticConvexType,
AtlasChunkConvexType, ///< @deprecated

View file

@ -69,21 +69,21 @@ void GjkCollisionState::swap()
void GjkCollisionState::compute_det()
{
// Dot new point with current set
for (int i = 0, bit = 1; i < 4; ++i, bit <<=1)
for (S32 i = 0, bit = 1; i < 4; ++i, bit <<=1)
if (bits & bit)
dp[i][last] = dp[last][i] = mDot(y[i], y[last]);
dp[last][last] = mDot(y[last], y[last]);
// Calulate the determinent
det[last_bit][last] = 1;
for (int j = 0, sj = 1; j < 4; ++j, sj <<= 1) {
for (S32 j = 0, sj = 1; j < 4; ++j, sj <<= 1) {
if (bits & sj) {
int s2 = sj | last_bit;
S32 s2 = sj | last_bit;
det[s2][j] = dp[last][last] - dp[last][j];
det[s2][last] = dp[j][j] - dp[j][last];
for (int k = 0, sk = 1; k < j; ++k, sk <<= 1) {
for (S32 k = 0, sk = 1; k < j; ++k, sk <<= 1) {
if (bits & sk) {
int s3 = sk | s2;
S32 s3 = sk | s2;
det[s3][k] = det[s2][j] * (dp[j][j] - dp[j][k]) +
det[s2][last] * (dp[last][j] - dp[last][k]);
det[s3][j] = det[sk | last_bit][k] * (dp[k][k] - dp[k][j]) +
@ -114,11 +114,11 @@ void GjkCollisionState::compute_det()
//----------------------------------------------------------------------------
inline void GjkCollisionState::compute_vector(int bits, VectorF& v)
inline void GjkCollisionState::compute_vector(S32 bits, VectorF& v)
{
F32 sum = 0;
v.set(0, 0, 0);
for (int i = 0, bit = 1; i < 4; ++i, bit <<= 1) {
for (S32 i = 0, bit = 1; i < 4; ++i, bit <<= 1) {
if (bits & bit) {
sum += det[bits][i];
v += y[i] * det[bits][i];
@ -130,9 +130,9 @@ inline void GjkCollisionState::compute_vector(int bits, VectorF& v)
//----------------------------------------------------------------------------
inline bool GjkCollisionState::valid(int s)
inline bool GjkCollisionState::valid(S32 s)
{
for (int i = 0, bit = 1; i < 4; ++i, bit <<= 1) {
for (S32 i = 0, bit = 1; i < 4; ++i, bit <<= 1) {
if (all_bits & bit) {
if (s & bit) {
if (det[s][i] <= 0)
@ -152,7 +152,7 @@ inline bool GjkCollisionState::valid(int s)
inline bool GjkCollisionState::closest(VectorF& v)
{
compute_det();
for (int s = bits; s; --s) {
for (S32 s = bits; s; --s) {
if ((s & bits) == s) {
if (valid(s | last_bit)) {
bits = s | last_bit;
@ -175,7 +175,7 @@ inline bool GjkCollisionState::closest(VectorF& v)
inline bool GjkCollisionState::degenerate(const VectorF& w)
{
for (int i = 0, bit = 1; i < 4; ++i, bit <<= 1)
for (S32 i = 0, bit = 1; i < 4; ++i, bit <<= 1)
if ((all_bits & bit) && y[i] == w)
return true;
return false;
@ -256,7 +256,7 @@ void GjkCollisionState::getClosestPoints(Point3F& p1, Point3F& p2)
F32 sum = 0;
p1.set(0, 0, 0);
p2.set(0, 0, 0);
for (int i = 0, bit = 1; i < 4; ++i, bit <<= 1) {
for (S32 i = 0, bit = 1; i < 4; ++i, bit <<= 1) {
if (bits & bit) {
sum += det[bits][i];
p1 += p[i] * det[bits][i];

Some files were not shown because too many files have changed in this diff Show more