Merge branch 'development' into style-cleanup

Conflicts:
	Engine/source/console/astNodes.cpp
	Engine/source/console/codeBlock.cpp
	Engine/source/console/compiledEval.cpp
	Engine/source/ts/collada/colladaAppMesh.cpp
	Engine/source/ts/tsShape.cpp
	Engine/source/ts/tsShapeConstruct.cpp
This commit is contained in:
Daniel Buckmaster 2014-12-15 12:15:55 +11:00
commit 33ff180593
2053 changed files with 172002 additions and 69530 deletions

View file

@ -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

@ -147,6 +147,7 @@ ConsoleFunction(aiConnect, S32 , 2, 20, "(...)"
// Make sure and leav args[1] empty.
const char* args[21];
args[0] = "onConnect";
args[1] = NULL; // Filled in later
for (S32 i = 1; i < argc; i++)
args[i + 1] = argv[i];

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,28 +419,21 @@ 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,
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
@ -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

@ -214,7 +214,7 @@ void CameraSpline::renderTimeMap()
// Render the buffer
GFX->pushWorldMatrix();
GFX->disableShaders();
GFX->setupGenericShaders();
GFX->setVertexBuffer(vb);
GFX->drawPrimitive(GFXLineStrip,0,index);
GFX->popWorldMatrix();

View file

@ -41,7 +41,7 @@
#include "lighting/lightQuery.h"
const U32 csmStaticCollisionMask = TerrainObjectType;
const U32 csmStaticCollisionMask = TerrainObjectType | StaticShapeObjectType | StaticObjectType;
const U32 csmDynamicCollisionMask = StaticShapeObjectType;
@ -99,7 +99,6 @@ DebrisData::DebrisData()
friction = 0.2f;
numBounces = 0;
bounceVariance = 0;
minSpinSpeed = maxSpinSpeed = 0.0;
staticOnMaxBounce = false;
explodeOnMaxBounce = false;
snapOnMaxBounce = false;
@ -511,6 +510,12 @@ bool Debris::onAdd()
return false;
}
if( !mDataBlock )
{
Con::errorf("Debris::onAdd - Fail - No datablock");
return false;
}
// create emitters
for( S32 i=0; i<DebrisData::DDC_NUM_EMITTERS; i++ )
{
@ -653,8 +658,7 @@ void Debris::onRemove()
}
}
getSceneManager()->removeObjectFromScene(this);
getContainer()->removeObject(this);
removeFromScene();
Parent::onRemove();
}

View file

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

View file

@ -749,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");
@ -784,6 +784,7 @@ bool ExplosionData::preload(bool server, String &errorStr)
//--------------------------------------
//
Explosion::Explosion()
: mDataBlock( NULL )
{
mTypeMask |= ExplosionObjectType | LightObjectType;
@ -844,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 );
@ -957,10 +964,7 @@ void Explosion::onRemove()
mMainEmitter = NULL;
}
if (getSceneManager() != NULL)
getSceneManager()->removeObjectFromScene(this);
if (getContainer() != NULL)
getContainer()->removeObject(this);
removeFromScene();
Parent::onRemove();
}

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++)
{

View file

@ -1168,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)
@ -1668,7 +1666,7 @@ void Precipitation::renderObject(ObjectRenderInst *ri, SceneRenderState *state,
}
else
{
GFX->disableShaders();
GFX->setupGenericShaders(GFXDevice::GSTexture);
// We don't support distance fade or lighting without shaders.
GFX->setStateBlock(mDistantSB);
@ -1801,7 +1799,7 @@ void Precipitation::renderObject(ObjectRenderInst *ri, SceneRenderState *state,
GFX->setShaderConstBuffer(mSplashShaderConsts);
}
else
GFX->disableShaders();
GFX->setupGenericShaders(GFXDevice::GSTexture);
while (curr)
{

View file

@ -0,0 +1,707 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "console/consoleTypes.h"
#include "console/typeValidators.h"
#include "core/stream/bitStream.h"
#include "T3D/shapeBase.h"
#include "ts/tsShapeInstance.h"
#include "T3D/fx/ribbon.h"
#include "math/mathUtils.h"
#include "math/mathIO.h"
#include "sim/netConnection.h"
#include "gfx/primBuilder.h"
#include "gfx/gfxDrawUtil.h"
#include "materials/sceneData.h"
#include "materials/matInstance.h"
#include "gui/3d/guiTSControl.h"
#include "materials/materialManager.h"
#include "materials/processedShaderMaterial.h"
#include "gfx/gfxTransformSaver.h"
IMPLEMENT_CO_DATABLOCK_V1(RibbonData);
IMPLEMENT_CO_NETOBJECT_V1(Ribbon);
//--------------------------------------------------------------------------
//
RibbonData::RibbonData()
{
for (U8 i = 0; i < NumFields; i++) {
mSizes[i] = 0.0f;
mColours[i].set(0.0f, 0.0f, 0.0f, 1.0f);
mTimes[i] = -1.0f;
}
mRibbonLength = 0;
mUseFadeOut = false;
mFadeAwayStep = 0.032f;
segmentsPerUpdate = 1;
mMatName = StringTable->insert("");
mTileScale = 1.0f;
mFixedTexcoords = false;
mSegmentSkipAmount = 0;
mTexcoordsRelativeToDistance = false;
}
//--------------------------------------------------------------------------
void RibbonData::initPersistFields()
{
Parent::initPersistFields();
addGroup("Ribbon");
addField("size", TypeF32, Offset(mSizes, RibbonData), NumFields,
"The size of the ribbon at the specified keyframe.");
addField("color", TypeColorF, Offset(mColours, RibbonData), NumFields,
"The colour of the ribbon at the specified keyframe.");
addField("position", TypeF32, Offset(mTimes, RibbonData), NumFields,
"The position of the keyframe along the lifetime of the ribbon.");
addField("ribbonLength", TypeS32, Offset(mRibbonLength, RibbonData),
"The amount of segments the Ribbon can maximally have in length.");
addField("segmentsPerUpdate", TypeS32, Offset(segmentsPerUpdate, RibbonData),
"How many segments to add each update.");
addField("skipAmount", TypeS32, Offset(mSegmentSkipAmount, RibbonData),
"The amount of segments to skip each update.");
addField("useFadeOut", TypeBool, Offset(mUseFadeOut, RibbonData),
"If true, the ribbon will fade away after deletion.");
addField("fadeAwayStep", TypeF32, Offset(mFadeAwayStep, RibbonData),
"How much to fade the ribbon with each update, after deletion.");
addField("ribbonMaterial", TypeString, Offset(mMatName, RibbonData),
"The material the ribbon uses for rendering.");
addField("tileScale", TypeF32, Offset(mTileScale, RibbonData),
"How much to scale each 'tile' with, where 1 means the material is stretched"
"across the whole ribbon. (If TexcoordsRelativeToDistance is true, this is in meters.)");
addField("fixedTexcoords", TypeBool, Offset(mFixedTexcoords, RibbonData),
"If true, this prevents 'floating' texture coordinates.");
addField("texcoordsRelativeToDistance", TypeBool, Offset(mTexcoordsRelativeToDistance, RibbonData),
"If true, texture coordinates are scaled relative to distance, this prevents"
"'stretched' textures.");
endGroup("Ribbon");
}
//--------------------------------------------------------------------------
bool RibbonData::onAdd()
{
if(!Parent::onAdd())
return false;
return true;
}
bool RibbonData::preload(bool server, String &errorBuffer)
{
if (Parent::preload(server, errorBuffer) == false)
return false;
return true;
}
//--------------------------------------------------------------------------
void RibbonData::packData(BitStream* stream)
{
Parent::packData(stream);
for (U8 i = 0; i < NumFields; i++) {
stream->write(mSizes[i]);
stream->write(mColours[i]);
stream->write(mTimes[i]);
}
stream->write(mRibbonLength);
stream->writeString(mMatName);
stream->writeFlag(mUseFadeOut);
stream->write(mFadeAwayStep);
stream->write(segmentsPerUpdate);
stream->write(mTileScale);
stream->writeFlag(mFixedTexcoords);
stream->writeFlag(mTexcoordsRelativeToDistance);
}
void RibbonData::unpackData(BitStream* stream)
{
Parent::unpackData(stream);
for (U8 i = 0; i < NumFields; i++) {
stream->read(&mSizes[i]);
stream->read(&mColours[i]);
stream->read(&mTimes[i]);
}
stream->read(&mRibbonLength);
mMatName = StringTable->insert(stream->readSTString());
mUseFadeOut = stream->readFlag();
stream->read(&mFadeAwayStep);
stream->read(&segmentsPerUpdate);
stream->read(&mTileScale);
mFixedTexcoords = stream->readFlag();
mTexcoordsRelativeToDistance = stream->readFlag();
}
//--------------------------------------------------------------------------
//--------------------------------------
//
Ribbon::Ribbon()
{
mTypeMask |= StaticObjectType;
VECTOR_SET_ASSOCIATION(mSegmentPoints);
mSegmentPoints.clear();
mRibbonMat = NULL;
mUpdateBuffers = true;
mDeleteOnEnd = false;
mUseFadeOut = false;
mFadeAwayStep = 1.0f;
mFadeOut = 1.0f;
mNetFlags.clear(Ghostable);
mNetFlags.set(IsGhost);
mRadiusSC = NULL;
mRibbonProjSC = NULL;
mSegmentOffset = 0;
mSegmentIdx = 0;
mTravelledDistance = 0;
}
Ribbon::~Ribbon()
{
//Make sure we cleanup
SAFE_DELETE(mRibbonMat);
}
//--------------------------------------------------------------------------
void Ribbon::initPersistFields()
{
Parent::initPersistFields();
}
bool Ribbon::onAdd()
{
if(!Parent::onAdd())
return false;
// add to client side mission cleanup
SimGroup *cleanup = dynamic_cast<SimGroup *>( Sim::findObject( "ClientMissionCleanup") );
if( cleanup != NULL )
{
cleanup->addObject( this );
}
else
{
AssertFatal( false, "Error, could not find ClientMissionCleanup group" );
return false;
}
if (!isServerObject()) {
if(GFX->getPixelShaderVersion() >= 1.1 && dStrlen(mDataBlock->mMatName) > 0 )
{
mRibbonMat = MATMGR->createMatInstance( mDataBlock->mMatName );
GFXStateBlockDesc desc;
desc.setZReadWrite( true, false );
desc.cullDefined = true;
desc.cullMode = GFXCullNone;
desc.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);
desc.samplersDefined = true;
GFXSamplerStateDesc sDesc(GFXSamplerStateDesc::getClampLinear());
sDesc.addressModeV = GFXAddressWrap;
desc.samplers[0] = sDesc;
mRibbonMat->addStateBlockDesc( desc );
mRibbonMat->init(MATMGR->getDefaultFeatures(), getGFXVertexFormat<GFXVertexPCNTT>());
mRadiusSC = mRibbonMat->getMaterialParameterHandle( "$radius" );
mRibbonProjSC = mRibbonMat->getMaterialParameterHandle( "$ribbonProj" );
} else {
Con::warnf( "Invalid Material name: %s: for Ribbon", mDataBlock->mMatName );
#ifdef TORQUE_DEBUG
Con::warnf( "- This could be caused by having the shader data datablocks in server-only code." );
#endif
mRibbonMat = NULL;
}
}
mObjBox.minExtents.set( 1.0f, 1.0f, 1.0f );
mObjBox.maxExtents.set( 2.0f, 2.0f, 2.0f );
// Reset the World Box.
resetWorldBox();
// Set the Render Transform.
setRenderTransform(mObjToWorld);
addToScene();
return true;
}
void Ribbon::onRemove()
{
removeFromScene();
SAFE_DELETE(mRibbonMat);
Parent::onRemove();
}
bool Ribbon::onNewDataBlock(GameBaseData* dptr, bool reload)
{
mDataBlock = dynamic_cast<RibbonData*>(dptr);
if (!mDataBlock || !Parent::onNewDataBlock(dptr, reload))
return false;
return true;
}
void Ribbon::processTick(const Move* move)
{
Parent::processTick(move);
if (mDeleteOnEnd) {
if (mUseFadeOut) {
if (mFadeOut <= 0.0f) {
mFadeOut = 0.0f;
//delete this class
mDeleteOnEnd = false;
safeDeleteObject();
return;
}
mFadeOut -= mFadeAwayStep;
if (mFadeOut < 0.0f) {
mFadeOut = 0.0f;
}
mUpdateBuffers = true;
} else {
//if (mSegmentPoints.size() == 0) {
//delete this class
mDeleteOnEnd = false;
safeDeleteObject();
return;
//}
//mSegmentPoints.pop_back();
}
}
}
void Ribbon::advanceTime(F32 dt)
{
Parent::advanceTime(dt);
}
void Ribbon::interpolateTick(F32 delta)
{
Parent::interpolateTick(delta);
}
void Ribbon::addSegmentPoint(Point3F &point, MatrixF &mat) {
//update our position
setRenderTransform(mat);
MatrixF xform(true);
xform.setColumn(3, point);
setTransform(xform);
if(mSegmentIdx < mDataBlock->mSegmentSkipAmount)
{
mSegmentIdx++;
return;
}
mSegmentIdx = 0;
U32 segmentsToDelete = checkRibbonDistance(mDataBlock->segmentsPerUpdate);
for (U32 i = 0; i < segmentsToDelete; i++) {
U32 last = mSegmentPoints.size() - 1;
if (last < 0)
break;
mTravelledDistance += last ? (mSegmentPoints[last] - mSegmentPoints[last-1]).len() : 0;
mSegmentPoints.pop_back();
mUpdateBuffers = true;
mSegmentOffset++;
}
//If there is no other points, just add a new one.
if (mSegmentPoints.size() == 0) {
mSegmentPoints.push_front(point);
mUpdateBuffers = true;
return;
}
Point3F startPoint = mSegmentPoints[0];
//add X points based on how many segments Per Update from last point to current point
for (U32 i = 0; i < mDataBlock->segmentsPerUpdate; i++) {
F32 interp = (F32(i+1) / (F32)mDataBlock->segmentsPerUpdate);
//(end - start) * percentage) + start
Point3F derivedPoint = ((point - startPoint) * interp) + startPoint;
mSegmentPoints.push_front(derivedPoint);
mUpdateBuffers = true;
}
if (mSegmentPoints.size() > 1) {
Point3F pointA = mSegmentPoints[mSegmentPoints.size()-1];
Point3F pointB = mSegmentPoints[0];
Point3F diffSize = pointA - pointB;
if (diffSize.x == 0.0f)
diffSize.x = 1.0f;
if (diffSize.y == 0.0f)
diffSize.y = 1.0f;
if (diffSize.z == 0.0f)
diffSize.z = 1.0f;
Box3F objBox;
objBox.minExtents.set( diffSize * -1 );
objBox.maxExtents.set( diffSize );
if (objBox.minExtents.x > objBox.maxExtents.x) {
F32 tmp = objBox.minExtents.x;
objBox.minExtents.x = objBox.maxExtents.x;
objBox.maxExtents.x = tmp;
}
if (objBox.minExtents.y > objBox.maxExtents.y) {
F32 tmp = objBox.minExtents.y;
objBox.minExtents.y = objBox.maxExtents.y;
objBox.maxExtents.y = tmp;
}
if (objBox.minExtents.z > objBox.maxExtents.z) {
F32 tmp = objBox.minExtents.z;
objBox.minExtents.z = objBox.maxExtents.z;
objBox.maxExtents.z = tmp;
}
if (objBox.isValidBox()) {
mObjBox = objBox;
// Reset the World Box.
resetWorldBox();
}
}
}
void Ribbon::deleteOnEnd() {
mDeleteOnEnd = true;
mUseFadeOut = mDataBlock->mUseFadeOut;
mFadeAwayStep = mDataBlock->mFadeAwayStep;
}
U32 Ribbon::checkRibbonDistance(S32 segments) {
S32 len = mSegmentPoints.size();
S32 difference = (mDataBlock->mRibbonLength/(mDataBlock->mSegmentSkipAmount+1)) - len;
if (difference < 0)
return mAbs(difference);
return 0; //do not delete any points
}
void Ribbon::setShaderParams() {
F32 numSegments = (F32)mSegmentPoints.size();
F32 length = (F32)mDataBlock->mRibbonLength;
Point3F radius(numSegments / length, numSegments, length);
MaterialParameters* matParams = mRibbonMat->getMaterialParameters();
matParams->setSafe( mRadiusSC, radius );
}
//--------------------------------------------------------------------------
//U32 Ribbon::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
//{
// U32 retMask = Parent::packUpdate(con, mask, stream);
// return retMask;
//}
//
//void Ribbon::unpackUpdate(NetConnection* con, BitStream* stream)
//{
// Parent::unpackUpdate(con, stream);
//}
//--------------------------------------------------------------------------
void Ribbon::prepRenderImage(SceneRenderState *state)
{
if (mFadeOut == 0.0f)
return;
if(!mRibbonMat)
return;
if (mDeleteOnEnd == true && mUseFadeOut == false) {
return;
}
// We only render during the normal diffuse render pass.
if( !state->isDiffusePass() )
return;
U32 segments = mSegmentPoints.size();
if (segments < 2)
return;
MeshRenderInst *ri = state->getRenderPass()->allocInst<MeshRenderInst>();
ri->type = RenderPassManager::RIT_Translucent;
ri->translucentSort = true;
ri->sortDistSq = ( mSegmentPoints[0] - state->getCameraPosition() ).lenSquared();
RenderPassManager *renderPass = state->getRenderPass();
MatrixF *proj = renderPass->allocUniqueXform(MatrixF( true ));
proj->mul(GFX->getProjectionMatrix());
proj->mul(GFX->getWorldMatrix());
ri->objectToWorld = &MatrixF::Identity;
ri->worldToCamera = &MatrixF::Identity;
ri->projection = proj;
ri->matInst = mRibbonMat;
// Set up our vertex buffer and primitive buffer
if(mUpdateBuffers)
createBuffers(state, verts, primBuffer, segments);
ri->vertBuff = &verts;
ri->primBuff = &primBuffer;
ri->visibility = 1.0f;
ri->prim = renderPass->allocPrim();
ri->prim->type = GFXTriangleList;
ri->prim->minIndex = 0;
ri->prim->startIndex = 0;
ri->prim->numPrimitives = (segments-1) * 2;
ri->prim->startVertex = 0;
ri->prim->numVertices = segments * 2;
if (mRibbonMat) {
ri->defaultKey = mRibbonMat->getStateHint();
} else {
ri->defaultKey = 1;
}
ri->defaultKey2 = (U32)ri->vertBuff; // Not 64bit safe!
state->getRenderPass()->addInst(ri);
}
void Ribbon::createBuffers(SceneRenderState *state, GFXVertexBufferHandle<GFXVertexPCNTT> &verts, GFXPrimitiveBufferHandle &pb, U32 segments) {
PROFILE_SCOPE( Ribbon_createBuffers );
Point3F cameraPos = state->getCameraPosition();
U32 count = 0;
U32 indexCount = 0;
verts.set(GFX, (segments*2), GFXBufferTypeDynamic);
// create index buffer based on that size
U32 indexListSize = (segments-1) * 6;
pb.set( GFX, indexListSize, 0, GFXBufferTypeDynamic );
U16 *indices = NULL;
verts.lock();
pb.lock( &indices );
F32 totalLength = 0;
if(mDataBlock->mTexcoordsRelativeToDistance)
{
for (U32 i = 0; i < segments; i++)
if (i != 0)
totalLength += (mSegmentPoints[i] - mSegmentPoints[i-1]).len();
}
U8 fixedAppend = 0;
F32 curLength = 0;
for (U32 i = 0; i < segments; i++) {
F32 interpol = ((F32)i / (F32)(segments-1));
Point3F leftvert = mSegmentPoints[i];
Point3F rightvert = mSegmentPoints[i];
F32 tRadius = mDataBlock->mSizes[0];
ColorF tColor = mDataBlock->mColours[0];
for (U8 j = 0; j < RibbonData::NumFields-1; j++) {
F32 curPosition = mDataBlock->mTimes[j];
F32 curRadius = mDataBlock->mSizes[j];
ColorF curColor = mDataBlock->mColours[j];
F32 nextPosition = mDataBlock->mTimes[j+1];
F32 nextRadius = mDataBlock->mSizes[j+1];
ColorF nextColor = mDataBlock->mColours[j+1];
if ( curPosition < 0
|| curPosition > interpol )
break;
F32 positionDiff = (interpol - curPosition) / (nextPosition - curPosition);
tRadius = curRadius + (nextRadius - curRadius) * positionDiff;
tColor.interpolate(curColor, nextColor, positionDiff);
}
Point3F diff;
F32 length;
if (i == 0) {
diff = mSegmentPoints[i+1] - mSegmentPoints[i];
length = 0;
} else if (i == segments-1) {
diff = mSegmentPoints[i] - mSegmentPoints[i-1];
length = diff.len();
} else {
diff = mSegmentPoints[i+1] - mSegmentPoints[i-1];
length = (mSegmentPoints[i] - mSegmentPoints[i-1]).len();
}
//left point
Point3F eyeMinPos = cameraPos - leftvert;
Point3F perpendicular = mCross(diff, eyeMinPos);
perpendicular.normalize();
perpendicular = perpendicular * tRadius * -1.0f;
perpendicular += mSegmentPoints[i];
verts[count].point.set(perpendicular);
ColorF color = tColor;
if (mDataBlock->mUseFadeOut)
color.alpha *= mFadeOut;
F32 texCoords;
if(mDataBlock->mFixedTexcoords && !mDataBlock->mTexcoordsRelativeToDistance)
{
U32 fixedIdx = (i+mDataBlock->mRibbonLength-mSegmentOffset)%mDataBlock->mRibbonLength;
if(fixedIdx == 0 && i > 0)
fixedAppend++;
F32 fixedInterpol = (F32)fixedIdx / (F32)(mDataBlock->mRibbonLength);
fixedInterpol += fixedAppend;
texCoords = (1.0f - fixedInterpol)*mDataBlock->mTileScale;
}
else if(mDataBlock->mTexcoordsRelativeToDistance)
texCoords = (mTravelledDistance + (totalLength - (curLength + length)))*mDataBlock->mTileScale;
else
texCoords = (1.0f - interpol)*mDataBlock->mTileScale;
verts[count].color = color;
verts[count].texCoord[1] = Point2F(interpol, 0);
verts[count].texCoord[0] = Point2F(0.0f, texCoords);
verts[count].normal.set(diff);
//Triangle strip style indexing, so grab last 2
if (count > 1) {
indices[indexCount] = count-2;
indexCount++;
indices[indexCount] = count;
indexCount++;
indices[indexCount] = count-1;
indexCount++;
}
count++;
eyeMinPos = cameraPos - rightvert;
perpendicular = mCross(diff, eyeMinPos);
perpendicular.normalize();
perpendicular = perpendicular * tRadius;
perpendicular += mSegmentPoints[i];
verts[count].point.set(perpendicular);
color = tColor;
if (mDataBlock->mUseFadeOut)
color.alpha *= mFadeOut;
verts[count].color = color;
verts[count].texCoord[1] = Point2F(interpol, 1);
verts[count].texCoord[0] = Point2F(1.0f, texCoords);
verts[count].normal.set(diff);
//Triangle strip style indexing, so grab last 2
if (count > 1) {
indices[indexCount] = count-2;
indexCount++;
indices[indexCount] = count-1;
indexCount++;
indices[indexCount] = count;
indexCount++;
}
count++;
curLength += length;
}
Point3F pointA = verts[count-1].point;
Point3F pointB = verts[0].point;
pb.unlock();
verts.unlock();
Point3F diffSize = pointA - pointB;
Box3F objBox;
objBox.minExtents.set( diffSize * -1 );
objBox.maxExtents.set( diffSize );
if (objBox.minExtents.x > objBox.maxExtents.x) {
F32 tmp = objBox.minExtents.x;
objBox.minExtents.x = objBox.maxExtents.x;
objBox.maxExtents.x = tmp;
}
if (objBox.minExtents.y > objBox.maxExtents.y) {
F32 tmp = objBox.minExtents.y;
objBox.minExtents.y = objBox.maxExtents.y;
objBox.maxExtents.y = tmp;
}
if (objBox.minExtents.z > objBox.maxExtents.z) {
F32 tmp = objBox.minExtents.z;
objBox.minExtents.z = objBox.maxExtents.z;
objBox.maxExtents.z = tmp;
}
if (objBox.isValidBox()) {
mObjBox = objBox;
// Reset the World Box.
resetWorldBox();
}
mUpdateBuffers = false;
}

View file

@ -0,0 +1,142 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _RIBBON_H_
#define _RIBBON_H_
#ifndef _GAMEBASE_H_
#include "T3D/gameBase/gameBase.h"
#endif
#ifndef _GFXPRIMITIVEBUFFER_H_
#include "gfx/gfxPrimitiveBuffer.h"
#endif
#ifndef _GFXVERTEXBUFFER_H_
#include "gfx/gfxVertexBuffer.h"
#endif
#include "materials/materialParameters.h"
#include "math/util/matrixSet.h"
//--------------------------------------------------------------------------
class RibbonData : public GameBaseData
{
typedef GameBaseData Parent;
protected:
bool onAdd();
public:
enum Constants
{
NumFields = 4
};
F32 mSizes[NumFields]; ///< The radius for each keyframe.
ColorF mColours[NumFields]; ///< The colour of the ribbon for each keyframe.
F32 mTimes[NumFields]; ///< The relative time for each keyframe.
U32 mRibbonLength; ///< The amount of segments that will make up the ribbon.
S32 segmentsPerUpdate; ///< Amount of segments to add each update.
S32 mSegmentSkipAmount; ///< The amount of segments to skip each time segments are added.
bool mUseFadeOut; ///< If true, the ribbon will fade away after deletion.
F32 mFadeAwayStep; ///< How quickly the ribbons is faded away after deletion.
StringTableEntry mMatName; ///< The material for the ribbon.
F32 mTileScale; ///< A scalar to scale the texcoord.
bool mFixedTexcoords; ///< If true, texcoords will stay the same over the lifetime for each segment.
bool mTexcoordsRelativeToDistance; ///< If true, texcoords will not be stretched if the distance between 2 segments are long.
RibbonData();
void packData(BitStream*);
void unpackData(BitStream*);
bool preload(bool server, String &errorBuffer);
static void initPersistFields();
DECLARE_CONOBJECT(RibbonData);
};
//--------------------------------------------------------------------------
class Ribbon : public GameBase
{
typedef GameBase Parent;
RibbonData* mDataBlock;
bool mDeleteOnEnd; ///< If true, the ribbon should delete itself as soon as the last segment is deleted
bool mUseFadeOut; ///< If true, the ribbon will fade away upon deletion
F32 mFadeAwayStep; ///< How quickly the ribbons is faded away after deletion.
F32 mFadeOut;
F32 mTravelledDistance; ///< How far the ribbon has travelled in it's lifetime.
Vector<Point3F> mSegmentPoints; ///< The points in space where the ribbon has spawned segments.
U32 mSegmentOffset;
U32 mSegmentIdx;
bool mUpdateBuffers; ///< If true, the vertex buffers need to be updated.
BaseMatInstance *mRibbonMat;
MaterialParameterHandle* mRadiusSC;
MaterialParameterHandle* mRibbonProjSC;
GFXPrimitiveBufferHandle primBuffer;
GFXVertexBufferHandle<GFXVertexPCNTT> verts;
protected:
bool onAdd();
void processTick(const Move*);
void advanceTime(F32);
void interpolateTick(F32 delta);
// Rendering
void prepRenderImage(SceneRenderState *state);
void setShaderParams();
///Checks to see if ribbon is too long
U32 checkRibbonDistance(S32 segments);
/// Construct the vertex and primitive buffers
void createBuffers(SceneRenderState *state, GFXVertexBufferHandle<GFXVertexPCNTT> &verts, GFXPrimitiveBufferHandle &pb, U32 segments);
public:
Ribbon();
~Ribbon();
DECLARE_CONOBJECT(Ribbon);
static void initPersistFields();
bool onNewDataBlock(GameBaseData*,bool);
void onRemove();
/// Used to add another segment to the ribbon.
void addSegmentPoint(Point3F &point, MatrixF &mat);
/// Delete all segments.
void clearSegments() { mSegmentPoints.clear(); }
/// Delete the ribbon when all segments have been deleted.
void deleteOnEnd();
};
#endif // _H_RIBBON

View file

@ -0,0 +1,324 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "ribbonNode.h"
#include "console/consoleTypes.h"
#include "core/stream/bitStream.h"
#include "T3D/fx/ribbon.h"
#include "math/mathIO.h"
#include "sim/netConnection.h"
#include "console/engineAPI.h"
IMPLEMENT_CO_DATABLOCK_V1(RibbonNodeData);
IMPLEMENT_CO_NETOBJECT_V1(RibbonNode);
ConsoleDocClass( RibbonNodeData,
"@brief Contains additional data to be associated with a RibbonNode."
"@ingroup FX\n"
);
ConsoleDocClass( RibbonNode, ""
);
//-----------------------------------------------------------------------------
// RibbonNodeData
//-----------------------------------------------------------------------------
RibbonNodeData::RibbonNodeData()
{
}
RibbonNodeData::~RibbonNodeData()
{
}
//-----------------------------------------------------------------------------
// initPersistFields
//-----------------------------------------------------------------------------
void RibbonNodeData::initPersistFields()
{
Parent::initPersistFields();
}
//-----------------------------------------------------------------------------
// RibbonNode
//-----------------------------------------------------------------------------
RibbonNode::RibbonNode()
{
// Todo: ScopeAlways?
mNetFlags.set(Ghostable);
mTypeMask |= EnvironmentObjectType;
mActive = true;
mDataBlock = NULL;
mRibbonDatablock = NULL;
mRibbonDatablockId = 0;
mRibbon = NULL;
}
//-----------------------------------------------------------------------------
// Destructor
//-----------------------------------------------------------------------------
RibbonNode::~RibbonNode()
{
//
}
//-----------------------------------------------------------------------------
// initPersistFields
//-----------------------------------------------------------------------------
void RibbonNode::initPersistFields()
{
addField( "active", TYPEID< bool >(), Offset(mActive,RibbonNode),
"Controls whether ribbon is emitted from this node." );
addField( "ribbon", TYPEID< RibbonData >(), Offset(mRibbonDatablock, RibbonNode),
"Datablock to use for the ribbon." );
Parent::initPersistFields();
}
//-----------------------------------------------------------------------------
// onAdd
//-----------------------------------------------------------------------------
bool RibbonNode::onAdd()
{
if( !Parent::onAdd() )
return false;
if( !mRibbonDatablock && mRibbonDatablockId != 0 )
{
if( Sim::findObject(mRibbonDatablockId, mRibbonDatablock) == false )
Con::errorf(ConsoleLogEntry::General, "RibbonNode::onAdd: Invalid packet, bad datablockId(mRibbonDatablock): %d", mRibbonDatablockId);
}
if( isClientObject() )
{
setRibbonDatablock( mRibbonDatablock );
}
else
{
setMaskBits( StateMask | EmitterDBMask );
}
mObjBox.minExtents.set(-0.5, -0.5, -0.5);
mObjBox.maxExtents.set( 0.5, 0.5, 0.5);
resetWorldBox();
addToScene();
return true;
}
//-----------------------------------------------------------------------------
// onRemove
//-----------------------------------------------------------------------------
void RibbonNode::onRemove()
{
removeFromScene();
if( isClientObject() )
{
if( mRibbon )
{
mRibbon->deleteOnEnd();
mRibbon = NULL;
}
}
Parent::onRemove();
}
//-----------------------------------------------------------------------------
// onNewDataBlock
//-----------------------------------------------------------------------------
bool RibbonNode::onNewDataBlock( GameBaseData *dptr, bool reload )
{
mDataBlock = dynamic_cast<RibbonNodeData*>( dptr );
if ( !mDataBlock || !Parent::onNewDataBlock( dptr, reload ) )
return false;
// Todo: Uncomment if this is a "leaf" class
scriptOnNewDataBlock();
return true;
}
//-----------------------------------------------------------------------------
void RibbonNode::inspectPostApply()
{
Parent::inspectPostApply();
setMaskBits(StateMask | EmitterDBMask);
}
//-----------------------------------------------------------------------------
// processTick
//-----------------------------------------------------------------------------
void RibbonNode::processTick(const Move* move)
{
Parent::processTick(move);
if ( isMounted() )
{
MatrixF mat;
mMount.object->getMountTransform( mMount.node, mMount.xfm, &mat );
setTransform( mat );
}
}
//-----------------------------------------------------------------------------
// advanceTime
//-----------------------------------------------------------------------------
void RibbonNode::advanceTime(F32 dt)
{
Parent::advanceTime(dt);
if(!mActive || mRibbon.isNull() || !mDataBlock)
return;
MatrixF trans(getTransform());
Point3F pos = getPosition();
mRibbon->addSegmentPoint(pos, trans);
}
//-----------------------------------------------------------------------------
// packUpdate
//-----------------------------------------------------------------------------
U32 RibbonNode::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
{
U32 retMask = Parent::packUpdate(con, mask, stream);
if ( stream->writeFlag( mask & InitialUpdateMask ) )
{
mathWrite(*stream, getTransform());
mathWrite(*stream, getScale());
}
if ( stream->writeFlag( mask & EmitterDBMask ) )
{
if( stream->writeFlag(mRibbonDatablock != NULL) )
{
stream->writeRangedU32(mRibbonDatablock->getId(), DataBlockObjectIdFirst,
DataBlockObjectIdLast);
}
}
if ( stream->writeFlag( mask & StateMask ) )
{
stream->writeFlag( mActive );
}
return retMask;
}
//-----------------------------------------------------------------------------
// unpackUpdate
//-----------------------------------------------------------------------------
void RibbonNode::unpackUpdate(NetConnection* con, BitStream* stream)
{
Parent::unpackUpdate(con, stream);
if ( stream->readFlag() )
{
MatrixF temp;
Point3F tempScale;
mathRead(*stream, &temp);
mathRead(*stream, &tempScale);
setScale(tempScale);
setTransform(temp);
}
if ( stream->readFlag() )
{
mRibbonDatablockId = stream->readFlag() ?
stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast) : 0;
RibbonData *emitterDB = NULL;
Sim::findObject( mRibbonDatablockId, emitterDB );
if ( isProperlyAdded() )
setRibbonDatablock( emitterDB );
}
if ( stream->readFlag() )
{
mActive = stream->readFlag();
}
}
//-----------------------------------------------------------------------------
// setRibbonDatablock
//-----------------------------------------------------------------------------
void RibbonNode::setRibbonDatablock(RibbonData* data)
{
if ( isServerObject() )
{
setMaskBits( EmitterDBMask );
}
else
{
Ribbon* pRibbon = NULL;
if ( data )
{
// Create emitter with new datablock
pRibbon = new Ribbon;
pRibbon->onNewDataBlock( data, false );
if( pRibbon->registerObject() == false )
{
Con::warnf(ConsoleLogEntry::General, "Could not register base ribbon of class: %s", data->getName() ? data->getName() : data->getIdString() );
delete pRibbon;
return;
}
}
// Replace emitter
if ( mRibbon )
mRibbon->deleteOnEnd();
mRibbon = pRibbon;
}
mRibbonDatablock = data;
}
DefineEngineMethod(RibbonNode, setRibbonDatablock, void, (RibbonData* ribbonDatablock), (0),
"Assigns the datablock for this ribbon node.\n"
"@param ribbonDatablock RibbonData datablock to assign\n"
"@tsexample\n"
"// Assign a new emitter datablock\n"
"%emitter.setRibbonDatablock( %ribbonDatablock );\n"
"@endtsexample\n" )
{
if ( !ribbonDatablock )
{
Con::errorf("RibbonData datablock could not be found when calling setRibbonDataBlock in ribbonNode.");
return;
}
object->setRibbonDatablock(ribbonDatablock);
}
DefineEngineMethod(RibbonNode, setActive, void, (bool active),,
"Turns the ribbon on or off.\n"
"@param active New ribbon state\n" )
{
object->setActive( active );
}

View file

@ -0,0 +1,105 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _RIBBON_NODE_H_
#define _RIBBON_NODE_H_
#ifndef _GAMEBASE_H_
#include "T3D/gameBase/gameBase.h"
#endif
class RibbonData;
class Ribbon;
//*****************************************************************************
// ParticleEmitterNodeData
//*****************************************************************************
class RibbonNodeData : public GameBaseData
{
typedef GameBaseData Parent;
public:
F32 timeMultiple;
public:
RibbonNodeData();
~RibbonNodeData();
DECLARE_CONOBJECT(RibbonNodeData);
static void initPersistFields();
};
//*****************************************************************************
// ParticleEmitterNode
//*****************************************************************************
class RibbonNode : public GameBase
{
typedef GameBase Parent;
enum MaskBits
{
StateMask = Parent::NextFreeMask << 0,
EmitterDBMask = Parent::NextFreeMask << 1,
NextFreeMask = Parent::NextFreeMask << 2,
};
RibbonNodeData* mDataBlock;
protected:
bool onAdd();
void onRemove();
bool onNewDataBlock( GameBaseData *dptr, bool reload );
void inspectPostApply();
RibbonData* mRibbonDatablock;
S32 mRibbonDatablockId;
SimObjectPtr<Ribbon> mRibbon;
bool mActive;
public:
RibbonNode();
~RibbonNode();
Ribbon *getRibbonEmitter() {return mRibbon;}
// Time/Move Management
void processTick(const Move* move);
void advanceTime(F32 dt);
DECLARE_CONOBJECT(RibbonNode);
static void initPersistFields();
U32 packUpdate (NetConnection *conn, U32 mask, BitStream* stream);
void unpackUpdate(NetConnection *conn, BitStream* stream);
inline bool getActive( void ) { return mActive; };
inline void setActive( bool active ) { mActive = active; setMaskBits( StateMask ); };
void setRibbonDatablock(RibbonData* data);
};
#endif // _RIBBON_NODE_H_

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,7 @@ void Splash::onRemove()
ringList.clear();
getSceneManager()->removeObjectFromScene(this);
getContainer()->removeObject(this);
removeFromScene();
Parent::onRemove();
}

View file

@ -281,7 +281,8 @@ ConsoleMethod(GameConnection, setConnectArgs, void, 3, 17,
"@see GameConnection::onConnect()\n\n")
{
object->setConnectArgs(argc - 2, argv + 2);
StringStackWrapper args(argc - 2, argv + 2);
object->setConnectArgs(args.count(), args);
}
void GameConnection::onTimedOut()
@ -323,6 +324,7 @@ void GameConnection::onConnectionEstablished(bool isInitiator)
const char *argv[MaxConnectArgs + 2];
argv[0] = "onConnect";
argv[1] = NULL; // Filled in later
for(U32 i = 0; i < mConnectArgc; i++)
argv[i + 2] = mConnectArgv[i];
// NOTE: Need to fallback to Con::execute() as IMPLEMENT_CALLBACK does not
@ -442,7 +444,7 @@ bool GameConnection::readConnectRequest(BitStream *stream, const char **errorStr
*errorString = "CR_INVALID_ARGS";
return false;
}
const char *connectArgv[MaxConnectArgs + 3];
ConsoleValueRef connectArgv[MaxConnectArgs + 3];
for(U32 i = 0; i < mConnectArgc; i++)
{
char argString[256];
@ -451,6 +453,7 @@ bool GameConnection::readConnectRequest(BitStream *stream, const char **errorStr
connectArgv[i + 3] = mConnectArgv[i];
}
connectArgv[0] = "onConnectRequest";
connectArgv[1] = NULL;
char buffer[256];
Net::addressToString(getNetAddress(), buffer);
connectArgv[2] = buffer;
@ -974,7 +977,7 @@ bool GameConnection::readDemoStartBlock(BitStream *stream)
void GameConnection::demoPlaybackComplete()
{
static const char *demoPlaybackArgv[1] = { "demoPlaybackComplete" };
static ConsoleValueRef demoPlaybackArgv[1] = { "demoPlaybackComplete" };
Sim::postCurrentEvent(Sim::getRootGroup(), new SimConsoleEvent(1, demoPlaybackArgv, false));
Parent::demoPlaybackComplete();
}

View file

@ -145,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';
@ -162,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';

View file

@ -110,7 +110,7 @@ GuiObjectView::GuiObjectView()
{
mCameraMatrix.identity();
mCameraRot.set( 0.0f, 0.0f, 3.9f );
mCameraPos.set( 0.0f, 1.75f, 1.25f );
mCameraPos.set( 0.0f, 0.0f, 0.0f );
mCameraMatrix.setColumn( 3, mCameraPos );
mOrbitPos.set( 0.0f, 0.0f, 0.0f );
@ -520,9 +520,9 @@ void GuiObjectView::renderWorld( const RectI& updateRect )
(
gClientSceneGraph,
SPT_Diffuse,
SceneCameraState( GFX->getViewport(), frust, GFX->getWorldMatrix(), GFX->getProjectionMatrix() ),
SceneCameraState( GFX->getViewport(), frust, MatrixF::Identity, GFX->getProjectionMatrix() ),
renderPass,
false
true
);
// Set up our TS render state here.

View file

@ -1241,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);
@ -1263,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

@ -439,7 +439,7 @@ ConsoleMethod( LightBase, playAnimation, void, 2, 3, "( [LightAnimData anim] )\t
LightAnimData *animData;
if ( !Sim::findObject( argv[2], animData ) )
{
Con::errorf( "LightBase::playAnimation() - Invalid LightAnimData '%s'.", argv[2] );
Con::errorf( "LightBase::playAnimation() - Invalid LightAnimData '%s'.", (const char*)argv[2] );
return;
}
@ -481,4 +481,4 @@ void LightBase::pauseAnimation( void )
mAnimState.active = false;
setMaskBits( UpdateMask );
}
}
}

View file

@ -176,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

@ -223,12 +223,6 @@ ConsoleDocClass( WayPoint,
"@ingroup enviroMisc\n"
);
WayPointTeam::WayPointTeam()
{
mTeamId = 0;
mWayPoint = 0;
}
WayPoint::WayPoint()
{
mName = StringTable->insert("");
@ -252,7 +246,6 @@ bool WayPoint::onAdd()
Sim::getWayPointSet()->addObject(this);
else
{
mTeam.mWayPoint = this;
setMaskBits(UpdateNameMask|UpdateTeamMask);
}
@ -272,8 +265,6 @@ U32 WayPoint::packUpdate(NetConnection * con, U32 mask, BitStream * stream)
U32 retMask = Parent::packUpdate(con, mask, stream);
if(stream->writeFlag(mask & UpdateNameMask))
stream->writeString(mName);
if(stream->writeFlag(mask & UpdateTeamMask))
stream->write(mTeam.mTeamId);
if(stream->writeFlag(mask & UpdateHiddenMask))
stream->writeFlag(isHidden());
return(retMask);
@ -284,47 +275,17 @@ void WayPoint::unpackUpdate(NetConnection * con, BitStream * stream)
Parent::unpackUpdate(con, stream);
if(stream->readFlag())
mName = stream->readSTString(true);
if(stream->readFlag())
stream->read(&mTeam.mTeamId);
if(stream->readFlag())
setHidden(stream->readFlag());
}
//-----------------------------------------------------------------------------
// TypeWayPointTeam
//-----------------------------------------------------------------------------
IMPLEMENT_STRUCT( WayPointTeam, WayPointTeam,,
"" )
END_IMPLEMENT_STRUCT;
//FIXME: this should work but does not; need to check the stripping down to base types within TYPE
//ConsoleType( WayPointTeam, TypeWayPointTeam, WayPointTeam* )
ConsoleType( WayPointTeam, TypeWayPointTeam, WayPointTeam )
ConsoleGetType( TypeWayPointTeam )
{
char * buf = Con::getReturnBuffer(32);
dSprintf(buf, 32, "%d", ((WayPointTeam*)dptr)->mTeamId);
return(buf);
}
ConsoleSetType( TypeWayPointTeam )
{
WayPointTeam * pTeam = (WayPointTeam*)dptr;
pTeam->mTeamId = dAtoi(argv[0]);
if(pTeam->mWayPoint && pTeam->mWayPoint->isServerObject())
pTeam->mWayPoint->setMaskBits(WayPoint::UpdateTeamMask);
}
void WayPoint::initPersistFields()
{
addGroup("Misc");
addField("markerName", TypeCaseString, Offset(mName, WayPoint), "Unique name representing this waypoint");
addField("team", TypeWayPointTeam, Offset(mTeam, WayPoint), "Unique numerical ID assigned to this waypoint, or set of waypoints");
endGroup("Misc");
Parent::initPersistFields();
}
@ -554,7 +515,7 @@ ConsoleMethod(SpawnSphere, spawnObject, S32, 2, 3,
String additionalProps;
if (argc == 3)
additionalProps = String(argv[2]);
additionalProps = (const char*)argv[2];
SimObject* obj = object->spawnObject(additionalProps);

View file

@ -92,17 +92,6 @@ class MissionMarker : public ShapeBase
// Class: WayPoint
//------------------------------------------------------------------------------
class WayPoint;
class WayPointTeam
{
public:
WayPointTeam();
S32 mTeamId;
WayPoint * mWayPoint;
};
DECLARE_STRUCT( WayPointTeam );
DefineConsoleType( TypeWayPointTeam, WayPointTeam * );
class WayPoint : public MissionMarker
{
@ -132,7 +121,6 @@ class WayPoint : public MissionMarker
// field data
StringTableEntry mName;
WayPointTeam mTeam;
static void initPersistFields();

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

@ -147,13 +147,13 @@ ConsoleFunction( physicsDestroy, void, 1, 1, "physicsDestroy()" )
ConsoleFunction( physicsInitWorld, bool, 2, 2, "physicsInitWorld( String worldName )" )
{
return PHYSICSMGR && PHYSICSMGR->createWorld( String( argv[1] ) );
return PHYSICSMGR && PHYSICSMGR->createWorld( (const char*)argv[1] );
}
ConsoleFunction( physicsDestroyWorld, void, 2, 2, "physicsDestroyWorld( String worldName )" )
{
if ( PHYSICSMGR )
PHYSICSMGR->destroyWorld( String( argv[1] ) );
PHYSICSMGR->destroyWorld( (const char*)argv[1] );
}
@ -162,13 +162,13 @@ ConsoleFunction( physicsDestroyWorld, void, 2, 2, "physicsDestroyWorld( String w
ConsoleFunction( physicsStartSimulation, void, 2, 2, "physicsStartSimulation( String worldName )" )
{
if ( PHYSICSMGR )
PHYSICSMGR->enableSimulation( String( argv[1] ), true );
PHYSICSMGR->enableSimulation( (const char*)argv[1], true );
}
ConsoleFunction( physicsStopSimulation, void, 2, 2, "physicsStopSimulation( String worldName )" )
{
if ( PHYSICSMGR )
PHYSICSMGR->enableSimulation( String( argv[1] ), false );
PHYSICSMGR->enableSimulation( (const char*)argv[1], false );
}
ConsoleFunction( physicsSimulationEnabled, bool, 1, 1, "physicsSimulationEnabled()" )
@ -182,7 +182,7 @@ ConsoleFunction( physicsSimulationEnabled, bool, 1, 1, "physicsSimulationEnabled
ConsoleFunction( physicsSetTimeScale, void, 2, 2, "physicsSetTimeScale( F32 scale )" )
{
if ( PHYSICSMGR )
PHYSICSMGR->setTimeScale( dAtof( argv[1] ) );
PHYSICSMGR->setTimeScale( argv[1] );
}
// Get the currently set time scale.
@ -212,5 +212,5 @@ ConsoleFunction( physicsRestoreState, void, 1, 1, "physicsRestoreState()" )
ConsoleFunction( physicsDebugDraw, void, 2, 2, "physicsDebugDraw( bool enable )" )
{
if ( PHYSICSMGR )
PHYSICSMGR->enableDebugDraw( dAtoi( argv[1] ) );
}
PHYSICSMGR->enableDebugDraw( (S32)argv[1] );
}

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

@ -20,35 +20,34 @@
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "unit/test.h"
#include "core/util/tFixedSizeDeque.h"
#ifndef _PHYSX3_H_
#define _PHYSX3_H_
//-------------------------------------------------------------------------
//defines to keep PhysX happy and compiling
#if defined(TORQUE_OS_MAC) && !defined(__APPLE__)
#define __APPLE__
#elif defined(TORQUE_OS_LINUX) && !defined(LINUX)
#define LINUX
#elif defined(TORQUE_OS_WIN) && !defined(WIN32)
#define WIN32
#endif
//-------------------------------------------------------------------------
#include <PxPhysicsAPI.h>
#include <PxExtensionsAPI.h>
#include <PxDefaultErrorCallback.h>
#include <PxDefaultAllocator.h>
#include <PxDefaultSimulationFilterShader.h>
#include <PxDefaultCpuDispatcher.h>
#include <PxShapeExt.h>
#include <PxSimpleFactory.h>
#include <PxFoundation.h>
#include <PxController.h>
#include <PxIO.h>
using namespace UnitTesting;
extern physx::PxPhysics* gPhysics3SDK;
#define TEST( x ) test( ( x ), "FAIL: " #x )
CreateUnitTest( TestFixedSizeDeque, "Util/FixedSizeDeque" )
{
void run()
{
enum { DEQUE_SIZE = 3 };
FixedSizeDeque< U32 > deque( DEQUE_SIZE );
TEST( deque.capacity() == DEQUE_SIZE );
TEST( deque.size() == 0 );
deque.pushFront( 1 );
TEST( deque.capacity() == ( DEQUE_SIZE - 1 ) );
TEST( deque.size() == 1 );
TEST( !deque.isEmpty() );
deque.pushBack( 2 );
TEST( deque.capacity() == ( DEQUE_SIZE - 2 ) );
TEST( deque.size() == 2 );
TEST( deque.popFront() == 1 );
TEST( deque.popFront() == 2 );
TEST( deque.isEmpty() );
}
};
#endif // _PHYSX3_

View file

@ -0,0 +1,419 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "T3D/physics/physx3/px3Body.h"
#include "T3D/physics/physx3/px3.h"
#include "T3D/physics/physx3/px3Casts.h"
#include "T3D/physics/physx3/px3World.h"
#include "T3D/physics/physx3/px3Collision.h"
#include "console/console.h"
#include "console/consoleTypes.h"
Px3Body::Px3Body() :
mActor( NULL ),
mMaterial( NULL ),
mWorld( NULL ),
mBodyFlags( 0 ),
mIsEnabled( true ),
mIsStatic(false)
{
}
Px3Body::~Px3Body()
{
_releaseActor();
}
void Px3Body::_releaseActor()
{
if ( !mActor )
return;
mWorld->releaseWriteLock();
mActor->userData = NULL;
mActor->release();
mActor = NULL;
mBodyFlags = 0;
if ( mMaterial )
{
mMaterial->release();
}
mColShape = NULL;
}
bool Px3Body::init( PhysicsCollision *shape,
F32 mass,
U32 bodyFlags,
SceneObject *obj,
PhysicsWorld *world )
{
AssertFatal( obj, "Px3Body::init - Got a null scene object!" );
AssertFatal( world, "Px3Body::init - Got a null world!" );
AssertFatal( dynamic_cast<Px3World*>( world ), "Px3Body::init - The world is the wrong type!" );
AssertFatal( shape, "Px3Body::init - Got a null collision shape!" );
AssertFatal( dynamic_cast<Px3Collision*>( shape ), "Px3Body::init - The collision shape is the wrong type!" );
AssertFatal( !((Px3Collision*)shape)->getShapes().empty(), "Px3Body::init - Got empty collision shape!" );
// Cleanup any previous actor.
_releaseActor();
mWorld = (Px3World*)world;
mColShape = (Px3Collision*)shape;
mBodyFlags = bodyFlags;
const bool isKinematic = mBodyFlags & BF_KINEMATIC;
const bool isTrigger = mBodyFlags & BF_TRIGGER;
const bool isDebris = mBodyFlags & BF_DEBRIS;
if ( isKinematic )
{
mActor = gPhysics3SDK->createRigidDynamic(physx::PxTransform(physx::PxIDENTITY()));
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
actor->setRigidDynamicFlag(physx::PxRigidDynamicFlag::eKINEMATIC, true);
actor->setMass(getMax( mass, 1.0f ));
}
else if ( mass > 0.0f )
{
mActor = gPhysics3SDK->createRigidDynamic(physx::PxTransform(physx::PxIDENTITY()));
}
else
{
mActor = gPhysics3SDK->createRigidStatic(physx::PxTransform(physx::PxIDENTITY()));
mIsStatic = true;
}
mMaterial = gPhysics3SDK->createMaterial(0.6f,0.4f,0.1f);
// Add all the shapes.
const Vector<Px3CollisionDesc*> &shapes = mColShape->getShapes();
for ( U32 i=0; i < shapes.size(); i++ )
{
Px3CollisionDesc* desc = shapes[i];
if( mass > 0.0f )
{
if(desc->pGeometry->getType() == physx::PxGeometryType::eTRIANGLEMESH)
{
Con::errorf("PhysX3 Dynamic Triangle Mesh is not supported.");
}
}
physx::PxShape * pShape = mActor->createShape(*desc->pGeometry,*mMaterial);
physx::PxFilterData colData;
if(isDebris)
colData.word0 = PX3_DEBRIS;
else if(isTrigger)
colData.word0 = PX3_TRIGGER;
else
colData.word0 = PX3_DEFAULT;
//set local pose - actor->createShape with a local pose is deprecated in physx 3.3
pShape->setLocalPose(desc->pose);
//set the skin width
pShape->setContactOffset(0.01f);
pShape->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE, !isTrigger);
pShape->setFlag(physx::PxShapeFlag::eSCENE_QUERY_SHAPE,true);
pShape->setSimulationFilterData(colData);
pShape->setQueryFilterData(colData);
}
//mass & intertia has to be set after creating the shape
if ( mass > 0.0f )
{
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
physx::PxRigidBodyExt::setMassAndUpdateInertia(*actor,mass);
}
// This sucks, but it has to happen if we want
// to avoid write lock errors from PhysX right now.
mWorld->releaseWriteLock();
mWorld->getScene()->addActor(*mActor);
mIsEnabled = true;
if ( isDebris )
mActor->setDominanceGroup( 31 );
mUserData.setObject( obj );
mUserData.setBody( this );
mActor->userData = &mUserData;
return true;
}
void Px3Body::setMaterial( F32 restitution,
F32 friction,
F32 staticFriction )
{
AssertFatal( mActor, "Px3Body::setMaterial - The actor is null!" );
if ( isDynamic() )
{
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
actor->wakeUp();
}
mMaterial->setRestitution(restitution);
mMaterial->setStaticFriction(staticFriction);
mMaterial->setDynamicFriction(friction);
}
void Px3Body::setSleepThreshold( F32 linear, F32 angular )
{
AssertFatal( mActor, "Px3Body::setSleepThreshold - The actor is null!" );
if(mIsStatic)
return;
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
physx::PxF32 massNormalized= (linear*linear+angular*angular)/2.0f;
actor->setSleepThreshold(massNormalized);
}
void Px3Body::setDamping( F32 linear, F32 angular )
{
AssertFatal( mActor, "Px3Body::setDamping - The actor is null!" );
if(mIsStatic)
return;
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
actor->setLinearDamping( linear );
actor->setAngularDamping( angular );
}
void Px3Body::getState( PhysicsState *outState )
{
AssertFatal( mActor, "Px3Body::getState - The actor is null!" );
AssertFatal( isDynamic(), "Px3Body::getState - This call is only for dynamics!" );
outState->position = px3Cast<Point3F>( mActor->getGlobalPose().p );
outState->orientation = px3Cast<QuatF>( mActor->getGlobalPose().q );
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
outState->linVelocity = px3Cast<Point3F>( actor->getLinearVelocity() );
outState->angVelocity = px3Cast<Point3F>( actor->getAngularVelocity() );
outState->sleeping = actor->isSleeping();
outState->momentum = px3Cast<Point3F>( (1.0f/actor->getMass()) * actor->getLinearVelocity() );
}
F32 Px3Body::getMass() const
{
AssertFatal( mActor, "PxBody::getCMassPosition - The actor is null!" );
if(mIsStatic)
return 0;
const physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
return actor->getMass();
}
Point3F Px3Body::getCMassPosition() const
{
AssertFatal( mActor, "Px3Body::getCMassPosition - The actor is null!" );
if(mIsStatic)
return px3Cast<Point3F>(mActor->getGlobalPose().p);
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
physx::PxTransform pose = actor->getGlobalPose() * actor->getCMassLocalPose();
return px3Cast<Point3F>(pose.p);
}
void Px3Body::setLinVelocity( const Point3F &vel )
{
AssertFatal( mActor, "Px3Body::setLinVelocity - The actor is null!" );
AssertFatal( isDynamic(), "Px3Body::setLinVelocity - This call is only for dynamics!" );
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
actor->setLinearVelocity( px3Cast<physx::PxVec3>( vel ) );
}
void Px3Body::setAngVelocity( const Point3F &vel )
{
AssertFatal( mActor, "Px3Body::setAngVelocity - The actor is null!" );
AssertFatal( isDynamic(), "Px3Body::setAngVelocity - This call is only for dynamics!" );
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
actor->setAngularVelocity(px3Cast<physx::PxVec3>( vel ) );
}
Point3F Px3Body::getLinVelocity() const
{
AssertFatal( mActor, "Px3Body::getLinVelocity - The actor is null!" );
AssertFatal( isDynamic(), "Px3Body::getLinVelocity - This call is only for dynamics!" );
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
return px3Cast<Point3F>( actor->getLinearVelocity() );
}
Point3F Px3Body::getAngVelocity() const
{
AssertFatal( mActor, "Px3Body::getAngVelocity - The actor is null!" );
AssertFatal( isDynamic(), "Px3Body::getAngVelocity - This call is only for dynamics!" );
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
return px3Cast<Point3F>( actor->getAngularVelocity() );
}
void Px3Body::setSleeping( bool sleeping )
{
AssertFatal( mActor, "Px3Body::setSleeping - The actor is null!" );
AssertFatal( isDynamic(), "Px3Body::setSleeping - This call is only for dynamics!" );
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
if ( sleeping )
actor->putToSleep();
else
actor->wakeUp();
}
bool Px3Body::isDynamic() const
{
AssertFatal( mActor, "PxBody::isDynamic - The actor is null!" );
return !mIsStatic && ( mBodyFlags & BF_KINEMATIC ) == 0;
}
PhysicsWorld* Px3Body::getWorld()
{
return mWorld;
}
PhysicsCollision* Px3Body::getColShape()
{
return mColShape;
}
MatrixF& Px3Body::getTransform( MatrixF *outMatrix )
{
AssertFatal( mActor, "Px3Body::getTransform - The actor is null!" );
*outMatrix = px3Cast<MatrixF>(mActor->getGlobalPose());
return *outMatrix;
}
Box3F Px3Body::getWorldBounds()
{
AssertFatal( mActor, "Px3Body::getTransform - The actor is null!" );
physx::PxBounds3 bounds;
bounds.setEmpty();
physx::PxBounds3 shapeBounds;
U32 shapeCount = mActor->getNbShapes();
physx::PxShape **shapes = new physx::PxShape*[shapeCount];
mActor->getShapes(shapes, shapeCount);
for ( U32 i = 0; i < shapeCount; i++ )
{
// Get the shape's bounds.
shapeBounds = physx::PxShapeExt::getWorldBounds(*shapes[i],*mActor);
// Combine them into the total bounds.
bounds.include( shapeBounds );
}
delete [] shapes;
return px3Cast<Box3F>( bounds );
}
void Px3Body::setSimulationEnabled( bool enabled )
{
if ( mIsEnabled == enabled )
return;
//Don't need to enable/disable eSIMULATION_SHAPE for trigger,it's disabled permanently
if(mBodyFlags & BF_TRIGGER)
return;
// This sucks, but it has to happen if we want
// to avoid write lock errors from PhysX right now.
mWorld->releaseWriteLock();
U32 shapeCount = mActor->getNbShapes();
physx::PxShape **shapes = new physx::PxShape*[shapeCount];
mActor->getShapes(shapes, shapeCount);
for ( S32 i = 0; i < mActor->getNbShapes(); i++ )
{
shapes[i]->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE,!mIsEnabled);//?????
}
delete [] shapes;
}
void Px3Body::setTransform( const MatrixF &transform )
{
AssertFatal( mActor, "Px3Body::setTransform - The actor is null!" );
// This sucks, but it has to happen if we want
// to avoid write lock errors from PhysX right now.
mWorld->releaseWriteLock();
mActor->setGlobalPose(px3Cast<physx::PxTransform>(transform),false);
if(mIsStatic)
return;
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
bool kinematic = actor->getRigidDynamicFlags() & physx::PxRigidDynamicFlag::eKINEMATIC;
// If its dynamic we have more to do.
if ( isDynamic() && !kinematic )
{
actor->setLinearVelocity( physx::PxVec3(0) );
actor->setAngularVelocity( physx::PxVec3(0) );
actor->wakeUp();
}
}
void Px3Body::applyCorrection( const MatrixF &transform )
{
AssertFatal( mActor, "Px3Body::applyCorrection - The actor is null!" );
AssertFatal( isDynamic(), "Px3Body::applyCorrection - This call is only for dynamics!" );
// This sucks, but it has to happen if we want
// to avoid write lock errors from PhysX right now.
mWorld->releaseWriteLock();
mActor->setGlobalPose( px3Cast<physx::PxTransform>(transform) );
}
void Px3Body::applyImpulse( const Point3F &origin, const Point3F &force )
{
AssertFatal( mActor, "Px3Body::applyImpulse - The actor is null!" );
// This sucks, but it has to happen if we want
// to avoid write lock errors from PhysX right now.
mWorld->releaseWriteLock();
physx::PxRigidDynamic *actor = mActor->is<physx::PxRigidDynamic>();
if ( mIsEnabled && isDynamic() )
physx::PxRigidBodyExt::addForceAtPos(*actor,px3Cast<physx::PxVec3>(force),
px3Cast<physx::PxVec3>(origin),
physx::PxForceMode::eIMPULSE);
}

View file

@ -0,0 +1,122 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _PX3BODY_H_
#define _PX3BODY_H_
#ifndef _T3D_PHYSICS_PHYSICSBODY_H_
#include "T3D/physics/physicsBody.h"
#endif
#ifndef _PHYSICS_PHYSICSUSERDATA_H_
#include "T3D/physics/physicsUserData.h"
#endif
#ifndef _REFBASE_H_
#include "core/util/refBase.h"
#endif
#ifndef _MMATRIX_H_
#include "math/mMatrix.h"
#endif
class Px3World;
class Px3Collision;
struct Px3CollisionDesc;
namespace physx{
class PxRigidActor;
class PxMaterial;
class PxShape;
}
class Px3Body : public PhysicsBody
{
protected:
/// The physics world we are in.
Px3World *mWorld;
/// The physics actor.
physx::PxRigidActor *mActor;
/// The unshared local material used on all the
/// shapes on this actor.
physx::PxMaterial *mMaterial;
/// We hold the collision reference as it contains
/// allocated objects that we own and must free.
StrongRefPtr<Px3Collision> mColShape;
///
MatrixF mInternalTransform;
/// The body flags set at creation time.
U32 mBodyFlags;
/// Is true if this body is enabled and active
/// in the simulation of the scene.
bool mIsEnabled;
bool mIsStatic;
///
void _releaseActor();
public:
Px3Body();
virtual ~Px3Body();
// PhysicsObject
virtual PhysicsWorld* getWorld();
virtual void setTransform( const MatrixF &xfm );
virtual MatrixF& getTransform( MatrixF *outMatrix );
virtual Box3F getWorldBounds();
virtual void setSimulationEnabled( bool enabled );
virtual bool isSimulationEnabled() { return mIsEnabled; }
// PhysicsBody
virtual bool init( PhysicsCollision *shape,
F32 mass,
U32 bodyFlags,
SceneObject *obj,
PhysicsWorld *world );
virtual bool isDynamic() const;
virtual PhysicsCollision* getColShape();
virtual void setSleepThreshold( F32 linear, F32 angular );
virtual void setDamping( F32 linear, F32 angular );
virtual void getState( PhysicsState *outState );
virtual F32 getMass() const;
virtual Point3F getCMassPosition() const;
virtual void setLinVelocity( const Point3F &vel );
virtual void setAngVelocity( const Point3F &vel );
virtual Point3F getLinVelocity() const;
virtual Point3F getAngVelocity() const;
virtual void setSleeping( bool sleeping );
virtual void setMaterial( F32 restitution,
F32 friction,
F32 staticFriction );
virtual void applyCorrection( const MatrixF &xfm );
virtual void applyImpulse( const Point3F &origin, const Point3F &force );
};
#endif // _PX3BODY_H_

View file

@ -0,0 +1,137 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _PX3CASTS_H_
#define _PX3CASTS_H_
#ifndef _MPOINT3_H_
#include "math/mPoint3.h"
#endif
#ifndef _MMATRIX_H_
#include "math/mMatrix.h"
#endif
#ifndef _MBOX_H_
#include "math/mBox.h"
#endif
#ifndef _MQUAT_H_
#include "math/mQuat.h"
#endif
#ifndef _MTRANSFORM_H_
#include "math/mTransform.h"
#endif
template <class T, class F> inline T px3Cast( const F &from );
//-------------------------------------------------------------------------
template<>
inline Point3F px3Cast( const physx::PxVec3 &vec )
{
return Point3F( vec.x, vec.y, vec.z );
}
template<>
inline physx::PxVec3 px3Cast( const Point3F &point )
{
return physx::PxVec3( point.x, point.y, point.z );
}
//-------------------------------------------------------------------------
template<>
inline QuatF px3Cast( const physx::PxQuat &quat )
{
/// The Torque quat has the opposite winding order.
return QuatF( -quat.x, -quat.y, -quat.z, quat.w );
}
template<>
inline physx::PxQuat px3Cast( const QuatF &quat )
{
/// The Torque quat has the opposite winding order.
physx::PxQuat result( -quat.x, -quat.y, -quat.z, quat.w );
return result;
}
//-------------------------------------------------------------------------
template<>
inline physx::PxExtendedVec3 px3Cast( const Point3F &point )
{
return physx::PxExtendedVec3( point.x, point.y, point.z );
}
template<>
inline Point3F px3Cast( const physx::PxExtendedVec3 &xvec )
{
return Point3F( xvec.x, xvec.y, xvec.z );
}
//-------------------------------------------------------------------------
template<>
inline physx::PxBounds3 px3Cast( const Box3F &box )
{
physx::PxBounds3 bounds(px3Cast<physx::PxVec3>(box.minExtents),
px3Cast<physx::PxVec3>(box.maxExtents));
return bounds;
}
template<>
inline Box3F px3Cast( const physx::PxBounds3 &bounds )
{
return Box3F( bounds.minimum.x,
bounds.minimum.y,
bounds.minimum.z,
bounds.maximum.x,
bounds.maximum.y,
bounds.maximum.z );
}
//-------------------------------------------------------------------------
template<>
inline physx::PxTransform px3Cast( const MatrixF &xfm )
{
physx::PxTransform out;
QuatF q;
q.set(xfm);
out.q = px3Cast<physx::PxQuat>(q);
out.p = px3Cast<physx::PxVec3>(xfm.getPosition());
return out;
}
template<>
inline TransformF px3Cast(const physx::PxTransform &xfm)
{
TransformF out(px3Cast<Point3F>(xfm.p),AngAxisF(px3Cast<QuatF>(xfm.q)));
return out;
}
template<>
inline MatrixF px3Cast( const physx::PxTransform &xfm )
{
MatrixF out;
TransformF t = px3Cast<TransformF>(xfm);
out = t.getMatrix();
return out;
}
#endif //_PX3CASTS_H_

View file

@ -0,0 +1,217 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "T3D/physics/physx3/px3Collision.h"
#include "math/mPoint3.h"
#include "math/mMatrix.h"
#include "T3D/physics/physx3/px3.h"
#include "T3D/physics/physx3/px3Casts.h"
#include "T3D/physics/physx3/px3World.h"
#include "T3D/physics/physx3/px3Stream.h"
Px3Collision::Px3Collision()
{
}
Px3Collision::~Px3Collision()
{
for ( U32 i=0; i < mColShapes.size(); i++ )
{
Px3CollisionDesc *desc = mColShapes[i];
delete desc->pGeometry;
// Delete the descriptor.
delete desc;
}
mColShapes.clear();
}
void Px3Collision::addPlane( const PlaneF &plane )
{
physx::PxVec3 pos = px3Cast<physx::PxVec3>(plane.getPosition());
Px3CollisionDesc *desc = new Px3CollisionDesc;
desc->pGeometry = new physx::PxPlaneGeometry();
desc->pose = physx::PxTransform(pos, physx::PxQuat(physx::PxHalfPi, physx::PxVec3(0.0f, -1.0f, 0.0f)));
mColShapes.push_back(desc);
}
void Px3Collision::addBox( const Point3F &halfWidth,const MatrixF &localXfm )
{
Px3CollisionDesc *desc = new Px3CollisionDesc;
desc->pGeometry = new physx::PxBoxGeometry(px3Cast<physx::PxVec3>(halfWidth));
desc->pose = px3Cast<physx::PxTransform>(localXfm);
mColShapes.push_back(desc);
}
void Px3Collision::addSphere( F32 radius,
const MatrixF &localXfm )
{
Px3CollisionDesc *desc = new Px3CollisionDesc;
desc->pGeometry = new physx::PxSphereGeometry(radius);
desc->pose = px3Cast<physx::PxTransform>(localXfm);
mColShapes.push_back(desc);
}
void Px3Collision::addCapsule( F32 radius,
F32 height,
const MatrixF &localXfm )
{
Px3CollisionDesc *desc = new Px3CollisionDesc;
desc->pGeometry = new physx::PxCapsuleGeometry(radius,height*0.5);//uses half height
desc->pose = px3Cast<physx::PxTransform>(localXfm);
mColShapes.push_back(desc);
}
bool Px3Collision::addConvex( const Point3F *points,
U32 count,
const MatrixF &localXfm )
{
physx::PxCooking *cooking = Px3World::getCooking();
physx::PxConvexMeshDesc convexDesc;
convexDesc.points.data = points;
convexDesc.points.stride = sizeof(Point3F);
convexDesc.points.count = count;
convexDesc.flags = physx::PxConvexFlag::eFLIPNORMALS|physx::PxConvexFlag::eCOMPUTE_CONVEX | physx::PxConvexFlag::eINFLATE_CONVEX;
Px3MemOutStream stream;
if(!cooking->cookConvexMesh(convexDesc,stream))
return false;
physx::PxConvexMesh* convexMesh;
Px3MemInStream in(stream.getData(), stream.getSize());
convexMesh = gPhysics3SDK->createConvexMesh(in);
Px3CollisionDesc *desc = new Px3CollisionDesc;
physx::PxVec3 scale = px3Cast<physx::PxVec3>(localXfm.getScale());
physx::PxQuat rotation = px3Cast<physx::PxQuat>(QuatF(localXfm));
physx::PxMeshScale meshScale(scale,rotation);
desc->pGeometry = new physx::PxConvexMeshGeometry(convexMesh,meshScale);
desc->pose = px3Cast<physx::PxTransform>(localXfm);
mColShapes.push_back(desc);
return true;
}
bool Px3Collision::addTriangleMesh( const Point3F *vert,
U32 vertCount,
const U32 *index,
U32 triCount,
const MatrixF &localXfm )
{
physx::PxCooking *cooking = Px3World::getCooking();
physx::PxTriangleMeshDesc meshDesc;
meshDesc.points.count = vertCount;
meshDesc.points.data = vert;
meshDesc.points.stride = sizeof(Point3F);
meshDesc.triangles.count = triCount;
meshDesc.triangles.data = index;
meshDesc.triangles.stride = 3*sizeof(U32);
meshDesc.flags = physx::PxMeshFlag::eFLIPNORMALS;
Px3MemOutStream stream;
if(!cooking->cookTriangleMesh(meshDesc,stream))
return false;
physx::PxTriangleMesh *mesh;
Px3MemInStream in(stream.getData(), stream.getSize());
mesh = gPhysics3SDK->createTriangleMesh(in);
Px3CollisionDesc *desc = new Px3CollisionDesc;
desc->pGeometry = new physx::PxTriangleMeshGeometry(mesh);
desc->pose = px3Cast<physx::PxTransform>(localXfm);
mColShapes.push_back(desc);
return true;
}
bool Px3Collision::addHeightfield( const U16 *heights,
const bool *holes,
U32 blockSize,
F32 metersPerSample,
const MatrixF &localXfm )
{
const F32 heightScale = 0.03125f;
physx::PxHeightFieldSample* samples = (physx::PxHeightFieldSample*) new physx::PxHeightFieldSample[blockSize*blockSize];
memset(samples,0,blockSize*blockSize*sizeof(physx::PxHeightFieldSample));
physx::PxHeightFieldDesc heightFieldDesc;
heightFieldDesc.nbColumns = blockSize;
heightFieldDesc.nbRows = blockSize;
heightFieldDesc.thickness = -10.f;
heightFieldDesc.convexEdgeThreshold = 0;
heightFieldDesc.format = physx::PxHeightFieldFormat::eS16_TM;
heightFieldDesc.samples.data = samples;
heightFieldDesc.samples.stride = sizeof(physx::PxHeightFieldSample);
physx::PxU8 *currentByte = (physx::PxU8*)heightFieldDesc.samples.data;
for ( U32 row = 0; row < blockSize; row++ )
{
const U32 tess = ( row + 1 ) % 2;
for ( U32 column = 0; column < blockSize; column++ )
{
physx::PxHeightFieldSample *currentSample = (physx::PxHeightFieldSample*)currentByte;
U32 index = ( blockSize - row - 1 ) + ( column * blockSize );
currentSample->height = (physx::PxI16)heights[ index ];
if ( holes && holes[ getMax( (S32)index - 1, 0 ) ] ) // row index for holes adjusted so PhysX collision shape better matches rendered terrain
{
currentSample->materialIndex0 = physx::PxHeightFieldMaterial::eHOLE;
currentSample->materialIndex1 = physx::PxHeightFieldMaterial::eHOLE;
}
else
{
currentSample->materialIndex0 = 0;
currentSample->materialIndex1 = 0;
}
int flag = ( column + tess ) % 2;
if(flag)
currentSample->clearTessFlag();
else
currentSample->setTessFlag();
currentByte += heightFieldDesc.samples.stride;
}
}
physx::PxHeightField * hf = gPhysics3SDK->createHeightField(heightFieldDesc);
physx::PxHeightFieldGeometry *geom = new physx::PxHeightFieldGeometry(hf,physx::PxMeshGeometryFlags(),heightScale,metersPerSample,metersPerSample);
physx::PxTransform pose= physx::PxTransform(physx::PxQuat(Float_HalfPi, physx::PxVec3(1, 0, 0 )));
physx::PxTransform pose1= physx::PxTransform(physx::PxQuat(Float_Pi, physx::PxVec3(0, 0, 1 )));
physx::PxTransform pose2 = pose1 * pose;
pose2.p = physx::PxVec3(( blockSize - 1 ) * metersPerSample, 0, 0 );
Px3CollisionDesc *desc = new Px3CollisionDesc;
desc->pGeometry = geom;
desc->pose = pose2;
mColShapes.push_back(desc);
SAFE_DELETE(samples);
return true;
}

View file

@ -0,0 +1,87 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _PX3COLLISION_H_
#define _PX3COLLISION_H_
#ifndef _T3D_PHYSICS_PHYSICSCOLLISION_H_
#include "T3D/physics/physicsCollision.h"
#endif
#ifndef _TVECTOR_H_
#include "core/util/tVector.h"
#endif
#ifndef _MMATRIX_H_
#include "math/mMatrix.h"
#endif
#include <foundation/PxTransform.h>
//forward declare
namespace physx{class PxGeometry;}
struct Px3CollisionDesc
{
physx::PxGeometry *pGeometry;
physx::PxTransform pose;
};
class Px3Collision : public PhysicsCollision
{
typedef Vector<Px3CollisionDesc*> Px3CollisionList;
protected:
/// The collision representation.
Px3CollisionList mColShapes;
public:
Px3Collision();
virtual ~Px3Collision();
/// Return the PhysX shape descriptions.
const Px3CollisionList& getShapes() const { return mColShapes; }
// PhysicsCollision
virtual void addPlane( const PlaneF &plane );
virtual void addBox( const Point3F &halfWidth,
const MatrixF &localXfm );
virtual void addSphere( F32 radius,
const MatrixF &localXfm );
virtual void addCapsule( F32 radius,
F32 height,
const MatrixF &localXfm );
virtual bool addConvex( const Point3F *points,
U32 count,
const MatrixF &localXfm );
virtual bool addTriangleMesh( const Point3F *vert,
U32 vertCount,
const U32 *index,
U32 triCount,
const MatrixF &localXfm );
virtual bool addHeightfield( const U16 *heights,
const bool *holes,
U32 blockSize,
F32 metersPerSample,
const MatrixF &localXfm );
};
#endif // _PX3COLLISION_H_

View file

@ -0,0 +1,331 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "T3D/physics/physx3/px3Player.h"
#include "T3D/physics/physicsPlugin.h"
#include "T3D/physics/physx3/px3World.h"
#include "T3D/physics/physx3/px3Casts.h"
#include "T3D/physics/physx3/px3Utils.h"
#include "collision/collision.h"
Px3Player::Px3Player()
: PhysicsPlayer(),
mController( NULL ),
mWorld( NULL ),
mObject( NULL ),
mSkinWidth( 0.05f ),
mOriginOffset( 0.0f ),
mElapsed(0)
{
PHYSICSMGR->getPhysicsResetSignal().notify( this, &Px3Player::_onPhysicsReset );
}
Px3Player::~Px3Player()
{
_releaseController();
PHYSICSMGR->getPhysicsResetSignal().remove( this, &Px3Player::_onPhysicsReset );
}
void Px3Player::_releaseController()
{
if ( mController )
{
mController->getActor()->userData = NULL;
mWorld->getStaticChangedSignal().remove( this, &Px3Player::_onStaticChanged );
mController->release();
}
}
void Px3Player::init( const char *type,
const Point3F &size,
F32 runSurfaceCos,
F32 stepHeight,
SceneObject *obj,
PhysicsWorld *world )
{
AssertFatal( obj, "Px3Player::init - Got a null scene object!" );
AssertFatal( world, "Px3Player::init - Got a null world!" );
AssertFatal( dynamic_cast<Px3World*>( world ), "Px3Player::init - The world is the wrong type!" );
// Cleanup any previous controller.
_releaseController();
mObject = obj;
mWorld = (Px3World*)world;
mOriginOffset = size.z * 0.5f;
physx::PxCapsuleControllerDesc desc;
desc.contactOffset = mSkinWidth;
desc.radius = getMax( size.x, size.y ) * 0.5f;
desc.radius -= mSkinWidth;
desc.height = size.z - ( desc.radius * 2.0f );
desc.height -= mSkinWidth * 2.0f;
desc.climbingMode = physx::PxCapsuleClimbingMode::eCONSTRAINED;
desc.position.set( 0, 0, 0 );
desc.upDirection = physx::PxVec3(0,0,1);
desc.reportCallback = this;
desc.slopeLimit = runSurfaceCos;
desc.stepOffset = stepHeight;
desc.behaviorCallback = NULL;
desc.material = gPhysics3SDK->createMaterial(0.1f, 0.1f, 0.2f);
mController = mWorld->createController( desc );
mWorld->getStaticChangedSignal().notify( this, &Px3Player::_onStaticChanged );
physx::PxRigidDynamic *kineActor = mController->getActor();
//player only has one shape
physx::PxShape *shape = px3GetFirstShape(kineActor);
physx::PxFilterData colData;
colData.word0 = PX3_PLAYER;
shape->setSimulationFilterData(colData);
shape->setQueryFilterData(colData);
//store geometry for later use in findContact calls
shape->getCapsuleGeometry(mGeometry);
mUserData.setObject( obj );
kineActor->userData = &mUserData;
}
void Px3Player::_onStaticChanged()
{
if(mController)
mController->invalidateCache();
}
void Px3Player::_onPhysicsReset( PhysicsResetEvent reset )
{
if(mController)
mController->invalidateCache();
}
Point3F Px3Player::move( const VectorF &disp, CollisionList &outCol )
{
AssertFatal( mController, "Px3Player::move - The controller is null!" );
// Return the last position if the simulation is stopped.
//
// See PxPlayer::_onPhysicsReset
if ( !mWorld->isEnabled() )
{
Point3F newPos = px3Cast<Point3F>( mController->getPosition() );
newPos.z -= mOriginOffset;
return newPos;
}
mWorld->releaseWriteLock();
mCollisionList = &outCol;
physx::PxVec3 dispNx( disp.x, disp.y, disp.z );
if (mIsZero(disp.z))
dispNx.z = 0.0f;
U32 groups = 0xffffffff;
groups &= ~( PX3_TRIGGER ); // No trigger shapes!
groups &= ~( PX3_DEBRIS);
physx::PxControllerFilters filter;
physx::PxFilterData data;
data.word0=groups;
filter.mFilterData = &data;
filter.mFilterFlags = physx::PxSceneQueryFilterFlags(physx::PxControllerFlag::eCOLLISION_DOWN|physx::PxControllerFlag::eCOLLISION_SIDES|physx::PxControllerFlag::eCOLLISION_UP);
mController->move( dispNx,0.0001f,0, filter );
Point3F newPos = px3Cast<Point3F>( mController->getPosition() );
newPos.z -= mOriginOffset;
mCollisionList = NULL;
return newPos;
}
void Px3Player::onShapeHit( const physx::PxControllerShapeHit& hit )
{
if (!mCollisionList || mCollisionList->getCount() >= CollisionList::MaxCollisions)
return;
physx::PxRigidActor *actor = hit.actor;
PhysicsUserData *userData = PhysicsUserData::cast( actor->userData );
// Fill out the Collision
// structure for use later.
Collision &col = mCollisionList->increment();
dMemset( &col, 0, sizeof( col ) );
col.normal = px3Cast<Point3F>( hit.worldNormal );
col.point = px3Cast<Point3F>( hit.worldPos );
col.distance = hit.length;
if ( userData )
col.object = userData->getObject();
if (mIsZero(hit.dir.z))
{
if (col.normal.z > 0.0f)
{
col.normal.z = 0.0f;
col.normal.normalizeSafe();
}
}
else
{
col.normal.set(0.0f, 0.0f, 1.0f);
}
}
void Px3Player::onControllerHit( const physx::PxControllersHit& hit )
{
if (!mCollisionList || mCollisionList->getCount() >= CollisionList::MaxCollisions)
return;
physx::PxRigidActor *actor = hit.other->getActor();
PhysicsUserData *userData = PhysicsUserData::cast( actor->userData );
// For controller-to-controller hit we don't have an actual hit point, so all
// we can do is set the hit object.
Collision &col = mCollisionList->increment();
dMemset( &col, 0, sizeof( col ) );
if ( userData )
col.object = userData->getObject();
}
void Px3Player::findContact( SceneObject **contactObject,
VectorF *contactNormal,
Vector<SceneObject*> *outOverlapObjects ) const
{
// Calculate the sweep motion...
F32 halfCapSize = mOriginOffset;
F32 halfSmallCapSize = halfCapSize * 0.8f;
F32 diff = halfCapSize - halfSmallCapSize;
F32 distance = diff + mSkinWidth + 0.01f;
physx::PxVec3 dir(0,0,-1);
physx::PxScene *scene = mWorld->getScene();
physx::PxHitFlags hitFlags(physx::PxHitFlag::eDEFAULT);
physx::PxQueryFilterData filterData(physx::PxQueryFlag::eDYNAMIC|physx::PxQueryFlag::eSTATIC);
filterData.data.word0 = PX3_DEFAULT;
physx::PxSweepHit sweepHit;
physx::PxRigidDynamic *actor= mController->getActor();
physx::PxU32 shapeIndex;
bool hit = physx::PxRigidBodyExt::linearSweepSingle(*actor,*scene,dir,distance,hitFlags,sweepHit,shapeIndex,filterData);
if ( hit )
{
PhysicsUserData *data = PhysicsUserData::cast( sweepHit.actor->userData);
if ( data )
{
*contactObject = data->getObject();
*contactNormal = px3Cast<Point3F>( sweepHit.normal );
}
}
// Check for overlapped objects ( triggers )
if ( !outOverlapObjects )
return;
filterData.data.word0 = PX3_TRIGGER;
const physx::PxU32 bufferSize = 10;
physx::PxOverlapBufferN<bufferSize> hitBuffer;
hit = scene->overlap(mGeometry,actor->getGlobalPose(),hitBuffer,filterData);
if(hit)
{
for ( U32 i = 0; i < hitBuffer.nbTouches; i++ )
{
PhysicsUserData *data = PhysicsUserData::cast( hitBuffer.touches[i].actor->userData );
if ( data )
outOverlapObjects->push_back( data->getObject() );
}
}
}
void Px3Player::enableCollision()
{
AssertFatal( mController, "Px3Player::enableCollision - The controller is null!" );
mWorld->releaseWriteLock();
px3GetFirstShape(mController->getActor())->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE,true);
}
void Px3Player::disableCollision()
{
AssertFatal( mController, "Px3Player::disableCollision - The controller is null!" );
mWorld->releaseWriteLock();
px3GetFirstShape(mController->getActor())->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE,false);
}
PhysicsWorld* Px3Player::getWorld()
{
return mWorld;
}
void Px3Player::setTransform( const MatrixF &transform )
{
AssertFatal( mController, "Px3Player::setTransform - The controller is null!" );
mWorld->releaseWriteLock();
Point3F newPos = transform.getPosition();
newPos.z += mOriginOffset;
const Point3F &curPos = px3Cast<Point3F>(mController->getPosition());
if ( !(newPos - curPos ).isZero() )
mController->setPosition( px3Cast<physx::PxExtendedVec3>(newPos) );
}
MatrixF& Px3Player::getTransform( MatrixF *outMatrix )
{
AssertFatal( mController, "Px3Player::getTransform - The controller is null!" );
Point3F newPos = px3Cast<Point3F>( mController->getPosition() );
newPos.z -= mOriginOffset;
outMatrix->setPosition( newPos );
return *outMatrix;
}
void Px3Player::setScale( const Point3F &scale )
{
//Ignored
}
Box3F Px3Player::getWorldBounds()
{
physx::PxBounds3 bounds;
physx::PxRigidDynamic *actor = mController->getActor();
physx::PxShape *shape = px3GetFirstShape(actor);
bounds = physx::PxShapeExt::getWorldBounds(*shape,*actor);
return px3Cast<Box3F>( bounds );
}

View file

@ -0,0 +1,104 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _PX3PLAYER_H
#define _PX3PLAYER_H
#ifndef _PHYSX3_H_
#include "T3D/physics/physx3/px3.h"
#endif
#ifndef _T3D_PHYSICS_PHYSICSPLAYER_H_
#include "T3D/physics/physicsPlayer.h"
#endif
#ifndef _T3D_PHYSICSCOMMON_H_
#include "T3D/physics/physicsCommon.h"
#endif
class Px3World;
class Px3Player : public PhysicsPlayer, public physx::PxUserControllerHitReport
{
protected:
physx::PxController *mController;
physx::PxCapsuleGeometry mGeometry;
F32 mSkinWidth;
Px3World *mWorld;
SceneObject *mObject;
/// Used to get collision info out of the
/// PxUserControllerHitReport callbacks.
CollisionList *mCollisionList;
///
F32 mOriginOffset;
///
F32 mStepHeight;
U32 mElapsed;
///
void _releaseController();
virtual void onShapeHit( const physx::PxControllerShapeHit &hit );
virtual void onControllerHit( const physx::PxControllersHit &hit );
virtual void onObstacleHit(const physx::PxControllerObstacleHit &){}
void _findContact( SceneObject **contactObject, VectorF *contactNormal ) const;
void _onPhysicsReset( PhysicsResetEvent reset );
void _onStaticChanged();
public:
Px3Player();
virtual ~Px3Player();
// PhysicsObject
virtual PhysicsWorld* getWorld();
virtual void setTransform( const MatrixF &transform );
virtual MatrixF& getTransform( MatrixF *outMatrix );
virtual void setScale( const Point3F &scale );
virtual Box3F getWorldBounds();
virtual void setSimulationEnabled( bool enabled ) {}
virtual bool isSimulationEnabled() { return true; }
// PhysicsPlayer
virtual void init( const char *type,
const Point3F &size,
F32 runSurfaceCos,
F32 stepHeight,
SceneObject *obj,
PhysicsWorld *world );
virtual Point3F move( const VectorF &displacement, CollisionList &outCol );
virtual void findContact( SceneObject **contactObject, VectorF *contactNormal, Vector<SceneObject*> *outOverlapObjects ) const;
virtual bool testSpacials( const Point3F &nPos, const Point3F &nSize ) const { return true; }
virtual void setSpacials( const Point3F &nPos, const Point3F &nSize ) {}
virtual void enableCollision();
virtual void disableCollision();
};
#endif // _PX3PLAYER_H_

View file

@ -0,0 +1,226 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "console/consoleTypes.h"
#include "T3D/physics/physx3/px3World.h"
#include "T3D/physics/physx3/px3Plugin.h"
#include "T3D/physics/physx3/px3Collision.h"
#include "T3D/physics/physx3/px3Body.h"
#include "T3D/physics/physx3/px3Player.h"
#include "T3D/physics/physicsShape.h"
#include "T3D/gameBase/gameProcess.h"
#include "core/util/tNamedFactory.h"
AFTER_MODULE_INIT( Sim )
{
NamedFactory<PhysicsPlugin>::add( "PhysX3", &Px3Plugin::create );
#if defined(TORQUE_OS_WIN) || defined(TORQUE_OS_XBOX) || defined(TORQUE_OS_XENON)
NamedFactory<PhysicsPlugin>::add( "default", &Px3Plugin::create );
#endif
}
PhysicsPlugin* Px3Plugin::create()
{
// Only create the plugin if it hasn't been set up AND
// the PhysX world is successfully initialized.
bool success = Px3World::restartSDK( false );
if ( success )
return new Px3Plugin();
return NULL;
}
Px3Plugin::Px3Plugin()
{
}
Px3Plugin::~Px3Plugin()
{
}
void Px3Plugin::destroyPlugin()
{
// Cleanup any worlds that are still kicking.
Map<StringNoCase, PhysicsWorld*>::Iterator iter = mPhysicsWorldLookup.begin();
for ( ; iter != mPhysicsWorldLookup.end(); iter++ )
{
iter->value->destroyWorld();
delete iter->value;
}
mPhysicsWorldLookup.clear();
Px3World::restartSDK( true );
delete this;
}
void Px3Plugin::reset()
{
// First delete all the cleanup objects.
if ( getPhysicsCleanup() )
getPhysicsCleanup()->deleteAllObjects();
getPhysicsResetSignal().trigger( PhysicsResetEvent_Restore );
// Now let each world reset itself.
Map<StringNoCase, PhysicsWorld*>::Iterator iter = mPhysicsWorldLookup.begin();
for ( ; iter != mPhysicsWorldLookup.end(); iter++ )
iter->value->reset();
}
PhysicsCollision* Px3Plugin::createCollision()
{
return new Px3Collision();
}
PhysicsBody* Px3Plugin::createBody()
{
return new Px3Body();
}
PhysicsPlayer* Px3Plugin::createPlayer()
{
return new Px3Player();
}
bool Px3Plugin::isSimulationEnabled() const
{
bool ret = false;
Px3World *world = static_cast<Px3World*>( getWorld( smClientWorldName ) );
if ( world )
{
ret = world->isEnabled();
return ret;
}
world = static_cast<Px3World*>( getWorld( smServerWorldName ) );
if ( world )
{
ret = world->isEnabled();
return ret;
}
return ret;
}
void Px3Plugin::enableSimulation( const String &worldName, bool enable )
{
Px3World *world = static_cast<Px3World*>( getWorld( worldName ) );
if ( world )
world->setEnabled( enable );
}
void Px3Plugin::setTimeScale( const F32 timeScale )
{
// Grab both the client and
// server worlds and set their time
// scales to the passed value.
Px3World *world = static_cast<Px3World*>( getWorld( smClientWorldName ) );
if ( world )
world->setEditorTimeScale( timeScale );
world = static_cast<Px3World*>( getWorld( smServerWorldName ) );
if ( world )
world->setEditorTimeScale( timeScale );
}
const F32 Px3Plugin::getTimeScale() const
{
// Grab both the client and
// server worlds and call
// setEnabled( true ) on them.
Px3World *world = static_cast<Px3World*>( getWorld( smClientWorldName ) );
if ( !world )
{
world = static_cast<Px3World*>( getWorld( smServerWorldName ) );
if ( !world )
return 0.0f;
}
return world->getEditorTimeScale();
}
bool Px3Plugin::createWorld( const String &worldName )
{
Map<StringNoCase, PhysicsWorld*>::Iterator iter = mPhysicsWorldLookup.find( worldName );
PhysicsWorld *world = NULL;
iter != mPhysicsWorldLookup.end() ? world = (*iter).value : world = NULL;
if ( world )
{
Con::errorf( "Px3Plugin::createWorld - %s world already exists!", worldName.c_str() );
return false;
}
world = new Px3World();
if ( worldName.equal( smClientWorldName, String::NoCase ) )
world->initWorld( false, ClientProcessList::get() );
else
world->initWorld( true, ServerProcessList::get() );
mPhysicsWorldLookup.insert( worldName, world );
return world != NULL;
}
void Px3Plugin::destroyWorld( const String &worldName )
{
Map<StringNoCase, PhysicsWorld*>::Iterator iter = mPhysicsWorldLookup.find( worldName );
if ( iter == mPhysicsWorldLookup.end() )
return;
PhysicsWorld *world = (*iter).value;
world->destroyWorld();
delete world;
mPhysicsWorldLookup.erase( iter );
}
PhysicsWorld* Px3Plugin::getWorld( const String &worldName ) const
{
if ( mPhysicsWorldLookup.isEmpty() )
return NULL;
Map<StringNoCase, PhysicsWorld*>::ConstIterator iter = mPhysicsWorldLookup.find( worldName );
return iter != mPhysicsWorldLookup.end() ? (*iter).value : NULL;
}
PhysicsWorld* Px3Plugin::getWorld() const
{
if ( mPhysicsWorldLookup.size() == 0 )
return NULL;
Map<StringNoCase, PhysicsWorld*>::ConstIterator iter = mPhysicsWorldLookup.begin();
return iter->value;
}
U32 Px3Plugin::getWorldCount() const
{
return mPhysicsWorldLookup.size();
}

View file

@ -0,0 +1,59 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _PX3PLUGIN_H_
#define _PX3PLUGIN_H_
#ifndef _T3D_PHYSICS_PHYSICSPLUGIN_H_
#include "T3D/physics/physicsPlugin.h"
#endif
class Px3ClothShape;
class Px3Plugin : public PhysicsPlugin
{
public:
Px3Plugin();
~Px3Plugin();
/// Create function for factory.
static PhysicsPlugin* create();
// PhysicsPlugin
virtual void destroyPlugin();
virtual void reset();
virtual PhysicsCollision* createCollision();
virtual PhysicsBody* createBody();
virtual PhysicsPlayer* createPlayer();
virtual bool isSimulationEnabled() const;
virtual void enableSimulation( const String &worldName, bool enable );
virtual void setTimeScale( const F32 timeScale );
virtual const F32 getTimeScale() const;
virtual bool createWorld( const String &worldName );
virtual void destroyWorld( const String &worldName );
virtual PhysicsWorld* getWorld( const String &worldName ) const;
virtual PhysicsWorld* getWorld() const;
virtual U32 getWorldCount() const;
};
#endif // _PX3PLUGIN_H_

View file

@ -0,0 +1,92 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "T3D/physics/physx3/px3Stream.h"
#include "console/console.h"
#include "console/consoleTypes.h"
#include "core/strings/stringFunctions.h"
Px3MemOutStream::Px3MemOutStream() : mMemStream(1024)
{
}
Px3MemOutStream::~Px3MemOutStream()
{
}
physx::PxU32 Px3MemOutStream::write(const void *src, physx::PxU32 count)
{
physx::PxU32 out=0;
if(!mMemStream.write(count,src))
return out;
out = count;
return out;
}
Px3MemInStream::Px3MemInStream(physx::PxU8* data, physx::PxU32 length):mMemStream(length,data)
{
}
physx::PxU32 Px3MemInStream::read(void* dest, physx::PxU32 count)
{
physx::PxU32 read =0;
if(!mMemStream.read(count,dest))
return read;
read = count;
return read;
}
void Px3MemInStream::seek(physx::PxU32 pos)
{
mMemStream.setPosition(pos);
}
physx::PxU32 Px3MemInStream::getLength() const
{
return mMemStream.getStreamSize();
}
physx::PxU32 Px3MemInStream::tell() const
{
return mMemStream.getPosition();
}
Px3ConsoleStream::Px3ConsoleStream()
{
}
Px3ConsoleStream::~Px3ConsoleStream()
{
}
void Px3ConsoleStream::reportError( physx::PxErrorCode code, const char *message, const char* file, int line )
{
UTF8 info[1024];
dSprintf( info, 1024, "File: %s\nLine: %d\n%s", file, line, message );
Platform::AlertOK( "PhysX Error", info );
// Con::printf( "PhysX Error:\n %s(%d) : %s\n", file, line, message );
}

View file

@ -0,0 +1,77 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _PX3STREAM_H_
#define _PX3STREAM_H_
#ifndef _PHYSX3_H_
#include "T3D/physics/physx3/px3.h"
#endif
#ifndef _MEMSTREAM_H_
#include "core/stream/memStream.h"
#endif
class Px3MemOutStream : public physx::PxOutputStream
{
public:
Px3MemOutStream();
virtual ~Px3MemOutStream();
void resetPosition();
virtual physx::PxU32 write(const void *src, physx::PxU32 count);
physx::PxU32 getSize() const {return mMemStream.getStreamSize();}
physx::PxU8* getData() const {return (physx::PxU8*)mMemStream.getBuffer();}
protected:
mutable MemStream mMemStream;
};
class Px3MemInStream: public physx::PxInputData
{
public:
Px3MemInStream(physx::PxU8* data, physx::PxU32 length);
virtual physx::PxU32 read(void* dest, physx::PxU32 count);
physx::PxU32 getLength() const;
virtual void seek(physx::PxU32 pos);
virtual physx::PxU32 tell() const;
protected:
mutable MemStream mMemStream;
};
class Px3ConsoleStream : public physx::PxDefaultErrorCallback
{
protected:
virtual void reportError( physx::PxErrorCode code, const char *message, const char* file, int line );
public:
Px3ConsoleStream();
virtual ~Px3ConsoleStream();
};
#endif // _PX3STREAM_H_

View file

@ -21,17 +21,12 @@
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "unit/memoryTester.h"
#include "T3D/physics/physx3/px3Utils.h"
#include "T3D/physics/physx3/px3.h"
using namespace UnitTesting;
void MemoryTester::mark()
physx::PxShape* px3GetFirstShape(physx::PxRigidActor *actor)
{
}
bool MemoryTester::check()
{
//UnitTesting::UnitPrint("MemoryTester::check - unavailable w/o TORQUE_DEBUG_GUARD defined!");
return true;
physx::PxShape *shapes[1];
actor->getShapes(shapes, 1);
return shapes[0];
}

View file

@ -20,18 +20,15 @@
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _UNIT_MEMORYTESTER_H_
#define _UNIT_MEMORYTESTER_H_
#ifndef _PX3UTILS_H_
#define _PX3UTILS_H_
namespace UnitTesting
namespace physx
{
class MemoryTester
{
public:
void mark();
bool check();
};
class PxRigidActor;
class PxShape;
}
extern physx::PxShape* px3GetFirstShape(physx::PxRigidActor *actor);
#endif
#endif // _PX3UTILS_H_

View file

@ -0,0 +1,565 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "T3D/physics/physx3/px3World.h"
#include "T3D/physics/physx3/px3.h"
#include "T3D/physics/physx3/px3Plugin.h"
#include "T3D/physics/physx3/px3Casts.h"
#include "T3D/physics/physx3/px3Stream.h"
#include "T3D/physics/physicsUserData.h"
#include "console/engineAPI.h"
#include "core/stream/bitStream.h"
#include "platform/profiler.h"
#include "sim/netConnection.h"
#include "console/console.h"
#include "console/consoleTypes.h"
#include "core/util/safeDelete.h"
#include "collision/collision.h"
#include "T3D/gameBase/gameProcess.h"
#include "gfx/sim/debugDraw.h"
#include "gfx/primBuilder.h"
physx::PxPhysics* gPhysics3SDK = NULL;
physx::PxCooking* Px3World::smCooking = NULL;
physx::PxFoundation* Px3World::smFoundation = NULL;
physx::PxProfileZoneManager* Px3World::smProfileZoneManager = NULL;
physx::PxDefaultCpuDispatcher* Px3World::smCpuDispatcher=NULL;
Px3ConsoleStream* Px3World::smErrorCallback = NULL;
physx::PxVisualDebuggerConnection* Px3World::smPvdConnection=NULL;
physx::PxDefaultAllocator Px3World::smMemoryAlloc;
//Physics timing
F32 Px3World::smPhysicsStepTime = 1.0f/(F32)TickMs;
U32 Px3World::smPhysicsMaxIterations = 4;
Px3World::Px3World(): mScene( NULL ),
mProcessList( NULL ),
mIsSimulating( false ),
mErrorReport( false ),
mTickCount( 0 ),
mIsEnabled( false ),
mEditorTimeScale( 1.0f ),
mAccumulator( 0 ),
mControllerManager( NULL )
{
}
Px3World::~Px3World()
{
}
physx::PxCooking *Px3World::getCooking()
{
return smCooking;
}
void Px3World::setTiming(F32 stepTime,U32 maxIterations)
{
smPhysicsStepTime = stepTime;
smPhysicsMaxIterations = maxIterations;
}
bool Px3World::restartSDK( bool destroyOnly, Px3World *clientWorld, Px3World *serverWorld)
{
// If either the client or the server still exist
// then we cannot reset the SDK.
if ( clientWorld || serverWorld )
return false;
if(smPvdConnection)
smPvdConnection->release();
if(smCooking)
smCooking->release();
if(smCpuDispatcher)
smCpuDispatcher->release();
// Destroy the existing SDK.
if ( gPhysics3SDK )
{
PxCloseExtensions();
gPhysics3SDK->release();
}
if(smErrorCallback)
{
SAFE_DELETE(smErrorCallback);
}
if(smFoundation)
{
smFoundation->release();
SAFE_DELETE(smErrorCallback);
}
// If we're not supposed to restart... return.
if ( destroyOnly )
return true;
bool memTrack = false;
#ifdef TORQUE_DEBUG
memTrack = true;
#endif
smErrorCallback = new Px3ConsoleStream;
smFoundation = PxCreateFoundation(PX_PHYSICS_VERSION, smMemoryAlloc, *smErrorCallback);
smProfileZoneManager = &physx::PxProfileZoneManager::createProfileZoneManager(smFoundation);
gPhysics3SDK = PxCreatePhysics(PX_PHYSICS_VERSION, *smFoundation, physx::PxTolerancesScale(),memTrack,smProfileZoneManager);
if ( !gPhysics3SDK )
{
Con::errorf( "PhysX3 failed to initialize!" );
Platform::messageBox( Con::getVariable( "$appName" ),
avar("PhysX3 could not be started!\r\n"),
MBOk, MIStop );
Platform::forceShutdown( -1 );
// We shouldn't get here, but this shuts up
// source diagnostic tools.
return false;
}
if(!PxInitExtensions(*gPhysics3SDK))
{
Con::errorf( "PhysX3 failed to initialize extensions!" );
Platform::messageBox( Con::getVariable( "$appName" ),
avar("PhysX3 could not be started!\r\n"),
MBOk, MIStop );
Platform::forceShutdown( -1 );
return false;
}
smCooking = PxCreateCooking(PX_PHYSICS_VERSION, *smFoundation, physx::PxCookingParams(physx::PxTolerancesScale()));
if(!smCooking)
{
Con::errorf( "PhysX3 failed to initialize cooking!" );
Platform::messageBox( Con::getVariable( "$appName" ),
avar("PhysX3 could not be started!\r\n"),
MBOk, MIStop );
Platform::forceShutdown( -1 );
return false;
}
#ifdef TORQUE_DEBUG
physx::PxVisualDebuggerConnectionFlags connectionFlags(physx::PxVisualDebuggerExt::getAllConnectionFlags());
smPvdConnection = physx::PxVisualDebuggerExt::createConnection(gPhysics3SDK->getPvdConnectionManager(),
"localhost", 5425, 100, connectionFlags);
#endif
return true;
}
void Px3World::destroyWorld()
{
getPhysicsResults();
// Release the tick processing signals.
if ( mProcessList )
{
mProcessList->preTickSignal().remove( this, &Px3World::getPhysicsResults );
mProcessList->postTickSignal().remove( this, &Px3World::tickPhysics );
mProcessList = NULL;
}
if(mControllerManager)
{
mControllerManager->release();
mControllerManager = NULL;
}
// Destroy the scene.
if ( mScene )
{
// Release the scene.
mScene->release();
mScene = NULL;
}
}
bool Px3World::initWorld( bool isServer, ProcessList *processList )
{
if ( !gPhysics3SDK )
{
Con::errorf( "Physx3World::init - PhysXSDK not initialized!" );
return false;
}
mIsServer = isServer;
physx::PxSceneDesc sceneDesc(gPhysics3SDK->getTolerancesScale());
sceneDesc.gravity = px3Cast<physx::PxVec3>(mGravity);
sceneDesc.userData = this;
if(!sceneDesc.cpuDispatcher)
{
smCpuDispatcher = physx::PxDefaultCpuDispatcherCreate(PHYSICSMGR->getThreadCount());
sceneDesc.cpuDispatcher = smCpuDispatcher;
Con::printf("PhysX3 using Cpu: %d workers", smCpuDispatcher->getWorkerCount());
}
sceneDesc.flags |= physx::PxSceneFlag::eENABLE_CCD;
sceneDesc.flags |= physx::PxSceneFlag::eENABLE_ACTIVETRANSFORMS;
sceneDesc.filterShader = physx::PxDefaultSimulationFilterShader;
mScene = gPhysics3SDK->createScene(sceneDesc);
physx::PxDominanceGroupPair debrisDominance( 0.0f, 1.0f );
mScene->setDominanceGroupPair(0,31,debrisDominance);
mControllerManager = PxCreateControllerManager(*mScene);
AssertFatal( processList, "Px3World::init() - We need a process list to create the world!" );
mProcessList = processList;
mProcessList->preTickSignal().notify( this, &Px3World::getPhysicsResults );
mProcessList->postTickSignal().notify( this, &Px3World::tickPhysics, 1000.0f );
return true;
}
// Most of this borrowed from bullet physics library, see btDiscreteDynamicsWorld.cpp
bool Px3World::_simulate(const F32 dt)
{
int numSimulationSubSteps = 0;
//fixed timestep with interpolation
mAccumulator += dt;
if (mAccumulator >= smPhysicsStepTime)
{
numSimulationSubSteps = int(mAccumulator / smPhysicsStepTime);
mAccumulator -= numSimulationSubSteps * smPhysicsStepTime;
}
if (numSimulationSubSteps)
{
//clamp the number of substeps, to prevent simulation grinding spiralling down to a halt
int clampedSimulationSteps = (numSimulationSubSteps > smPhysicsMaxIterations)? smPhysicsMaxIterations : numSimulationSubSteps;
for (int i=0;i<clampedSimulationSteps;i++)
{
mScene->fetchResults(true);
mScene->simulate(smPhysicsStepTime);
}
}
mIsSimulating = true;
return true;
}
void Px3World::tickPhysics( U32 elapsedMs )
{
if ( !mScene || !mIsEnabled )
return;
// Did we forget to call getPhysicsResults somewhere?
AssertFatal( !mIsSimulating, "PhysX3World::tickPhysics() - Already simulating!" );
// The elapsed time should be non-zero and
// a multiple of TickMs!
AssertFatal( elapsedMs != 0 &&
( elapsedMs % TickMs ) == 0 , "PhysX3World::tickPhysics() - Got bad elapsed time!" );
PROFILE_SCOPE(Px3World_TickPhysics);
// Convert it to seconds.
const F32 elapsedSec = (F32)elapsedMs * 0.001f;
mIsSimulating = _simulate(elapsedSec * mEditorTimeScale);
//Con::printf( "%s PhysX3World::tickPhysics!", mIsServer ? "Client" : "Server" );
}
void Px3World::getPhysicsResults()
{
if ( !mScene || !mIsSimulating )
return;
PROFILE_SCOPE(Px3World_GetPhysicsResults);
// Get results from scene.
mScene->fetchResults(true);
mIsSimulating = false;
mTickCount++;
// Con::printf( "%s PhysXWorld::getPhysicsResults!", this == smClientWorld ? "Client" : "Server" );
}
void Px3World::releaseWriteLocks()
{
Px3World *world = dynamic_cast<Px3World*>( PHYSICSMGR->getWorld( "server" ) );
if ( world )
world->releaseWriteLock();
world = dynamic_cast<Px3World*>( PHYSICSMGR->getWorld( "client" ) );
if ( world )
world->releaseWriteLock();
}
void Px3World::releaseWriteLock()
{
if ( !mScene || !mIsSimulating )
return;
PROFILE_SCOPE(PxWorld_ReleaseWriteLock);
// We use checkResults here to release the write lock
// but we do not change the simulation flag or increment
// the tick count... we may have gotten results, but the
// simulation hasn't really ticked!
mScene->checkResults( true );
//AssertFatal( mScene->isWritable(), "PhysX3World::releaseWriteLock() - We should have been writable now!" );
}
bool Px3World::castRay( const Point3F &startPnt, const Point3F &endPnt, RayInfo *ri, const Point3F &impulse )
{
physx::PxVec3 orig = px3Cast<physx::PxVec3>( startPnt );
physx::PxVec3 dir = px3Cast<physx::PxVec3>( endPnt - startPnt );
physx::PxF32 maxDist = dir.magnitude();
dir.normalize();
U32 groups = 0xffffffff;
groups &= ~( PX3_TRIGGER ); // No trigger shapes!
physx::PxHitFlags outFlags(physx::PxHitFlag::eDISTANCE | physx::PxHitFlag::eIMPACT | physx::PxHitFlag::eNORMAL);
physx::PxQueryFilterData filterData(physx::PxQueryFlag::eSTATIC|physx::PxQueryFlag::eDYNAMIC);
filterData.data.word0 = groups;
physx::PxRaycastBuffer buf;
if(!mScene->raycast(orig,dir,maxDist,buf,outFlags,filterData))
return false;
if(!buf.hasBlock)
return false;
const physx::PxRaycastHit hit = buf.block;
physx::PxRigidActor *actor = hit.actor;
PhysicsUserData *userData = PhysicsUserData::cast( actor->userData );
if ( ri )
{
ri->object = ( userData != NULL ) ? userData->getObject() : NULL;
if ( ri->object == NULL )
ri->distance = hit.distance;
ri->normal = px3Cast<Point3F>( hit.normal );
ri->point = px3Cast<Point3F>( hit.position );
ri->t = maxDist / hit.distance;
}
if ( impulse.isZero() ||
!actor->isRigidDynamic() ||
actor->is<physx::PxRigidDynamic>()->getRigidDynamicFlags() & physx::PxRigidDynamicFlag::eKINEMATIC )
return true;
physx::PxRigidBody *body = actor->is<physx::PxRigidBody>();
physx::PxVec3 force = px3Cast<physx::PxVec3>( impulse );
physx::PxRigidBodyExt::addForceAtPos(*body,force,hit.position,physx::PxForceMode::eIMPULSE);
return true;
}
PhysicsBody* Px3World::castRay( const Point3F &start, const Point3F &end, U32 bodyTypes )
{
physx::PxVec3 orig = px3Cast<physx::PxVec3>( start );
physx::PxVec3 dir = px3Cast<physx::PxVec3>( end - start );
physx::PxF32 maxDist = dir.magnitude();
dir.normalize();
U32 groups = 0xFFFFFFFF;
if ( !( bodyTypes & BT_Player ) )
groups &= ~( PX3_PLAYER );
// TODO: For now always skip triggers and debris,
// but we should consider how game specifc this API
// should be in the future.
groups &= ~( PX3_TRIGGER ); // triggers
groups &= ~( PX3_DEBRIS ); // debris
physx::PxHitFlags outFlags(physx::PxHitFlag::eDISTANCE | physx::PxHitFlag::eIMPACT | physx::PxHitFlag::eNORMAL);
physx::PxQueryFilterData filterData;
if(bodyTypes & BT_Static)
filterData.flags |= physx::PxQueryFlag::eSTATIC;
if(bodyTypes & BT_Dynamic)
filterData.flags |= physx::PxQueryFlag::eDYNAMIC;
filterData.data.word0 = groups;
physx::PxRaycastBuffer buf;
if( !mScene->raycast(orig,dir,maxDist,buf,outFlags,filterData) )
return NULL;
if(!buf.hasBlock)
return NULL;
physx::PxRigidActor *actor = buf.block.actor;
PhysicsUserData *userData = PhysicsUserData::cast( actor->userData );
if( !userData )
return NULL;
return userData->getBody();
}
void Px3World::explosion( const Point3F &pos, F32 radius, F32 forceMagnitude )
{
physx::PxVec3 nxPos = px3Cast<physx::PxVec3>( pos );
const physx::PxU32 bufferSize = 10;
physx::PxSphereGeometry worldSphere(radius);
physx::PxTransform pose(nxPos);
physx::PxOverlapBufferN<bufferSize> buffer;
if(!mScene->overlap(worldSphere,pose,buffer))
return;
for ( physx::PxU32 i = 0; i < buffer.nbTouches; i++ )
{
physx::PxRigidActor *actor = buffer.touches[i].actor;
bool dynamic = actor->isRigidDynamic();
if ( !dynamic )
continue;
bool kinematic = actor->is<physx::PxRigidDynamic>()->getRigidDynamicFlags() & physx::PxRigidDynamicFlag::eKINEMATIC;
if ( kinematic )
continue;
physx::PxVec3 force = actor->getGlobalPose().p - nxPos;
force.normalize();
force *= forceMagnitude;
physx::PxRigidBody *body = actor->is<physx::PxRigidBody>();
physx::PxRigidBodyExt::addForceAtPos(*body,force,nxPos,physx::PxForceMode::eIMPULSE);
}
}
void Px3World::setEnabled( bool enabled )
{
mIsEnabled = enabled;
if ( !mIsEnabled )
getPhysicsResults();
}
physx::PxController* Px3World::createController( physx::PxControllerDesc &desc )
{
if ( !mScene )
return NULL;
// We need the writelock!
releaseWriteLock();
physx::PxController* pController = mControllerManager->createController(desc);
AssertFatal( pController, "Px3World::createController - Got a null!" );
return pController;
}
static ColorI getDebugColor( physx::PxU32 packed )
{
ColorI col;
col.blue = (packed)&0xff;
col.green = (packed>>8)&0xff;
col.red = (packed>>16)&0xff;
col.alpha = 255;
return col;
}
void Px3World::onDebugDraw( const SceneRenderState *state )
{
if ( !mScene )
return;
mScene->setVisualizationParameter(physx::PxVisualizationParameter::eSCALE,1.0f);
mScene->setVisualizationParameter(physx::PxVisualizationParameter::eBODY_AXES,1.0f);
mScene->setVisualizationParameter(physx::PxVisualizationParameter::eCOLLISION_SHAPES,1.0f);
const physx::PxRenderBuffer *renderBuffer = &mScene->getRenderBuffer();
if(!renderBuffer)
return;
// Render points
{
physx::PxU32 numPoints = renderBuffer->getNbPoints();
const physx::PxDebugPoint *points = renderBuffer->getPoints();
PrimBuild::begin( GFXPointList, numPoints );
while ( numPoints-- )
{
PrimBuild::color( getDebugColor(points->color) );
PrimBuild::vertex3fv(px3Cast<Point3F>(points->pos));
points++;
}
PrimBuild::end();
}
// Render lines
{
physx::PxU32 numLines = renderBuffer->getNbLines();
const physx::PxDebugLine *lines = renderBuffer->getLines();
PrimBuild::begin( GFXLineList, numLines * 2 );
while ( numLines-- )
{
PrimBuild::color( getDebugColor( lines->color0 ) );
PrimBuild::vertex3fv( px3Cast<Point3F>(lines->pos0));
PrimBuild::color( getDebugColor( lines->color1 ) );
PrimBuild::vertex3fv( px3Cast<Point3F>(lines->pos1));
lines++;
}
PrimBuild::end();
}
// Render triangles
{
physx::PxU32 numTris = renderBuffer->getNbTriangles();
const physx::PxDebugTriangle *triangles = renderBuffer->getTriangles();
PrimBuild::begin( GFXTriangleList, numTris * 3 );
while ( numTris-- )
{
PrimBuild::color( getDebugColor( triangles->color0 ) );
PrimBuild::vertex3fv( px3Cast<Point3F>(triangles->pos0) );
PrimBuild::color( getDebugColor( triangles->color1 ) );
PrimBuild::vertex3fv( px3Cast<Point3F>(triangles->pos1));
PrimBuild::color( getDebugColor( triangles->color2 ) );
PrimBuild::vertex3fv( px3Cast<Point3F>(triangles->pos2) );
triangles++;
}
PrimBuild::end();
}
}
//set simulation timing via script
DefineEngineFunction( physx3SetSimulationTiming, void, ( F32 stepTime, U32 maxSteps ),, "Set simulation timing of the PhysX 3 plugin" )
{
Px3World::setTiming(stepTime,maxSteps);
}

View file

@ -0,0 +1,106 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _PX3WORLD_H_
#define _PX3WORLD_H_
#ifndef _T3D_PHYSICS_PHYSICSWORLD_H_
#include "T3D/physics/physicsWorld.h"
#endif
#ifndef _MMATH_H_
#include "math/mMath.h"
#endif
#ifndef _PHYSX3_H_
#include "T3D/physics/physx3/px3.h"
#endif
#ifndef _TVECTOR_H_
#include "core/util/tVector.h"
#endif
class Px3ConsoleStream;
class Px3ContactReporter;
class FixedStepper;
enum Px3CollisionGroup
{
PX3_DEFAULT = BIT(0),
PX3_PLAYER = BIT(1),
PX3_DEBRIS = BIT(2),
PX3_TRIGGER = BIT(3),
};
class Px3World : public PhysicsWorld
{
protected:
physx::PxScene* mScene;
bool mIsEnabled;
bool mIsSimulating;
bool mIsServer;
U32 mTickCount;
ProcessList *mProcessList;
F32 mEditorTimeScale;
bool mErrorReport;
physx::PxControllerManager* mControllerManager;
static Px3ConsoleStream *smErrorCallback;
static physx::PxDefaultAllocator smMemoryAlloc;
static physx::PxFoundation* smFoundation;
static physx::PxCooking *smCooking;
static physx::PxProfileZoneManager* smProfileZoneManager;
static physx::PxDefaultCpuDispatcher* smCpuDispatcher;
static physx::PxVisualDebuggerConnection* smPvdConnection;
static F32 smPhysicsStepTime;
static U32 smPhysicsMaxIterations;
F32 mAccumulator;
bool _simulate(const F32 dt);
public:
Px3World();
virtual ~Px3World();
virtual bool initWorld( bool isServer, ProcessList *processList );
virtual void destroyWorld();
virtual void onDebugDraw( const SceneRenderState *state );
virtual void reset() {}
virtual bool castRay( const Point3F &startPnt, const Point3F &endPnt, RayInfo *ri, const Point3F &impulse );
virtual PhysicsBody* castRay( const Point3F &start, const Point3F &end, U32 bodyTypes = BT_All );
virtual void explosion( const Point3F &pos, F32 radius, F32 forceMagnitude );
virtual bool isEnabled() const { return mIsEnabled; }
physx::PxScene* getScene(){ return mScene;}
void setEnabled( bool enabled );
U32 getTick() { return mTickCount; }
void tickPhysics( U32 elapsedMs );
void getPhysicsResults();
void setEditorTimeScale( F32 timeScale ) { mEditorTimeScale = timeScale; }
const F32 getEditorTimeScale() const { return mEditorTimeScale; }
void releaseWriteLock();
bool isServer(){return mIsServer;}
physx::PxController* createController( physx::PxControllerDesc &desc );
//static
static bool restartSDK( bool destroyOnly = false, Px3World *clientWorld = NULL, Px3World *serverWorld = NULL );
static void releaseWriteLocks();
static physx::PxCooking *getCooking();
static void setTiming(F32 stepTime,U32 maxIterations);
};
#endif // _PX3WORLD_H_

View file

@ -356,6 +356,7 @@ PlayerData::PlayerData()
decalID = 0;
decalOffset = 0.0f;
actionCount = 0;
lookAction = 0;
// size of bounding box
@ -427,9 +428,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() );
}
}
@ -487,10 +488,6 @@ 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 (S32 b = 0; b < mShape->mSequences.size(); b++)
{
@ -586,7 +583,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();
@ -2952,7 +2952,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;
@ -3692,7 +3692,7 @@ bool Player::setActionThread(const char* sequence,bool hold,bool wait,bool fsp)
void Player::setActionThread(U32 action,bool forward,bool hold,bool wait,bool fsp, bool forceSet)
{
if (!mDataBlock || (mActionAnimation.action == action && mActionAnimation.forward == forward && !forceSet))
if (!mDataBlock || !mDataBlock->actionCount || (mActionAnimation.action == action && mActionAnimation.forward == forward && !forceSet))
return;
if (action >= PlayerData::NumActionAnims)
@ -6507,8 +6507,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;
}

View file

@ -320,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)
@ -550,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 ),
@ -697,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;
@ -1011,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();

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 )

View file

@ -92,7 +92,7 @@ ConsoleDocClass( RigidShapeData,
"@see RigidShape\n"
"@see ShapeBase\n\n"
"@ingroup Platform\n"
"@ingroup Physics\n"
);
@ -149,7 +149,7 @@ ConsoleDocClass( RigidShape,
"@see RigidShapeData\n"
"@see ShapeBase\n\n"
"@ingroup Platform\n"
"@ingroup Physics\n"
);
@ -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;
}
@ -1140,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);

View file

@ -91,7 +91,9 @@ void SFX3DObject::getEarTransform( MatrixF& transform ) const
if ( !shapeInstance )
{
// Just in case.
transform = mObject->getTransform();
GameConnection* connection = dynamic_cast<GameConnection *>(NetConnection::getConnectionToServer());
if ( !connection || !connection->getControlCameraTransform( 0.0f, &transform ) )
transform = mObject->getTransform();
return;
}

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"
@ -306,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();
@ -928,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;
@ -2152,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;
@ -2174,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:
@ -2196,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
@ -2208,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)
@ -2325,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++) {
@ -2349,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));
}
}
@ -2358,6 +2334,7 @@ void ShapeBase::advanceThreads(F32 dt)
if(st.thread)
{
mShapeInstance->advanceTime(dt,st.thread);
st.position = mShapeInstance->getPos(st.thread);
}
}
}
@ -3058,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);

View file

@ -648,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 ) );
/// @}
};
@ -729,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;
};
@ -1354,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);

View file

@ -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)
{

View file

@ -259,8 +259,9 @@ 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,

View file

@ -111,6 +111,11 @@ TSStatic::TSStatic()
mMeshCulling = false;
mUseOriginSort = false;
mUseAlphaFade = false;
mAlphaFadeStart = 100.0f;
mAlphaFadeEnd = 150.0f;
mInvertAlphaFade = false;
mAlphaFade = 1.0f;
mPhysicsRep = NULL;
mCollisionType = CollisionMesh;
@ -192,6 +197,13 @@ void TSStatic::initPersistFields()
endGroup("Collision");
addGroup( "AlphaFade" );
addField( "Alpha Fade Enable", TypeBool, Offset(mUseAlphaFade, TSStatic), "Turn on/off Alpha Fade" );
addField( "Alpha Fade Start", TypeF32, Offset(mAlphaFadeStart, TSStatic), "Distance of start Alpha Fade" );
addField( "Alpha Fade End", TypeF32, Offset(mAlphaFadeEnd, TSStatic), "Distance of end Alpha Fade" );
addField( "Alpha Fade Inverse", TypeBool, Offset(mInvertAlphaFade, TSStatic), "Invert Alpha Fade's Start & End Distance" );
endGroup( "AlphaFade" );
addGroup("Debug");
addField( "renderNormals", TypeF32, Offset( mRenderNormalScalar, TSStatic ),
@ -502,6 +514,36 @@ void TSStatic::prepRenderImage( SceneRenderState* state )
if (dist < 0.01f)
dist = 0.01f;
if (mUseAlphaFade)
{
mAlphaFade = 1.0f;
if ((mAlphaFadeStart < mAlphaFadeEnd) && mAlphaFadeStart > 0.1f)
{
if (mInvertAlphaFade)
{
if (dist <= mAlphaFadeStart)
{
return;
}
if (dist < mAlphaFadeEnd)
{
mAlphaFade = ((dist - mAlphaFadeStart) / (mAlphaFadeEnd - mAlphaFadeStart));
}
}
else
{
if (dist >= mAlphaFadeEnd)
{
return;
}
if (dist > mAlphaFadeStart)
{
mAlphaFade -= ((dist - mAlphaFadeStart) / (mAlphaFadeEnd - mAlphaFadeStart));
}
}
}
}
F32 invScale = (1.0f/getMax(getMax(mObjScale.x,mObjScale.y),mObjScale.z));
if ( mForceDetail == -1 )
@ -545,6 +587,19 @@ void TSStatic::prepRenderImage( SceneRenderState* state )
GFX->setWorldMatrix( mat );
mShapeInstance->animate();
if(mShapeInstance)
{
if (mUseAlphaFade)
{
mShapeInstance->setAlphaAlways(mAlphaFade);
S32 s = mShapeInstance->mMeshObjects.size();
for(S32 x = 0; x < s; x++)
{
mShapeInstance->mMeshObjects[x].visible = mAlphaFade;
}
}
}
mShapeInstance->render( rdata );
if ( mRenderNormalScalar > 0 )
@ -625,6 +680,13 @@ U32 TSStatic::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
stream->writeFlag( mPlayAmbient );
if ( stream->writeFlag(mUseAlphaFade) )
{
stream->write(mAlphaFadeStart);
stream->write(mAlphaFadeEnd);
stream->write(mInvertAlphaFade);
}
if ( mLightPlugin )
retMask |= mLightPlugin->packUpdate(this, AdvancedStaticOptionsMask, con, mask, stream);
@ -682,6 +744,14 @@ void TSStatic::unpackUpdate(NetConnection *con, BitStream *stream)
mPlayAmbient = stream->readFlag();
mUseAlphaFade = stream->readFlag();
if (mUseAlphaFade)
{
stream->read(&mAlphaFadeStart);
stream->read(&mAlphaFadeEnd);
stream->read(&mInvertAlphaFade);
}
if ( mLightPlugin )
{
mLightPlugin->unpackUpdate(this, con, stream);
@ -702,41 +772,9 @@ bool TSStatic::castRay(const Point3F &start, const Point3F &end, RayInfo* info)
if ( mCollisionType == Bounds )
{
F32 st, et, fst = 0.0f, fet = 1.0f;
F32 *bmin = &mObjBox.minExtents.x;
F32 *bmax = &mObjBox.maxExtents.x;
F32 const *si = &start.x;
F32 const *ei = &end.x;
for ( U32 i = 0; i < 3; i++ )
{
if (*si < *ei)
{
if ( *si > *bmax || *ei < *bmin )
return false;
F32 di = *ei - *si;
st = ( *si < *bmin ) ? ( *bmin - *si ) / di : 0.0f;
et = ( *ei > *bmax ) ? ( *bmax - *si ) / di : 1.0f;
}
else
{
if ( *ei > *bmax || *si < *bmin )
return false;
F32 di = *ei - *si;
st = ( *si > *bmax ) ? ( *bmax - *si ) / di : 0.0f;
et = ( *ei < *bmin ) ? ( *bmin - *si ) / di : 1.0f;
}
if ( st > fst ) fst = st;
if ( et < fet ) fet = et;
if ( fet < fst )
return false;
bmin++; bmax++;
si++; ei++;
}
info->normal = start - end;
info->normal.normalizeSafe();
getTransform().mulV( info->normal );
F32 fst;
if (!mObjBox.collideLine(start, end, &fst, &info->normal))
return false;
info->t = fst;
info->object = this;

View file

@ -97,6 +97,13 @@ class TSStatic : public SceneObject
};
public:
void setAlphaFade(bool enable, F32 start, F32 end, bool inverse)
{
mUseAlphaFade = enable;
mAlphaFadeStart = start;
mAlphaFadeEnd = end;
mInvertAlphaFade = inverse;
}
/// The different types of mesh data types
enum MeshType
@ -108,6 +115,11 @@ public:
};
protected:
bool mUseAlphaFade;
F32 mAlphaFadeStart;
F32 mAlphaFadeEnd;
F32 mAlphaFade;
bool mInvertAlphaFade;
bool onAdd();
void onRemove();

View file

@ -892,7 +892,7 @@ void AITurretShape::_trackTarget(F32 dt)
//if (pitch > M_PI_F)
// pitch = -(pitch - M_2PI_F);
Point3F rot(pitch, 0.0f, -yaw);
Point3F rot(-pitch, 0.0f, yaw);
// If we have a rotation rate make sure we follow it
if (mHeadingRate > 0)

View file

@ -1155,7 +1155,7 @@ void TurretShape::unpackUpdate(NetConnection *connection, BitStream *stream)
void TurretShape::getWeaponMountTransform( S32 index, const MatrixF &xfm, MatrixF *outMat )
{
// Returns mount point to world space transform
if ( index >= 0 && index < SceneObject::NumMountPoints) {
if ( index >= 0 && index < ShapeBase::MaxMountedImages) {
S32 ni = mDataBlock->weaponMountNode[index];
if (ni != -1) {
MatrixF mountTransform = mShapeInstance->mNodeTransforms[ni];
@ -1180,7 +1180,7 @@ void TurretShape::getWeaponMountTransform( S32 index, const MatrixF &xfm, Matrix
void TurretShape::getRenderWeaponMountTransform( F32 delta, S32 mountPoint, const MatrixF &xfm, MatrixF *outMat )
{
// Returns mount point to world space transform
if ( mountPoint >= 0 && mountPoint < SceneObject::NumMountPoints) {
if ( mountPoint >= 0 && mountPoint < ShapeBase::MaxMountedImages) {
S32 ni = mDataBlock->weaponMountNode[mountPoint];
if (ni != -1) {
MatrixF mountTransform = mShapeInstance->mNodeTransforms[ni];

View file

@ -218,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;
}

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

@ -623,6 +623,11 @@ bool StandardMainLoop::doMainLoop()
return keepRunning;
}
S32 StandardMainLoop::getReturnStatus()
{
return Process::getReturnStatus();
}
void StandardMainLoop::setRestart(bool restart )
{
gRequiresRestart = restart;

View file

@ -41,6 +41,9 @@ public:
/// Shut down the core libraries and call registered shutdown fucntions.
static void shutdown();
/// Gets the return status code of the current process.
static S32 getReturnStatus();
static void setRestart( bool restart );
static bool requiresRestart();

View file

@ -266,7 +266,19 @@ void HTTPObject::onConnected()
char *pt = dStrchr(mHostName, ':');
if(pt)
*pt = 0;
dSprintf(buffer, sizeof(buffer), "GET %s HTTP/1.1\r\nHost: %s\r\n\r\n", expPath, mHostName);
//If we want to do a get request
if(mPost == NULL)
{
dSprintf(buffer, sizeof(buffer), "GET %s HTTP/1.1\r\nHost: %s\r\n\r\n", expPath, mHostName);
}
//Else we want to do a post request
else
{
dSprintf(buffer, sizeof(buffer), "POST %s HTTP/1.1\r\nHost: %s\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: %i\r\n\r\n%s\r\n\r\n",
expPath, mHostName, dStrlen(mPost), mPost);
}
if(pt)
*pt = ':';
@ -431,8 +443,6 @@ DefineEngineMethod( HTTPObject, post, void, ( const char* Address, const char* r
"@param requirstURI Specific location on the server to access (IE: \"index.php\".)\n"
"@param query Actual data to transmit to the server. Can be anything required providing it sticks with limitations of the HTTP protocol. \n"
"@param post Submission data to be processed.\n"
"@note The post() method is currently non-functional.\n"
"@tsexample\n"
"// Create an HTTP object for communications\n"

View file

@ -251,7 +251,8 @@ ConsoleFunction( commandToServer, void, 2, RemoteCommandEvent::MaxRemoteCommandA
NetConnection *conn = NetConnection::getConnectionToServer();
if(!conn)
return;
RemoteCommandEvent::sendRemoteCommand(conn, argc - 1, argv + 1);
StringStackWrapper args(argc - 1, argv + 1);
RemoteCommandEvent::sendRemoteCommand(conn, args.count(), args);
}
ConsoleFunction( commandToClient, void, 3, RemoteCommandEvent::MaxRemoteCommandArgs + 2, "(NetConnection client, string func, ...)"
@ -288,7 +289,8 @@ ConsoleFunction( commandToClient, void, 3, RemoteCommandEvent::MaxRemoteCommandA
NetConnection *conn;
if(!Sim::findObject(argv[1], conn))
return;
RemoteCommandEvent::sendRemoteCommand(conn, argc - 2, argv + 2);
StringStackWrapper args(argc - 2, argv + 2);
RemoteCommandEvent::sendRemoteCommand(conn, args.count(), args);
}
@ -304,9 +306,10 @@ DefineEngineFunction(removeTaggedString, void, (S32 tag), (-1),
"@see addTaggedString()\n"
"@see getTaggedString()\n"
"@ingroup Networking\n")
{
RemoteCommandEvent::removeTaggedString(tag);
}
{
RemoteCommandEvent::removeTaggedString(tag);
}
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"
@ -320,10 +323,9 @@ DefineEngineFunction(addTaggedString, const char* , (const char* str), (""),
"@see removeTaggedString()\n"
"@see getTaggedString()\n"
"@ingroup Networking\n")
{
return RemoteCommandEvent::addTaggedString(str);
}
{
return RemoteCommandEvent::addTaggedString(str);
}
DefineEngineFunction(getTaggedString, const char* , (const char *tag), (""),
@ -382,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

@ -226,7 +226,7 @@ TCPObject::~TCPObject()
}
}
bool TCPObject::processArguments(S32 argc, const char **argv)
bool TCPObject::processArguments(S32 argc, ConsoleValueRef *argv)
{
if(argc == 0)
return true;

View file

@ -79,7 +79,7 @@ public:
void disconnect();
State getState() { return mState; }
bool processArguments(S32 argc, const char **argv);
bool processArguments(S32 argc, ConsoleValueRef *argv);
void send(const U8 *buffer, U32 bufferLen);
void addToTable(NetSocket newTag);
void removeFromTable();

View file

@ -41,10 +41,10 @@
/// 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 3501
#define TORQUE_GAME_ENGINE 3620
/// Human readable engine version string.
#define TORQUE_GAME_ENGINE_VERSION_STRING "3.5.1"
#define TORQUE_GAME_ENGINE_VERSION_STRING "3.6.2"
/// Gets the engine version number. The version number is specified as a global in version.cc
U32 getVersionNumber();

View file

@ -76,7 +76,7 @@ extern "C" {
if (!entry)
return "";
const char* argv[] = {"consoleExportXML", 0};
ConsoleValueRef argv[] = {"consoleExportXML"};
return entry->cb.mStringCallbackFunc(NULL, 1, argv);
}
@ -215,14 +215,15 @@ extern "C" {
return "";
}
return entry->cb.mStringCallbackFunc(o, argc, argv);
StringStackConsoleWrapper args(argc, argv);
return entry->cb.mStringCallbackFunc(o, args.count(), args);
}
bool script_call_namespace_entry_bool(Namespace::Entry* entry, S32 argc, const char** argv)
{
// maxArgs improper on a number of console function/methods
if (argc < entry->mMinArgs)// || argc > entry->mMaxArgs)
return "";
return false;
SimObject* o = NULL;
@ -230,10 +231,11 @@ extern "C" {
{
o = Sim::findObject(dAtoi(argv[1]));
if (!o)
return "";
return false;
}
return entry->cb.mBoolCallbackFunc(o, argc, argv);
StringStackConsoleWrapper args(argc, argv);
return entry->cb.mBoolCallbackFunc(o, args.count(), args);
}
S32 script_call_namespace_entry_int(Namespace::Entry* entry, S32 argc, const char** argv)
@ -251,7 +253,8 @@ extern "C" {
return 0;
}
return entry->cb.mIntCallbackFunc(o, argc, argv);
StringStackConsoleWrapper args(argc, argv);
return entry->cb.mIntCallbackFunc(o, args.count(), args);
}
F32 script_call_namespace_entry_float(Namespace::Entry* entry, S32 argc, const char** argv)
@ -269,7 +272,8 @@ extern "C" {
return 0.0f;
}
return entry->cb.mFloatCallbackFunc(o, argc, argv);
StringStackConsoleWrapper args(argc, argv);
return entry->cb.mFloatCallbackFunc(o, args.count(), args);
}
@ -288,7 +292,8 @@ extern "C" {
return;
}
entry->cb.mVoidCallbackFunc(o, argc, argv);
StringStackConsoleWrapper args(argc, argv);
entry->cb.mVoidCallbackFunc(o, args.count(), args);
}
S32 script_simobject_get_id(SimObject* so)

View file

@ -132,6 +132,11 @@ extern "C" {
}
S32 torque_getreturnstatus()
{
return StandardMainLoop::getReturnStatus();
}
// signal an engine shutdown (as with the quit(); console command)
void torque_enginesignalshutdown()
{
@ -262,7 +267,8 @@ extern "C" {
if (!entry)
return;
entry->cb.mVoidCallbackFunc(NULL, argc, argv);
StringStackConsoleWrapper args(argc, argv);
entry->cb.mVoidCallbackFunc(NULL, args.count(), args);
}
F32 torque_callfloatfunction(const char* nameSpace, const char* name, S32 argc, const char ** argv)
@ -273,7 +279,8 @@ extern "C" {
if (!entry)
return 0.0f;
return entry->cb.mFloatCallbackFunc(NULL, argc, argv);
StringStackConsoleWrapper args(argc, argv);
return entry->cb.mFloatCallbackFunc(NULL, args.count(), args);
}
S32 torque_callintfunction(const char* nameSpace, const char* name, S32 argc, const char ** argv)
@ -284,7 +291,8 @@ extern "C" {
if (!entry)
return 0;
return entry->cb.mIntCallbackFunc(NULL, argc, argv);
StringStackConsoleWrapper args(argc, argv);
return entry->cb.mIntCallbackFunc(NULL, args.count(), args);
}
@ -295,7 +303,8 @@ extern "C" {
if (!entry)
return "";
return entry->cb.mStringCallbackFunc(NULL, argc, argv);
StringStackConsoleWrapper args(argc, argv);
return entry->cb.mStringCallbackFunc(NULL, args.count(), args);
}
bool torque_callboolfunction(const char* nameSpace, const char* name, S32 argc, const char ** argv)
@ -303,9 +312,10 @@ extern "C" {
Namespace::Entry* entry = GetEntry(nameSpace, name);
if (!entry)
return "";
return false;
return entry->cb.mBoolCallbackFunc(NULL, argc, argv);
StringStackConsoleWrapper args(argc, argv);
return entry->cb.mBoolCallbackFunc(NULL, args.count(), args);
}
@ -319,7 +329,8 @@ extern "C" {
if(!entry->mFunctionOffset)
return "";
const char* ret = entry->mCode->exec(entry->mFunctionOffset, StringTable->insert(name), entry->mNamespace, argc, argv, false, entry->mPackage);
StringStackConsoleWrapper args(argc, argv);
const char* ret = entry->mCode->exec(entry->mFunctionOffset, StringTable->insert(name), entry->mNamespace, args.count(), args, false, entry->mPackage);
if (!ret || !dStrlen(ret))
return "";
@ -468,9 +479,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

@ -181,25 +181,19 @@ void DepthSortList::set(const MatrixF & mat, Point3F & extents)
mPlaneList.clear();
mPlaneList.increment();
mPlaneList.last().set(-1.0f, 0.0f, 0.0f);
mPlaneList.last().d = -mExtent.x;
mPlaneList.last().set(-1.0f, 0.0f, 0.0f, -mExtent.x);
mPlaneList.increment();
mPlaneList.last().set( 1.0f, 0.0f, 0.0f);
mPlaneList.last().d = -mExtent.x;
mPlaneList.last().set( 1.0f, 0.0f, 0.0f, -mExtent.x);
mPlaneList.increment();
mPlaneList.last().set( 0.0f,-1.0f, 0.0f);
mPlaneList.last().d = 0;
mPlaneList.last().set( 0.0f,-1.0f, 0.0f, 0);
mPlaneList.increment();
mPlaneList.last().set( 0.0f, 1.0f, 0.0f);
mPlaneList.last().d = -2.0f * mExtent.y;
mPlaneList.last().set( 0.0f, 1.0f, 0.0f, -2.0f * mExtent.y);
mPlaneList.increment();
mPlaneList.last().set( 0.0f, 0.0f,-1.0f);
mPlaneList.last().d = -mExtent.z;
mPlaneList.last().set( 0.0f, 0.0f,-1.0f, -mExtent.z);
mPlaneList.increment();
mPlaneList.last().set( 0.0f, 0.0f, 1.0f);
mPlaneList.last().d = -mExtent.z;
mPlaneList.last().set( 0.0f, 0.0f, 1.0f, -mExtent.z);
}
//----------------------------------------------------------------------------

View file

@ -21,6 +21,10 @@
//-----------------------------------------------------------------------------
#include "component/dynamicConsoleMethodComponent.h"
#include "console/stringStack.h"
extern StringStack STR;
extern ConsoleValueStack CSTK;
IMPLEMENT_CO_NETOBJECT_V1(DynamicConsoleMethodComponent);
@ -90,7 +94,9 @@ const char *DynamicConsoleMethodComponent::callMethod( S32 argc, const char* met
argv[1] = methodName;
argv[2] = methodName;
return callMethodArgList( argc , argv );
StringStackConsoleWrapper argsw(argc, argv);
return callMethodArgList( argsw.count() , argsw );
}
#ifdef TORQUE_DEBUG
@ -117,7 +123,7 @@ void DynamicConsoleMethodComponent::injectMethodCall( const char* method )
}
#endif
const char* DynamicConsoleMethodComponent::callMethodArgList( U32 argc, const char *argv[], bool callThis /* = true */ )
const char* DynamicConsoleMethodComponent::callMethodArgList( U32 argc, ConsoleValueRef argv[], bool callThis /* = true */ )
{
#ifdef TORQUE_DEBUG
injectMethodCall( argv[0] );
@ -128,7 +134,7 @@ const char* DynamicConsoleMethodComponent::callMethodArgList( U32 argc, const ch
// Call all components that implement methodName giving them a chance to operate
// Components are called in reverse order of addition
const char *DynamicConsoleMethodComponent::_callMethod( U32 argc, const char *argv[], bool callThis /* = true */ )
const char *DynamicConsoleMethodComponent::_callMethod( U32 argc, ConsoleValueRef argv[], bool callThis /* = true */ )
{
// Set Owner
SimObject *pThis = dynamic_cast<SimObject *>( this );
@ -150,23 +156,42 @@ const char *DynamicConsoleMethodComponent::_callMethod( U32 argc, const char *ar
DynamicConsoleMethodComponent *pThisComponent = dynamic_cast<DynamicConsoleMethodComponent*>( pComponent );
AssertFatal( pThisComponent, "DynamicConsoleMethodComponent::callMethod - Non DynamicConsoleMethodComponent component attempting to callback!");
// Prevent stack corruption
STR.pushFrame();
CSTK.pushFrame();
// --
// Only call on first depth components
// Should isMethod check these calls? [11/22/2006 justind]
if(pComponent->isEnabled())
Con::execute( pThisComponent, argc, argv );
// Prevent stack corruption
STR.popFrame();
CSTK.popFrame();
// --
// Bail if this was the first element
//if( nItr == componentList.begin() )
// break;
}
unlockComponentList();
}
// Prevent stack corruption
STR.pushFrame();
CSTK.pushFrame();
// --
// Set Owner Field
const char* result = "";
if(callThis)
result = Con::execute( pThis, argc, argv, true ); // true - exec method onThisOnly, not on DCMCs
// Prevent stack corruption
STR.popFrame();
CSTK.popFrame();
// --
return result;
}

View file

@ -62,7 +62,7 @@ protected:
/// Internal callMethod : Actually does component notification and script method execution
/// @attention This method does some magic to the argc argv to make Con::execute act properly
/// as such it's internal and should not be exposed or used except by this class
virtual const char* _callMethod( U32 argc, const char *argv[], bool callThis = true );
virtual const char* _callMethod( U32 argc, ConsoleValueRef argv[], bool callThis = true );
public:
@ -75,7 +75,7 @@ public:
#endif
/// Call Method
virtual const char* callMethodArgList( U32 argc, const char *argv[], bool callThis = true );
virtual const char* callMethodArgList( U32 argc, ConsoleValueRef argv[], bool callThis = true );
/// Call Method format string
const char* callMethod( S32 argc, const char* methodName, ... );

View file

@ -21,7 +21,6 @@
//-----------------------------------------------------------------------------
#include "component/moreAdvancedComponent.h"
#include "unit/test.h"
// unitTest_runTests("Component/MoreAdvancedComponent");
@ -58,50 +57,4 @@ bool MoreAdvancedComponent::testDependentInterface()
return false;
return mSCInterface->isFortyTwo( 42 );
}
//////////////////////////////////////////////////////////////////////////
using namespace UnitTesting;
CreateUnitTest(MoreAdvancedComponentTest, "Component/MoreAdvancedComponent")
{
void run()
{
// Create component instances and compose them.
SimComponent *parentComponent = new SimComponent();
SimpleComponent *simpleComponent = new SimpleComponent();
MoreAdvancedComponent *moreAdvComponent = new MoreAdvancedComponent();
// CodeReview note that the interface pointer isn't initialized in a ctor
// on the components, so it's bad memory against which you might
// be checking in testDependentInterface [3/3/2007 justind]
parentComponent->addComponent( simpleComponent );
parentComponent->addComponent( moreAdvComponent );
simpleComponent->registerObject();
moreAdvComponent->registerObject();
// Put a break-point here, follow the onAdd call, and observe the order in
// which the SimComponent::onAdd function executes. You will see the interfaces
// get cached, and the dependent interface query being made.
parentComponent->registerObject();
// If the MoreAdvancedComponent found an interface, than the parentComponent
// should have returned true, from onAdd, and should therefore be registered
// properly with the Sim
test( parentComponent->isProperlyAdded(), "Parent component not properly added!" );
// Now lets test the interface. You can step through this, as well.
test( moreAdvComponent->testDependentInterface(), "Dependent interface test failed." );
// CodeReview is there a reason we can't just delete the parentComponent here? [3/3/2007 justind]
//
// Clean up
parentComponent->removeComponent( simpleComponent );
parentComponent->removeComponent( moreAdvComponent );
parentComponent->deleteObject();
moreAdvComponent->deleteObject();
simpleComponent->deleteObject();
}
};
}

View file

@ -171,7 +171,7 @@ void SimComponent::onRemove()
//////////////////////////////////////////////////////////////////////////
bool SimComponent::processArguments(S32 argc, const char **argv)
bool SimComponent::processArguments(S32 argc, ConsoleValueRef *argv)
{
for(S32 i = 0; i < argc; i++)
{
@ -179,7 +179,7 @@ bool SimComponent::processArguments(S32 argc, const char **argv)
if(obj)
addComponent(obj);
else
Con::printf("SimComponent::processArguments - Invalid Component Object \"%s\"", argv[i]);
Con::printf("SimComponent::processArguments - Invalid Component Object \"%s\"", (const char*)argv[i]);
}
return true;
}
@ -383,7 +383,7 @@ ConsoleMethod( SimComponent, addComponents, bool, 3, 64, "%obj.addComponents( %c
if(obj)
object->addComponent(obj);
else
Con::printf("SimComponent::addComponents - Invalid Component Object \"%s\"", argv[i]);
Con::printf("SimComponent::addComponents - Invalid Component Object \"%s\"", (const char*)argv[i]);
}
return true;
}
@ -399,7 +399,7 @@ ConsoleMethod( SimComponent, removeComponents, bool, 3, 64, "%obj.removeComponen
if(obj)
object->removeComponent(obj);
else
Con::printf("SimComponent::removeComponents - Invalid Component Object \"%s\"", argv[i]);
Con::printf("SimComponent::removeComponents - Invalid Component Object \"%s\"", (const char*)argv[i]);
}
return true;
}
@ -449,4 +449,4 @@ ConsoleMethod(SimComponent, getIsTemplate, bool, 2, 2, "() Check whether SimComp
"@return true if is a template and false if not")
{
return object->getIsTemplate();
}
}

View file

@ -150,7 +150,7 @@ public:
static void initPersistFields();
virtual bool processArguments(S32 argc, const char **argv);
virtual bool processArguments(S32 argc, ConsoleValueRef *argv);
bool isEnabled() const { return mEnabled; }

View file

@ -28,124 +28,4 @@ ConsoleDocClass( SimpleComponent,
"@brief The purpose of this component is to provide a minimalistic component that "
"exposes a simple, cached interface\n\n"
"Soon to be deprecated, internal only.\n\n "
"@internal");
//////////////////////////////////////////////////////////////////////////
// It may seem like some weak sauce to use a unit test for this, however
// it is very, very easy to set breakpoints in a unit test, and trace
// execution in the debugger, so I will use a unit test.
//
// Note I am not using much actual 'test' functionality, just providing
// an easy place to examine the functionality that was described and implemented
// in the header file.
//
// If you want to run this code, simply run Torque, pull down the console, and
// type:
// unitTest_runTests("Components/SimpleComponent");
#include "unit/test.h"
using namespace UnitTesting;
CreateUnitTest(TestSimpleComponent, "Components/SimpleComponent")
{
void run()
{
// When instantiating, and working with a SimObject in C++ code, such as
// a unit test, you *may not* allocate a SimObject off of the stack.
//
// For example:
// SimpleComponent sc;
// is a stack allocation. This memory is allocated off of the program stack
// when the function is called. SimObject deletion is done via SimObject::deleteObject()
// and the last command of this method is 'delete this;' That command will
// cause an assert if it is called on stack-allocated memory. Therefor, when
// instantiating SimObjects in C++ code, it is imperitive that you keep in
// mind that if any script calls 'delete()' on that SimObject, or any other
// C++ code calls 'deleteObject()' on that SimObject, it will crash.
SimpleComponent *sc = new SimpleComponent();
// SimObject::registerObject must be called on a SimObject before it is
// fully 'hooked in' to the engine.
//
// Tracing execution of this function will let you see onAdd get called on
// the component, and you will see it cache the interface we exposed.
sc->registerObject();
// It is *not* required that a component always be owned by a component (obviously)
// however I am using an owner so that you can trace execution of recursive
// calls to cache interfaces and such.
SimComponent *testOwner = new SimComponent();
// Add the test component to it's owner. This will set the 'mOwner' field
// of 'sc' to the address of 'testOwner'
testOwner->addComponent( sc );
// If you step-into this registerObject the same way as the previous one,
// you will be able to see the recursive caching of the exposed interface.
testOwner->registerObject();
// Now to prove that object composition is working properly, lets ask
// both of these components for their interface lists...
// The ComponentInterfaceList is a typedef for type 'VectorPtr<ComponentInterface *>'
// and it will be used by getInterfaces() to store the results of the interface
// query. This is the "complete" way to obtain an interface, and it is too
// heavy-weight for most cases. A simplified query will be performed next,
// to demonstrate the usage of both.
ComponentInterfaceList iLst;
// This query requests all interfaces, on all components, regardless of name
// or owner.
sc->getInterfaces( &iLst,
// This is the type field. I am passing NULL here to signify that the query
// should match all values of 'type' in the list.
NULL,
// The name field, let's pass NULL again just so when you trace execution
// you can see how queries work in the simple case, first.
NULL );
// Lets process the list that we've gotten back, and find the interface that
// we want.
SimpleComponentInterface *scQueriedInterface = NULL;
for( ComponentInterfaceListIterator i = iLst.begin(); i != iLst.end(); i++ )
{
scQueriedInterface = dynamic_cast<SimpleComponentInterface *>( *i );
if( scQueriedInterface != NULL )
break;
}
AssertFatal( scQueriedInterface != NULL, "No valid SimpleComponentInterface was found in query" );
// Lets do it again, only we will execute the query on the parent instead,
// in a simplified way. Remember the parent component doesn't expose any
// interfaces at all, so the success of this behavior is entirely dependent
// on the recursive registration that occurs in registerInterfaces()
SimpleComponentInterface *ownerQueriedInterface = testOwner->getInterface<SimpleComponentInterface>();
AssertFatal( ownerQueriedInterface != NULL, "No valid SimpleComponentInterface was found in query" );
// We should now have two pointers to the same interface obtained by querying
// different components.
test( ownerQueriedInterface == scQueriedInterface, "This really shouldn't be possible to fail given the setup of the test" );
// Lets call the method that was exposed on the component via the interface.
// Trace the execution of this function, if you wish.
test( ownerQueriedInterface->isFortyTwo( 42 ), "Don't panic, but it's a bad day in the component system." );
test( scQueriedInterface->isFortyTwo( 42 ), "Don't panic, but it's a bad day in the component system." );
// So there you have it. Writing a simple component that exposes a cached
// interface, and testing it. It's time to clean up.
testOwner->removeComponent( sc );
sc->deleteObject();
testOwner->deleteObject();
// Interfaces do not need to be freed. In Juggernaught, these will be ref-counted
// for more robust behavior. Right now, however, the values of our two interface
// pointers, scQueriedInterface and ownerQueriedInterface, reference invalid
// memory.
}
};
"@internal");

View file

@ -0,0 +1,68 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifdef TORQUE_TESTS_ENABLED
#include "testing/unitTesting.h"
#include "component/moreAdvancedComponent.h"
TEST(MoreAdvancedComponent, MoreAdvancedComponent)
{
// Create component instances and compose them.
SimComponent *parentComponent = new SimComponent();
SimpleComponent *simpleComponent = new SimpleComponent();
MoreAdvancedComponent *moreAdvComponent = new MoreAdvancedComponent();
// CodeReview note that the interface pointer isn't initialized in a ctor
// on the components, so it's bad memory against which you might
// be checking in testDependentInterface [3/3/2007 justind]
parentComponent->addComponent( simpleComponent );
parentComponent->addComponent( moreAdvComponent );
simpleComponent->registerObject();
moreAdvComponent->registerObject();
// Put a break-point here, follow the onAdd call, and observe the order in
// which the SimComponent::onAdd function executes. You will see the interfaces
// get cached, and the dependent interface query being made.
parentComponent->registerObject();
// If the MoreAdvancedComponent found an interface, than the parentComponent
// should have returned true, from onAdd, and should therefore be registered
// properly with the Sim
EXPECT_TRUE( parentComponent->isProperlyAdded() )
<< "Parent component not properly added!";
// Now lets test the interface. You can step through this, as well.
EXPECT_TRUE( moreAdvComponent->testDependentInterface() )
<< "Dependent interface test failed.";
// CodeReview is there a reason we can't just delete the parentComponent here? [3/3/2007 justind]
//
// Clean up
parentComponent->removeComponent( simpleComponent );
parentComponent->removeComponent( moreAdvComponent );
parentComponent->deleteObject();
moreAdvComponent->deleteObject();
simpleComponent->deleteObject();
};
#endif

View file

@ -1,5 +1,5 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
// Copyright (c) 2014 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
@ -20,14 +20,10 @@
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "unit/test.h"
#include "unit/memoryTester.h"
#ifdef TORQUE_TESTS_ENABLED
#include "testing/unitTesting.h"
#include "component/simComponent.h"
using namespace UnitTesting;
//////////////////////////////////////////////////////////////////////////
class CachedInterfaceExampleComponent : public SimComponent
{
typedef SimComponent Parent;
@ -51,10 +47,10 @@ public:
public:
//////////////////////////////////////////////////////////////////////////
virtual void registerInterfaces( const SimComponent *owner )
virtual void registerInterfaces( SimComponent *owner )
{
// Register a cached interface for this
registerCachedInterface( NULL, "aU32", this, &mMyId );
owner->registerCachedInterface( NULL, "aU32", this, &mMyId );
}
//////////////////////////////////////////////////////////////////////////
@ -70,7 +66,7 @@ public:
ComponentInterfaceList list;
// Enumerate the interfaces on the owner, only ignore interfaces that this object owns
if( !_getOwner()->getInterfaces( &list, NULL, "aU32", this, true ) )
if( !owner->getInterfaces( &list, NULL, "aU32", this, true ) )
return false;
// Sanity check before just assigning all willy-nilly
@ -89,11 +85,17 @@ public:
// CodeReview [patw, 2, 17, 2007] I'm going to make another lightweight interface
// for this functionality later
void unit_test( UnitTest *test )
void unit_test()
{
test->test( mpU32 != NULL, "Pointer to dependent interface is NULL" );
test->test( *(*mpU32) & ( 1 << 24 ), "Pointer to interface data is bogus." );
test->test( *(*mpU32) != *mMyId, "Two of me have the same ID, bad!" );
EXPECT_TRUE( mpU32 != NULL )
<< "Pointer to dependent interface is NULL";
if( mpU32 )
{
EXPECT_TRUE( *(*mpU32) & ( 1 << 24 ) )
<< "Pointer to interface data is bogus.";
EXPECT_TRUE( *(*mpU32) != *mMyId )
<< "Two of me have the same ID, bad!";
}
}
};
@ -105,39 +107,43 @@ ConsoleDocClass( CachedInterfaceExampleComponent,
"Not intended for game development, for editors or internal use only.\n\n "
"@internal");
//////////////////////////////////////////////////////////////////////////
CreateUnitTest(TestComponentInterfacing, "Components/Composition")
TEST(SimComponent, Composition)
{
void run()
SimComponent *testComponent = new SimComponent();
CachedInterfaceExampleComponent *componentA = new CachedInterfaceExampleComponent();
CachedInterfaceExampleComponent *componentB = new CachedInterfaceExampleComponent();
// Register sub-components
EXPECT_TRUE( componentA->registerObject() )
<< "Failed to register componentA";
EXPECT_TRUE( componentB->registerObject() )
<< "Failed to register componentB";
// Add the components
EXPECT_TRUE( testComponent->addComponent( componentA ) )
<< "Failed to add component a to testComponent";
EXPECT_TRUE( testComponent->addComponent( componentB ) )
<< "Failed to add component b to testComponent";
EXPECT_EQ( componentA->getOwner(), testComponent )
<< "testComponent did not properly set the mOwner field of componentA to NULL.";
EXPECT_EQ( componentB->getOwner(), testComponent )
<< "testComponent did not properly set the mOwner field of componentB to NULL.";
// Register the object with the simulation, kicking off the interface registration
ASSERT_TRUE( testComponent->registerObject() )
<< "Failed to register testComponent";
{
MemoryTester m;
m.mark();
SimComponent *testComponent = new SimComponent();
CachedInterfaceExampleComponent *componentA = new CachedInterfaceExampleComponent();
CachedInterfaceExampleComponent *componentB = new CachedInterfaceExampleComponent();
// Register sub-components
test( componentA->registerObject(), "Failed to register componentA" );
test( componentB->registerObject(), "Failed to register componentB" );
// Add the components
test( testComponent->addComponent( componentA ), "Failed to add component a to testComponent" );
test( testComponent->addComponent( componentB ), "Failed to add component b to testComponent" );
test( componentA->getOwner() == testComponent, "testComponent did not properly set the mOwner field of componentA to NULL." );
test( componentB->getOwner() == testComponent, "testComponent did not properly set the mOwner field of componentB to NULL." );
// Register the object with the simulation, kicking off the interface registration
test( testComponent->registerObject(), "Failed to register testComponent" );
// Interface tests
componentA->unit_test( this );
componentB->unit_test( this );
testComponent->deleteObject();
test( m.check(), "Component composition test leaked memory." );
SCOPED_TRACE("componentA");
componentA->unit_test();
}
};
{
SCOPED_TRACE("componentB");
componentB->unit_test();
}
testComponent->deleteObject();
};
#endif

View file

@ -0,0 +1,131 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2014 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifdef TORQUE_TESTS_ENABLED
#include "testing/unitTesting.h"
#include "component/simpleComponent.h"
TEST(SimpleComponent, SimpleComponent)
{
// When instantiating, and working with a SimObject in C++ code, such as
// a unit test, you *may not* allocate a SimObject off of the stack.
//
// For example:
// SimpleComponent sc;
// is a stack allocation. This memory is allocated off of the program stack
// when the function is called. SimObject deletion is done via SimObject::deleteObject()
// and the last command of this method is 'delete this;' That command will
// cause an assert if it is called on stack-allocated memory. Therefor, when
// instantiating SimObjects in C++ code, it is imperitive that you keep in
// mind that if any script calls 'delete()' on that SimObject, or any other
// C++ code calls 'deleteObject()' on that SimObject, it will crash.
SimpleComponent *sc = new SimpleComponent();
// SimObject::registerObject must be called on a SimObject before it is
// fully 'hooked in' to the engine.
//
// Tracing execution of this function will let you see onAdd get called on
// the component, and you will see it cache the interface we exposed.
sc->registerObject();
// It is *not* required that a component always be owned by a component (obviously)
// however I am using an owner so that you can trace execution of recursive
// calls to cache interfaces and such.
SimComponent *testOwner = new SimComponent();
// Add the test component to it's owner. This will set the 'mOwner' field
// of 'sc' to the address of 'testOwner'
testOwner->addComponent( sc );
// If you step-into this registerObject the same way as the previous one,
// you will be able to see the recursive caching of the exposed interface.
testOwner->registerObject();
// Now to prove that object composition is working properly, lets ask
// both of these components for their interface lists...
// The ComponentInterfaceList is a typedef for type 'VectorPtr<ComponentInterface *>'
// and it will be used by getInterfaces() to store the results of the interface
// query. This is the "complete" way to obtain an interface, and it is too
// heavy-weight for most cases. A simplified query will be performed next,
// to demonstrate the usage of both.
ComponentInterfaceList iLst;
// This query requests all interfaces, on all components, regardless of name
// or owner.
sc->getInterfaces( &iLst,
// This is the type field. I am passing NULL here to signify that the query
// should match all values of 'type' in the list.
NULL,
// The name field, let's pass NULL again just so when you trace execution
// you can see how queries work in the simple case, first.
NULL );
// Lets process the list that we've gotten back, and find the interface that
// we want.
SimpleComponentInterface *scQueriedInterface = NULL;
for( ComponentInterfaceListIterator i = iLst.begin(); i != iLst.end(); i++ )
{
scQueriedInterface = dynamic_cast<SimpleComponentInterface *>( *i );
if( scQueriedInterface != NULL )
break;
}
AssertFatal( scQueriedInterface != NULL, "No valid SimpleComponentInterface was found in query" );
// Lets do it again, only we will execute the query on the parent instead,
// in a simplified way. Remember the parent component doesn't expose any
// interfaces at all, so the success of this behavior is entirely dependent
// on the recursive registration that occurs in registerInterfaces()
SimpleComponentInterface *ownerQueriedInterface = testOwner->getInterface<SimpleComponentInterface>();
AssertFatal( ownerQueriedInterface != NULL, "No valid SimpleComponentInterface was found in query" );
// We should now have two pointers to the same interface obtained by querying
// different components.
EXPECT_EQ( ownerQueriedInterface, scQueriedInterface )
<< "This really shouldn't be possible to fail given the setup of the test";
// Lets call the method that was exposed on the component via the interface.
// Trace the execution of this function, if you wish.
EXPECT_TRUE( ownerQueriedInterface->isFortyTwo( 42 ) )
<< "Don't panic, but it's a bad day in the component system.";
EXPECT_TRUE( scQueriedInterface->isFortyTwo( 42 ) )
<< "Don't panic, but it's a bad day in the component system.";
// So there you have it. Writing a simple component that exposes a cached
// interface, and testing it. It's time to clean up.
testOwner->removeComponent( sc );
sc->deleteObject();
testOwner->deleteObject();
// Interfaces do not need to be freed. In Juggernaught, these will be ref-counted
// for more robust behavior. Right now, however, the values of our two interface
// pointers, scQueriedInterface and ownerQueriedInterface, reference invalid
// memory.
};
#endif

View file

@ -27,7 +27,7 @@ class ICallMethod
{
public:
virtual const char* callMethod( S32 argc, const char* methodName, ... ) = 0;
virtual const char* callMethodArgList( U32 argc, const char *argv[], bool callThis = true ) = 0;
virtual const char* callMethodArgList( U32 argc, ConsoleValueRef argv[], bool callThis = true ) = 0;
};
#endif

View file

@ -158,7 +158,7 @@ SimXMLDocument::~SimXMLDocument()
// -----------------------------------------------------------------------------
// Included for completeness.
// -----------------------------------------------------------------------------
bool SimXMLDocument::processArguments(S32 argc, const char** argv)
bool SimXMLDocument::processArguments(S32 argc, ConsoleValueRef *argv)
{
return argc == 0;
}

View file

@ -57,7 +57,7 @@ class SimXMLDocument: public SimObject
// tie in to the script language. The .cc file has more in depth
// comments on these.
//-----------------------------------------------------------------------
bool processArguments(S32 argc, const char** argv);
bool processArguments(S32 argc, ConsoleValueRef *argv);
bool onAdd();
void onRemove();
static void initPersistFields();

View file

@ -103,10 +103,7 @@ S32 QSORT_CALLBACK ArrayObject::_keyFunctionCompare( const void* a, const void*
ArrayObject::Element* ea = ( ArrayObject::Element* )( a );
ArrayObject::Element* eb = ( ArrayObject::Element* )( b );
const char* argv[ 3 ];
argv[ 0 ] = smCompareFunction;
argv[ 1 ] = ea->key;
argv[ 2 ] = eb->key;
ConsoleValueRef argv[] = { smCompareFunction, ea->key, eb->key };
S32 result = dAtoi( Con::execute( 3, argv ) );
S32 res = result < 0 ? -1 : ( result > 0 ? 1 : 0 );
@ -118,10 +115,7 @@ S32 QSORT_CALLBACK ArrayObject::_valueFunctionCompare( const void* a, const void
ArrayObject::Element* ea = ( ArrayObject::Element* )( a );
ArrayObject::Element* eb = ( ArrayObject::Element* )( b );
const char* argv[ 3 ];
argv[ 0 ] = smCompareFunction;
argv[ 1 ] = ea->value;
argv[ 2 ] = eb->value;
ConsoleValueRef argv[] = { smCompareFunction, ea->value, eb->value };
S32 result = dAtoi( Con::execute( 3, argv ) );
S32 res = result < 0 ? -1 : ( result > 0 ? 1 : 0 );

View file

@ -27,6 +27,7 @@ class ExprEvalState;
class Namespace;
class SimObject;
class SimGroup;
class CodeStream;
/// Enable this #define if you are seeing the message "precompile size mismatch" in the console.
/// This will help track down which node type is causing the error. It could be
@ -38,7 +39,8 @@ enum TypeReq
TypeReqNone,
TypeReqUInt,
TypeReqFloat,
TypeReqString
TypeReqString,
TypeReqVar
};
/// Representation of a node for the scripting language parser.
@ -77,15 +79,13 @@ struct StmtNode
/// @name Breaking
/// @{
void addBreakCount();
void addBreakLine(U32 ip);
void addBreakLine(CodeStream &codeStream);
/// @}
/// @name Compilation
/// @{
virtual U32 precompileStmt(U32 loopCount) = 0;
virtual U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint) = 0;
virtual U32 compileStmt(CodeStream &codeStream, U32 ip) = 0;
virtual void setPackage(StringTableEntry packageName);
/// @}
};
@ -101,27 +101,26 @@ struct BreakStmtNode : StmtNode
{
static BreakStmtNode *alloc( S32 lineNumber );
U32 precompileStmt(U32 loopCount);
U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint);
U32 compileStmt(CodeStream &codeStream, U32 ip);
DBG_STMT_TYPE(BreakStmtNode);
};
struct ContinueStmtNode : StmtNode
{
static ContinueStmtNode *alloc( S32 lineNumber );
U32 precompileStmt(U32 loopCount);
U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint);
U32 compileStmt(CodeStream &codeStream, U32 ip);
DBG_STMT_TYPE(ContinueStmtNode);
};
/// A mathematical expression.
struct ExprNode : StmtNode
{
U32 precompileStmt(U32 loopCount);
U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint);
U32 compileStmt(CodeStream &codeStream, U32 ip);
virtual U32 precompile(TypeReq type) = 0;
virtual U32 compile(U32 *codeStream, U32 ip, TypeReq type) = 0;
virtual U32 compile(CodeStream &codeStream, U32 ip, TypeReq type) = 0;
virtual TypeReq getPreferredType() = 0;
};
@ -130,8 +129,8 @@ struct ReturnStmtNode : StmtNode
ExprNode *expr;
static ReturnStmtNode *alloc( S32 lineNumber, ExprNode *expr );
U32 precompileStmt(U32 loopCount);
U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint);
U32 compileStmt(CodeStream &codeStream, U32 ip);
DBG_STMT_TYPE(ReturnStmtNode);
};
@ -147,8 +146,8 @@ struct IfStmtNode : StmtNode
static IfStmtNode *alloc( S32 lineNumber, ExprNode *testExpr, StmtNode *ifBlock, StmtNode *elseBlock, bool propagateThrough );
void propagateSwitchExpr(ExprNode *left, bool string);
ExprNode *getSwitchOR(ExprNode *left, ExprNode *list, bool string);
U32 precompileStmt(U32 loopCount);
U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint);
U32 compileStmt(CodeStream &codeStream, U32 ip);
DBG_STMT_TYPE(IfStmtNode);
};
@ -165,8 +164,8 @@ struct LoopStmtNode : StmtNode
bool integer;
static LoopStmtNode *alloc( S32 lineNumber, ExprNode *testExpr, ExprNode *initExpr, ExprNode *endLoopExpr, StmtNode *loopBlock, bool isDoLoop );
U32 precompileStmt(U32 loopCount);
U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint);
U32 compileStmt(CodeStream &codeStream, U32 ip);
DBG_STMT_TYPE(LoopStmtNode);
};
@ -190,8 +189,7 @@ struct IterStmtNode : StmtNode
static IterStmtNode* alloc( S32 lineNumber, StringTableEntry varName, ExprNode* containerExpr, StmtNode* body, bool isStringIter );
U32 precompileStmt( U32 loopCount );
U32 compileStmt( U32* codeStream, U32 ip, U32 continuePoint, U32 breakPoint );
U32 compileStmt( CodeStream &codeStream, U32 ip );
};
/// A binary mathematical expression (ie, left op right).
@ -205,8 +203,8 @@ struct BinaryExprNode : ExprNode
struct FloatBinaryExprNode : BinaryExprNode
{
static FloatBinaryExprNode *alloc( S32 lineNumber, S32 op, ExprNode *left, ExprNode *right );
U32 precompile(TypeReq type);
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
TypeReq getPreferredType();
DBG_STMT_TYPE(FloatBinaryExprNode);
};
@ -218,8 +216,8 @@ struct ConditionalExprNode : ExprNode
ExprNode *falseExpr;
bool integer;
static ConditionalExprNode *alloc( S32 lineNumber, ExprNode *testExpr, ExprNode *trueExpr, ExprNode *falseExpr );
virtual U32 precompile(TypeReq type);
virtual U32 compile(U32 *codeStream, U32 ip, TypeReq type);
virtual U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
virtual TypeReq getPreferredType();
DBG_STMT_TYPE(ConditionalExprNode);
};
@ -232,8 +230,8 @@ struct IntBinaryExprNode : BinaryExprNode
static IntBinaryExprNode *alloc( S32 lineNumber, S32 op, ExprNode *left, ExprNode *right );
void getSubTypeOperand();
U32 precompile(TypeReq type);
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
TypeReq getPreferredType();
DBG_STMT_TYPE(IntBinaryExprNode);
};
@ -242,8 +240,8 @@ struct StreqExprNode : BinaryExprNode
{
bool eq;
static StreqExprNode *alloc( S32 lineNumber, ExprNode *left, ExprNode *right, bool eq );
U32 precompile(TypeReq type);
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
TypeReq getPreferredType();
DBG_STMT_TYPE(StreqExprNode);
};
@ -252,8 +250,8 @@ struct StrcatExprNode : BinaryExprNode
{
S32 appendChar;
static StrcatExprNode *alloc( S32 lineNumber, ExprNode *left, ExprNode *right, S32 appendChar );
U32 precompile(TypeReq type);
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
TypeReq getPreferredType();
DBG_STMT_TYPE(StrcatExprNode);
};
@ -262,8 +260,8 @@ struct CommaCatExprNode : BinaryExprNode
{
static CommaCatExprNode *alloc( S32 lineNumber, ExprNode *left, ExprNode *right );
U32 precompile(TypeReq type);
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
TypeReq getPreferredType();
DBG_STMT_TYPE(CommaCatExprNode);
};
@ -275,8 +273,8 @@ struct IntUnaryExprNode : ExprNode
bool integer;
static IntUnaryExprNode *alloc( S32 lineNumber, S32 op, ExprNode *expr );
U32 precompile(TypeReq type);
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
TypeReq getPreferredType();
DBG_STMT_TYPE(IntUnaryExprNode);
};
@ -287,8 +285,8 @@ struct FloatUnaryExprNode : ExprNode
ExprNode *expr;
static FloatUnaryExprNode *alloc( S32 lineNumber, S32 op, ExprNode *expr );
U32 precompile(TypeReq type);
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
TypeReq getPreferredType();
DBG_STMT_TYPE(FloatUnaryExprNode);
};
@ -299,8 +297,8 @@ struct VarNode : ExprNode
ExprNode *arrayIndex;
static VarNode *alloc( S32 lineNumber, StringTableEntry varName, ExprNode *arrayIndex );
U32 precompile(TypeReq type);
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
TypeReq getPreferredType();
DBG_STMT_TYPE(VarNode);
};
@ -311,8 +309,8 @@ struct IntNode : ExprNode
U32 index; // if it's converted to float/string
static IntNode *alloc( S32 lineNumber, S32 value );
U32 precompile(TypeReq type);
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
TypeReq getPreferredType();
DBG_STMT_TYPE(IntNode);
};
@ -323,8 +321,8 @@ struct FloatNode : ExprNode
U32 index;
static FloatNode *alloc( S32 lineNumber, F64 value );
U32 precompile(TypeReq type);
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
TypeReq getPreferredType();
DBG_STMT_TYPE(FloatNode);
};
@ -338,8 +336,8 @@ struct StrConstNode : ExprNode
bool doc; // Specifies that this string is a documentation block.
static StrConstNode *alloc( S32 lineNumber, char *str, bool tag, bool doc = false );
U32 precompile(TypeReq type);
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
TypeReq getPreferredType();
DBG_STMT_TYPE(StrConstNode);
};
@ -351,8 +349,8 @@ struct ConstantNode : ExprNode
U32 index;
static ConstantNode *alloc( S32 lineNumber, StringTableEntry value );
U32 precompile(TypeReq type);
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
TypeReq getPreferredType();
DBG_STMT_TYPE(ConstantNode);
};
@ -365,8 +363,8 @@ struct AssignExprNode : ExprNode
TypeReq subType;
static AssignExprNode *alloc( S32 lineNumber, StringTableEntry varName, ExprNode *arrayIndex, ExprNode *expr );
U32 precompile(TypeReq type);
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
TypeReq getPreferredType();
DBG_STMT_TYPE(AssignExprNode);
};
@ -389,8 +387,8 @@ struct AssignOpExprNode : ExprNode
TypeReq subType;
static AssignOpExprNode *alloc( S32 lineNumber, StringTableEntry varName, ExprNode *arrayIndex, ExprNode *expr, S32 op );
U32 precompile(TypeReq type);
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
TypeReq getPreferredType();
DBG_STMT_TYPE(AssignOpExprNode);
};
@ -402,8 +400,8 @@ struct TTagSetStmtNode : StmtNode
ExprNode *stringExpr;
static TTagSetStmtNode *alloc( S32 lineNumber, StringTableEntry tag, ExprNode *valueExpr, ExprNode *stringExpr );
U32 precompileStmt(U32 loopCount);
U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint);
U32 compileStmt(CodeStream &codeStream, U32 ip);
DBG_STMT_TYPE(TTagSetStmtNode);
};
@ -412,8 +410,8 @@ struct TTagDerefNode : ExprNode
ExprNode *expr;
static TTagDerefNode *alloc( S32 lineNumber, ExprNode *expr );
U32 precompile(TypeReq type);
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
TypeReq getPreferredType();
DBG_STMT_TYPE(TTagDerefNode);
};
@ -423,8 +421,8 @@ struct TTagExprNode : ExprNode
StringTableEntry tag;
static TTagExprNode *alloc( S32 lineNumber, StringTableEntry tag );
U32 precompile(TypeReq type);
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
TypeReq getPreferredType();
DBG_STMT_TYPE(TTagExprNode);
};
@ -442,8 +440,8 @@ struct FuncCallExprNode : ExprNode
};
static FuncCallExprNode *alloc( S32 lineNumber, StringTableEntry funcName, StringTableEntry nameSpace, ExprNode *args, bool dot );
U32 precompile(TypeReq type);
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
TypeReq getPreferredType();
DBG_STMT_TYPE(FuncCallExprNode);
};
@ -455,8 +453,8 @@ struct AssertCallExprNode : ExprNode
U32 messageIndex;
static AssertCallExprNode *alloc( S32 lineNumber, ExprNode *testExpr, const char *message );
U32 precompile(TypeReq type);
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
TypeReq getPreferredType();
DBG_STMT_TYPE(AssertCallExprNode);
};
@ -475,8 +473,8 @@ struct SlotAccessNode : ExprNode
StringTableEntry slotName;
static SlotAccessNode *alloc( S32 lineNumber, ExprNode *objectExpr, ExprNode *arrayExpr, StringTableEntry slotName );
U32 precompile(TypeReq type);
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
TypeReq getPreferredType();
DBG_STMT_TYPE(SlotAccessNode);
};
@ -495,8 +493,8 @@ struct InternalSlotAccessNode : ExprNode
bool recurse;
static InternalSlotAccessNode *alloc( S32 lineNumber, ExprNode *objectExpr, ExprNode *slotExpr, bool recurse );
U32 precompile(TypeReq type);
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
TypeReq getPreferredType();
DBG_STMT_TYPE(InternalSlotAccessNode);
};
@ -509,8 +507,8 @@ struct SlotAssignNode : ExprNode
U32 typeID;
static SlotAssignNode *alloc( S32 lineNumber, ExprNode *objectExpr, ExprNode *arrayExpr, StringTableEntry slotName, ExprNode *valueExpr, U32 typeID = -1 );
U32 precompile(TypeReq type);
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
TypeReq getPreferredType();
DBG_STMT_TYPE(SlotAssignNode);
};
@ -525,8 +523,8 @@ struct SlotAssignOpNode : ExprNode
TypeReq subType;
static SlotAssignOpNode *alloc( S32 lineNumber, ExprNode *objectExpr, StringTableEntry slotName, ExprNode *arrayExpr, S32 op, ExprNode *valueExpr );
U32 precompile(TypeReq type);
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
TypeReq getPreferredType();
DBG_STMT_TYPE(SlotAssignOpNode);
};
@ -545,10 +543,10 @@ struct ObjectDeclNode : ExprNode
bool isSingleton;
static ObjectDeclNode *alloc( S32 lineNumber, ExprNode *classNameExpr, ExprNode *objectNameExpr, ExprNode *argList, StringTableEntry parentObject, SlotAssignNode *slotDecls, ObjectDeclNode *subObjects, bool isDatablock, bool classNameInternal, bool isSingleton );
U32 precompile(TypeReq type);
U32 precompileSubObject(bool);
U32 compile(U32 *codeStream, U32 ip, TypeReq type);
U32 compileSubObject(U32 *codeStream, U32 ip, bool);
U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
U32 compileSubObject(CodeStream &codeStream, U32 ip, bool);
TypeReq getPreferredType();
DBG_STMT_TYPE(ObjectDeclNode);
};
@ -570,18 +568,13 @@ struct FunctionDeclStmtNode : StmtNode
U32 argc;
static FunctionDeclStmtNode *alloc( S32 lineNumber, StringTableEntry fnName, StringTableEntry nameSpace, VarNode *args, StmtNode *stmts );
U32 precompileStmt(U32 loopCount);
U32 compileStmt(U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint);
U32 compileStmt(CodeStream &codeStream, U32 ip);
void setPackage(StringTableEntry packageName);
DBG_STMT_TYPE(FunctionDeclStmtNode);
};
extern StmtNode *gStatementList;
extern void createFunction(const char *fnName, VarNode *args, StmtNode *statements);
extern ExprEvalState gEvalState;
extern bool lookupFunction(const char *fnName, VarNode **args, StmtNode **statements);
typedef const char *(*cfunc)(S32 argc, char **argv);
extern bool lookupCFunction(const char *fnName, cfunc *f);
extern ExprEvalState gEvalState;;
#endif

File diff suppressed because it is too large Load diff

View file

@ -33,7 +33,6 @@
using namespace Compiler;
bool CodeBlock::smInFunction = false;
U32 CodeBlock::smBreakLineCount = 0;
CodeBlock * CodeBlock::smCodeBlockList = NULL;
CodeBlock * CodeBlock::smCurrentCodeBlock = NULL;
ConsoleParser *CodeBlock::smCurrentParser = NULL;
@ -403,14 +402,14 @@ bool CodeBlock::read(StringTableEntry fileName, Stream &st)
for(U32 i = 0; i < size; i++)
st.read(&mFunctionFloats[i]);
}
U32 codeSize;
st.read(&codeSize);
U32 codeLength;
st.read(&codeLength);
st.read(&mLineBreakPairCount);
U32 totSize = codeSize + mLineBreakPairCount * 2;
U32 totSize = codeLength + mLineBreakPairCount * 2;
mCode = new U32[totSize];
for(i = 0; i < codeSize; i++)
for(i = 0; i < codeLength; i++)
{
U8 b;
st.read(&b);
@ -420,10 +419,10 @@ bool CodeBlock::read(StringTableEntry fileName, Stream &st)
mCode[i] = b;
}
for(i = codeSize; i < totSize; i++)
for(i = codeLength; i < totSize; i++)
st.read(&mCode[i]);
mLineBreakPairs = mCode + codeSize;
mLineBreakPairs = mCode + codeLength;
// StringTable-ize our identifiers.
U32 identCount;
@ -456,6 +455,8 @@ bool CodeBlock::read(StringTableEntry fileName, Stream &st)
bool CodeBlock::compile(const char *codeFileName, StringTableEntry fileName, const char *inScript, bool overrideNoDso)
{
AssertFatal(Con::isMainThread(), "Compiling code on a secondary thread");
// This will return true, but return value is ignored
char *script;
chompUTF8BOM( inScript, &script );
@ -464,7 +465,7 @@ bool CodeBlock::compile(const char *codeFileName, StringTableEntry fileName, con
consoleAllocReset();
STEtoU32 = compileSTEtoU32;
STEtoCode = compileSTEtoCode;
gStatementList = NULL;
@ -497,17 +498,23 @@ bool CodeBlock::compile(const char *codeFileName, StringTableEntry fileName, con
resetTables();
smInFunction = false;
smBreakLineCount = 0;
setBreakCodeBlock(this);
CodeStream codeStream;
U32 lastIp;
if(gStatementList)
mCodeSize = precompileBlock(gStatementList, 0) + 1;
{
lastIp = compileBlock(gStatementList, codeStream, 0) + 1;
}
else
{
mCodeSize = 1;
mLineBreakPairCount = smBreakLineCount;
mCode = new U32[mCodeSize + smBreakLineCount * 2];
mLineBreakPairs = mCode + mCodeSize;
lastIp = 0;
}
codeStream.emit(OP_RETURN);
codeStream.emitCodeStream(&mCodeSize, &mCode, &mLineBreakPairs);
mLineBreakPairCount = codeStream.getNumLineBreaks();
// Write string table data...
getGlobalStringTable().write(st);
@ -517,18 +524,10 @@ bool CodeBlock::compile(const char *codeFileName, StringTableEntry fileName, con
getGlobalFloatTable().write(st);
getFunctionFloatTable().write(st);
smBreakLineCount = 0;
U32 lastIp;
if(gStatementList)
lastIp = compileBlock(gStatementList, mCode, 0, 0, 0);
else
lastIp = 0;
if(lastIp != mCodeSize - 1)
if(lastIp != mCodeSize)
Con::errorf(ConsoleLogEntry::General, "CodeBlock::compile - precompile size mismatch, a precompile/compile function pair is probably mismatched.");
mCode[lastIp++] = OP_RETURN;
U32 totSize = mCodeSize + smBreakLineCount * 2;
U32 totSize = mCodeSize + codeStream.getNumLineBreaks() * 2;
st.write(mCodeSize);
st.write(mLineBreakPairCount);
@ -561,11 +560,13 @@ bool CodeBlock::compile(const char *codeFileName, StringTableEntry fileName, con
const char *CodeBlock::compileExec(StringTableEntry fileName, const char *inString, bool noCalls, S32 setFrame)
{
AssertFatal(Con::isMainThread(), "Compiling code on a secondary thread");
// Check for a UTF8 script file
char *string;
chompUTF8BOM( inString, &string );
STEtoU32 = evalSTEtoU32;
STEtoCode = evalSTEtoCode;
consoleAllocReset();
mName = fileName;
@ -617,12 +618,11 @@ const char *CodeBlock::compileExec(StringTableEntry fileName, const char *inStri
resetTables();
smInFunction = false;
smBreakLineCount = 0;
setBreakCodeBlock(this);
CodeStream codeStream;
U32 lastIp = compileBlock(gStatementList, codeStream, 0);
mCodeSize = precompileBlock(gStatementList, 0) + 1;
mLineBreakPairCount = smBreakLineCount;
mLineBreakPairCount = codeStream.getNumLineBreaks();
mGlobalStrings = getGlobalStringTable().build();
mGlobalStringsMaxLen = getGlobalStringTable().totalLen;
@ -632,20 +632,18 @@ const char *CodeBlock::compileExec(StringTableEntry fileName, const char *inStri
mGlobalFloats = getGlobalFloatTable().build();
mFunctionFloats = getFunctionFloatTable().build();
mCode = new U32[mCodeSize + mLineBreakPairCount * 2];
mLineBreakPairs = mCode + mCodeSize;
smBreakLineCount = 0;
U32 lastIp = compileBlock(gStatementList, mCode, 0, 0, 0);
mCode[lastIp++] = OP_RETURN;
codeStream.emit(OP_RETURN);
codeStream.emitCodeStream(&mCodeSize, &mCode, &mLineBreakPairs);
//dumpInstructions(0, false);
consoleAllocReset();
if(mLineBreakPairCount && fileName)
calcBreakList();
if(lastIp != mCodeSize)
if(lastIp+1 != mCodeSize)
Con::warnf(ConsoleLogEntry::General, "precompile size mismatch, precompile: %d compile: %d", mCodeSize, lastIp);
return exec(0, fileName, NULL, 0, 0, noCalls, NULL, setFrame);
@ -674,7 +672,7 @@ String CodeBlock::getFunctionArgs( U32 ip )
U32 fnArgc = mCode[ ip + 5 ];
for( U32 i = 0; i < fnArgc; ++ i )
{
StringTableEntry var = U32toSTE( mCode[ ip + i + 6 ] );
StringTableEntry var = CodeToSTE(mCode, ip + (i*2) + 6);
if( i != 0 )
str.append( ", " );
@ -696,41 +694,52 @@ String CodeBlock::getFunctionArgs( U32 ip )
void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
{
U32 ip = startIp;
smInFunction = false;
U32 endFuncIp = 0;
while( ip < mCodeSize )
{
if (ip > endFuncIp)
{
smInFunction = false;
}
switch( mCode[ ip ++ ] )
{
case OP_FUNC_DECL:
{
StringTableEntry fnName = U32toSTE(mCode[ip]);
StringTableEntry fnNamespace = U32toSTE(mCode[ip+1]);
StringTableEntry fnPackage = U32toSTE(mCode[ip+2]);
bool hasBody = bool(mCode[ip+3]);
U32 newIp = mCode[ ip + 4 ];
U32 argc = mCode[ ip + 5 ];
StringTableEntry fnName = CodeToSTE(mCode, ip);
StringTableEntry fnNamespace = CodeToSTE(mCode, ip+2);
StringTableEntry fnPackage = CodeToSTE(mCode, ip+4);
bool hasBody = bool(mCode[ip+6]);
U32 newIp = mCode[ ip + 7 ];
U32 argc = mCode[ ip + 8 ];
endFuncIp = newIp;
Con::printf( "%i: OP_FUNC_DECL name=%s nspace=%s package=%s hasbody=%i newip=%i argc=%i",
ip - 1, fnName, fnNamespace, fnPackage, hasBody, newIp, argc );
// Skip args.
ip += 6 + argc;
ip += 9 + (argc * 2);
smInFunction = true;
break;
}
case OP_CREATE_OBJECT:
{
StringTableEntry objParent = U32toSTE(mCode[ip ]);
bool isDataBlock = mCode[ip + 1];
bool isInternal = mCode[ip + 2];
bool isSingleton = mCode[ip + 3];
U32 lineNumber = mCode[ip + 4];
U32 failJump = mCode[ip + 5];
StringTableEntry objParent = CodeToSTE(mCode, ip);
bool isDataBlock = mCode[ip + 2];
bool isInternal = mCode[ip + 3];
bool isSingleton = mCode[ip + 4];
U32 lineNumber = mCode[ip + 5];
U32 failJump = mCode[ip + 6];
Con::printf( "%i: OP_CREATE_OBJECT objParent=%s isDataBlock=%i isInternal=%i isSingleton=%i lineNumber=%i failJump=%i",
ip - 1, objParent, isDataBlock, isInternal, isSingleton, lineNumber, failJump );
ip += 6;
ip += 7;
break;
}
@ -823,6 +832,26 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
break;
}
case OP_RETURN_UINT:
{
Con::printf( "%i: OP_RETURNUINT", ip - 1 );
if( upToReturn )
return;
break;
}
case OP_RETURN_FLT:
{
Con::printf( "%i: OP_RETURNFLT", ip - 1 );
if( upToReturn )
return;
break;
}
case OP_CMPEQ:
{
Con::printf( "%i: OP_CMPEQ", ip - 1 );
@ -957,19 +986,19 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
case OP_SETCURVAR:
{
StringTableEntry var = U32toSTE(mCode[ip]);
StringTableEntry var = CodeToSTE(mCode, ip);
Con::printf( "%i: OP_SETCURVAR var=%s", ip - 1, var );
ip++;
ip += 2;
break;
}
case OP_SETCURVAR_CREATE:
{
StringTableEntry var = U32toSTE(mCode[ip]);
StringTableEntry var = CodeToSTE(mCode, ip);
Con::printf( "%i: OP_SETCURVAR_CREATE var=%s", ip - 1, var );
ip++;
ip += 2;
break;
}
@ -1003,6 +1032,12 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
break;
}
case OP_LOADVAR_VAR:
{
Con::printf( "%i: OP_LOADVAR_VAR", ip - 1 );
break;
}
case OP_SAVEVAR_UINT:
{
Con::printf( "%i: OP_SAVEVAR_UINT", ip - 1 );
@ -1021,6 +1056,12 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
break;
}
case OP_SAVEVAR_VAR:
{
Con::printf( "%i: OP_SAVEVAR_VAR", ip - 1 );
break;
}
case OP_SETCUROBJECT:
{
Con::printf( "%i: OP_SETCUROBJECT", ip - 1 );
@ -1042,9 +1083,10 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
case OP_SETCURFIELD:
{
StringTableEntry curField = U32toSTE(mCode[ip]);
StringTableEntry curField = CodeToSTE(mCode, ip);
Con::printf( "%i: OP_SETCURFIELD field=%s", ip - 1, curField );
++ ip;
ip += 2;
break;
}
case OP_SETCURFIELD_ARRAY:
@ -1151,6 +1193,12 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
break;
}
case OP_COPYVAR_TO_NONE:
{
Con::printf( "%i: OP_COPYVAR_TO_NONE", ip - 1 );
break;
}
case OP_LOADIMMED_UINT:
{
U32 val = mCode[ ip ];
@ -1161,7 +1209,7 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
case OP_LOADIMMED_FLT:
{
F64 val = mFunctionFloats[ mCode[ ip ] ];
F64 val = (smInFunction ? mFunctionFloats : mGlobalFloats)[ mCode[ ip ] ];
Con::printf( "%i: OP_LOADIMMED_FLT val=%f", ip - 1, val );
++ ip;
break;
@ -1169,7 +1217,7 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
case OP_TAG_TO_STR:
{
const char* str = mFunctionStrings + mCode[ ip ];
const char* str = (smInFunction ? mFunctionStrings : mGlobalStrings) + mCode[ ip ];
Con::printf( "%i: OP_TAG_TO_STR str=%s", ip - 1, str );
++ ip;
break;
@ -1177,7 +1225,7 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
case OP_LOADIMMED_STR:
{
const char* str = mFunctionStrings + mCode[ ip ];
const char* str = (smInFunction ? mFunctionStrings : mGlobalStrings) + mCode[ ip ];
Con::printf( "%i: OP_LOADIMMED_STR str=%s", ip - 1, str );
++ ip;
break;
@ -1185,7 +1233,7 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
case OP_DOCBLOCK_STR:
{
const char* str = mFunctionStrings + mCode[ ip ];
const char* str = (smInFunction ? mFunctionStrings : mGlobalStrings) + mCode[ ip ];
Con::printf( "%i: OP_DOCBLOCK_STR str=%s", ip - 1, str );
++ ip;
break;
@ -1193,37 +1241,37 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
case OP_LOADIMMED_IDENT:
{
StringTableEntry str = U32toSTE( mCode[ ip ] );
StringTableEntry str = CodeToSTE(mCode, ip);
Con::printf( "%i: OP_LOADIMMED_IDENT str=%s", ip - 1, str );
++ ip;
ip += 2;
break;
}
case OP_CALLFUNC_RESOLVE:
{
StringTableEntry fnNamespace = U32toSTE(mCode[ip+1]);
StringTableEntry fnName = U32toSTE(mCode[ip]);
StringTableEntry fnNamespace = CodeToSTE(mCode, ip+2);
StringTableEntry fnName = CodeToSTE(mCode, ip);
U32 callType = mCode[ip+2];
Con::printf( "%i: OP_CALLFUNC_RESOLVE name=%s nspace=%s callType=%s", ip - 1, fnName, fnNamespace,
callType == FuncCallExprNode::FunctionCall ? "FunctionCall"
: callType == FuncCallExprNode::MethodCall ? "MethodCall" : "ParentCall" );
ip += 3;
ip += 5;
break;
}
case OP_CALLFUNC:
{
StringTableEntry fnNamespace = U32toSTE(mCode[ip+1]);
StringTableEntry fnName = U32toSTE(mCode[ip]);
U32 callType = mCode[ip+2];
StringTableEntry fnNamespace = CodeToSTE(mCode, ip+2);
StringTableEntry fnName = CodeToSTE(mCode, ip);
U32 callType = mCode[ip+4];
Con::printf( "%i: OP_CALLFUNC name=%s nspace=%s callType=%s", ip - 1, fnName, fnNamespace,
callType == FuncCallExprNode::FunctionCall ? "FunctionCall"
: callType == FuncCallExprNode::MethodCall ? "MethodCall" : "ParentCall" );
ip += 3;
ip += 5;
break;
}
@ -1277,6 +1325,24 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
break;
}
case OP_PUSH_UINT:
{
Con::printf( "%i: OP_PUSH_UINT", ip - 1 );
break;
}
case OP_PUSH_FLT:
{
Con::printf( "%i: OP_PUSH_FLT", ip - 1 );
break;
}
case OP_PUSH_VAR:
{
Con::printf( "%i: OP_PUSH_VAR", ip - 1 );
break;
}
case OP_PUSH_FRAME:
{
Con::printf( "%i: OP_PUSH_FRAME", ip - 1 );
@ -1285,7 +1351,7 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
case OP_ASSERT:
{
const char* message = mFunctionStrings + mCode[ ip ];
const char* message = (smInFunction ? mFunctionStrings : mGlobalStrings) + mCode[ ip ];
Con::printf( "%i: OP_ASSERT message=%s", ip - 1, message );
++ ip;
break;
@ -1299,31 +1365,34 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
case OP_ITER_BEGIN:
{
StringTableEntry varName = U32toSTE( mCode[ ip ] );
U32 failIp = mCode[ ip + 1 ];
StringTableEntry varName = CodeToSTE(mCode, ip);
U32 failIp = mCode[ ip + 2 ];
Con::printf( "%i: OP_ITER_BEGIN varName=%s failIp=%i", varName, failIp );
Con::printf( "%i: OP_ITER_BEGIN varName=%s failIp=%i", ip - 1, varName, failIp );
++ ip;
ip += 3;
break;
}
case OP_ITER_BEGIN_STR:
{
StringTableEntry varName = U32toSTE( mCode[ ip ] );
U32 failIp = mCode[ ip + 1 ];
StringTableEntry varName = CodeToSTE(mCode, ip);
U32 failIp = mCode[ ip + 2 ];
Con::printf( "%i: OP_ITER_BEGIN varName=%s failIp=%i", varName, failIp );
Con::printf( "%i: OP_ITER_BEGIN varName=%s failIp=%i", ip - 1, varName, failIp );
ip += 2;
ip += 3;
break;
}
case OP_ITER:
{
U32 breakIp = mCode[ ip ];
Con::printf( "%i: OP_ITER breakIp=%i", breakIp );
Con::printf( "%i: OP_ITER breakIp=%i", ip - 1, breakIp );
++ ip;
break;
}
case OP_ITER_END:
@ -1337,4 +1406,6 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
break;
}
}
smInFunction = false;
}

View file

@ -27,6 +27,8 @@
#include "console/consoleParser.h"
class Stream;
class ConsoleValue;
class ConsoleValueRef;
/// Core TorqueScript code management class.
///
@ -38,7 +40,6 @@ private:
static CodeBlock* smCurrentCodeBlock;
public:
static U32 smBreakLineCount;
static bool smInFunction;
static Compiler::ConsoleParser * smCurrentParser;
@ -146,8 +147,8 @@ public:
/// -1 a new frame is created. If the index is out of range the
/// top stack frame is used.
/// @param packageName The code package name or null.
const char *exec(U32 offset, const char *fnName, Namespace *ns, U32 argc,
const char **argv, bool noCalls, StringTableEntry packageName,
ConsoleValueRef exec(U32 offset, const char *fnName, Namespace *ns, U32 argc,
ConsoleValueRef *argv, bool noCalls, StringTableEntry packageName,
S32 setFrame = -1);
};

View file

@ -45,6 +45,9 @@
#include "materials/materialManager.h"
#endif
// Uncomment to optimize function calls at the expense of potential invalid package lookups
//#define COMPILER_OPTIMIZE_FUNCTION_CALLS
using namespace Compiler;
enum EvalConstants {
@ -102,7 +105,11 @@ IterStackRecord iterStack[ MaxStackSize ];
F64 floatStack[MaxStackSize];
S64 intStack[MaxStackSize];
StringStack STR;
ConsoleValueStack CSTK;
U32 _FLT = 0; ///< Stack pointer for floatStack.
U32 _UINT = 0; ///< Stack pointer for intStack.
@ -188,18 +195,16 @@ namespace Con
return STR.getArgBuffer(bufferSize);
}
char *getFloatArg(F64 arg)
ConsoleValueRef getFloatArg(F64 arg)
{
char *ret = STR.getArgBuffer(32);
dSprintf(ret, 32, "%g", arg);
return ret;
ConsoleValueRef ref = arg;
return ref;
}
char *getIntArg(S32 arg)
ConsoleValueRef getIntArg(S32 arg)
{
char *ret = STR.getArgBuffer(32);
dSprintf(ret, 32, "%d", arg);
return ret;
ConsoleValueRef ref = arg;
return ref;
}
char *getStringArg( const char *arg )
@ -281,6 +286,25 @@ inline void ExprEvalState::setStringVariable(const char *val)
currentVariable->setStringValue(val);
}
inline void ExprEvalState::setCopyVariable()
{
if (copyVariable)
{
switch (copyVariable->value.type)
{
case ConsoleValue::TypeInternalInt:
currentVariable->setIntValue(copyVariable->getIntValue());
break;
case ConsoleValue::TypeInternalFloat:
currentVariable->setFloatValue(copyVariable->getFloatValue());
break;
default:
currentVariable->setStringValue(copyVariable->getStringValue());
break;
}
}
}
//------------------------------------------------------------
// Gets a component of an object's field value or a variable and returns it
@ -401,14 +425,15 @@ static void setFieldComponent( SimObject* object, StringTableEntry field, const
}
}
const char *CodeBlock::exec(U32 ip, const char *functionName, Namespace *thisNamespace, U32 argc, const char **argv, bool noCalls, StringTableEntry packageName, S32 setFrame)
ConsoleValueRef CodeBlock::exec(U32 ip, const char *functionName, Namespace *thisNamespace, U32 argc, ConsoleValueRef *argv, bool noCalls, StringTableEntry packageName, S32 setFrame)
{
#ifdef TORQUE_DEBUG
U32 stackStart = STR.mStartStackSize;
U32 consoleStackStart = CSTK.mStackPos;
#endif
static char traceBuffer[1024];
U32 i;
S32 i;
U32 iterDepth = 0;
@ -422,9 +447,9 @@ const char *CodeBlock::exec(U32 ip, const char *functionName, Namespace *thisNam
if(argv)
{
// assume this points into a function decl:
U32 fnArgc = mCode[ip + 5];
thisFunctionName = U32toSTE(mCode[ip]);
argc = getMin(argc-1, fnArgc); // argv[0] is func name
U32 fnArgc = mCode[ip + 2 + 6];
thisFunctionName = CodeToSTE(mCode, ip);
S32 wantedArgc = getMin(argc-1, fnArgc); // argv[0] is func name
if(gEvalState.traceOn)
{
traceBuffer[0] = 0;
@ -445,24 +470,35 @@ const char *CodeBlock::exec(U32 ip, const char *functionName, Namespace *thisNam
dSprintf(traceBuffer + dStrlen(traceBuffer), sizeof(traceBuffer) - dStrlen(traceBuffer),
"%s(", thisFunctionName);
}
for(i = 0; i < argc; i++)
for (i = 0; i < wantedArgc; i++)
{
dStrcat(traceBuffer, argv[i+1]);
if(i != argc - 1)
dStrcat(traceBuffer, ", ");
dStrcat(traceBuffer, argv[i + 1]);
if (i != wantedArgc - 1)
dStrcat(traceBuffer, ", ");
}
dStrcat(traceBuffer, ")");
Con::printf("%s", traceBuffer);
}
gEvalState.pushFrame(thisFunctionName, thisNamespace);
popFrame = true;
for(i = 0; i < argc; i++)
for(i = 0; i < wantedArgc; i++)
{
StringTableEntry var = U32toSTE(mCode[ip + i + 6]);
StringTableEntry var = CodeToSTE(mCode, ip + (2 + 6 + 1) + (i * 2));
gEvalState.setCurVarNameCreate(var);
gEvalState.setStringVariable(argv[i+1]);
ConsoleValueRef ref = argv[i+1];
if (argv[i+1].isString())
gEvalState.setStringVariable(argv[i+1]);
else if (argv[i+1].isInt())
gEvalState.setIntVariable(argv[i+1]);
else if (argv[i+1].isFloat())
gEvalState.setFloatVariable(argv[i+1]);
else
gEvalState.setStringVariable(argv[i+1]);
}
ip = ip + fnArgc + 6;
ip = ip + (fnArgc * 2) + (2 + 6 + 1);
curFloatTable = mFunctionFloats;
curStringTable = mFunctionStrings;
curStringTableLen = mFunctionStringsMaxLen;
@ -497,6 +533,10 @@ const char *CodeBlock::exec(U32 ip, const char *functionName, Namespace *thisNam
}
}
// Reset the console stack frame which at this point will contain
// either nothing or argv[] which we just copied
CSTK.resetFrame();
// Grab the state of the telenet debugger here once
// so that the push and pop frames are always balanced.
const bool telDebuggerOn = TelDebugger && TelDebugger->isConnected();
@ -530,7 +570,7 @@ const char *CodeBlock::exec(U32 ip, const char *functionName, Namespace *thisNam
char nsDocBlockClass[nsDocLength];
U32 callArgc;
const char **callArgv;
ConsoleValueRef *callArgv;
static char curFieldArray[256];
static char prevFieldArray[256];
@ -543,6 +583,10 @@ const char *CodeBlock::exec(U32 ip, const char *functionName, Namespace *thisNam
Con::gCurrentRoot = this->mModPath;
}
const char * val;
const char *retValue;
// note: anything returned is pushed to CSTK and will be invalidated on the next exec()
ConsoleValueRef returnValue;
// The frame temp is used by the variable accessor ops (OP_SAVEFIELD_* and
// OP_LOADFIELD_*) to store temporary values for the fields.
@ -559,11 +603,11 @@ breakContinue:
case OP_FUNC_DECL:
if(!noCalls)
{
fnName = U32toSTE(mCode[ip]);
fnNamespace = U32toSTE(mCode[ip+1]);
fnPackage = U32toSTE(mCode[ip+2]);
bool hasBody = ( mCode[ ip + 3 ] & 0x01 ) != 0;
U32 lineNumber = mCode[ ip + 3 ] >> 1;
fnName = CodeToSTE(mCode, ip);
fnNamespace = CodeToSTE(mCode, ip+2);
fnPackage = CodeToSTE(mCode, ip+4);
bool hasBody = ( mCode[ ip + 6 ] & 0x01 ) != 0;
U32 lineNumber = mCode[ ip + 6 ] >> 1;
Namespace::unlinkPackages();
ns = Namespace::find(fnNamespace, fnPackage);
@ -586,18 +630,18 @@ breakContinue:
//Con::printf("Adding function %s::%s (%d)", fnNamespace, fnName, ip);
}
ip = mCode[ip + 4];
ip = mCode[ip + 7];
break;
case OP_CREATE_OBJECT:
{
// Read some useful info.
objParent = U32toSTE(mCode[ip ]);
bool isDataBlock = mCode[ip + 1];
bool isInternal = mCode[ip + 2];
bool isSingleton = mCode[ip + 3];
U32 lineNumber = mCode[ip + 4];
failJump = mCode[ip + 5];
objParent = CodeToSTE(mCode, ip);
bool isDataBlock = mCode[ip + 2];
bool isInternal = mCode[ip + 3];
bool isSingleton = mCode[ip + 4];
U32 lineNumber = mCode[ip + 5];
failJump = mCode[ip + 6];
// If we don't allow calls, we certainly don't allow creating objects!
// Moved this to after failJump is set. Engine was crashing when
@ -615,8 +659,8 @@ breakContinue:
objectCreationStack[ objectCreationStackIndex++ ].failJump = failJump;
// Get the constructor information off the stack.
STR.getArgcArgv(NULL, &callArgc, &callArgv);
const char* objectName = callArgv[ 2 ];
CSTK.getArgcArgv(NULL, &callArgc, &callArgv);
const char *objectName = callArgv[ 2 ];
// Con::printf("Creating object...");
@ -638,6 +682,7 @@ breakContinue:
Con::errorf(ConsoleLogEntry::General, "%s: Cannot re-declare data block %s with a different class.", getFileLine(ip), objectName);
ip = failJump;
STR.popFrame();
CSTK.popFrame();
break;
}
@ -659,18 +704,19 @@ breakContinue:
break;
}
SimObject *obj = Sim::findObject( objectName );
SimObject *obj = Sim::findObject( (const char*)objectName );
if (obj /*&& !obj->isLocalName()*/)
{
if ( isSingleton )
{
// Make sure we're not trying to change types
if ( dStricmp( obj->getClassName(), callArgv[1] ) != 0 )
if ( dStricmp( obj->getClassName(), (const char*)callArgv[1] ) != 0 )
{
Con::errorf(ConsoleLogEntry::General, "%s: Cannot re-declare object [%s] with a different class [%s] - was [%s].",
getFileLine(ip), objectName, callArgv[1], obj->getClassName());
getFileLine(ip), objectName, (const char*)callArgv[1], obj->getClassName());
ip = failJump;
STR.popFrame();
CSTK.popFrame();
break;
}
@ -688,13 +734,29 @@ breakContinue:
// string stack and may get stomped if deleteObject triggers
// script execution.
const char* savedArgv[ StringStack::MaxArgs ];
dMemcpy( savedArgv, callArgv, sizeof( savedArgv[ 0 ] ) * callArgc );
ConsoleValueRef savedArgv[ StringStack::MaxArgs ];
for (int i=0; i<callArgc; i++) {
savedArgv[i] = callArgv[i];
}
//dMemcpy( savedArgv, callArgv, sizeof( savedArgv[ 0 ] ) * callArgc );
// Prevent stack value corruption
CSTK.pushFrame();
STR.pushFrame();
// --
obj->deleteObject();
obj = NULL;
dMemcpy( callArgv, savedArgv, sizeof( callArgv[ 0 ] ) * callArgc );
// Prevent stack value corruption
CSTK.popFrame();
STR.popFrame();
// --
//dMemcpy( callArgv, savedArgv, sizeof( callArgv[ 0 ] ) * callArgc );
for (int i=0; i<callArgc; i++) {
callArgv[i] = savedArgv[i];
}
}
else if( dStricmp( redefineBehavior, "renameNew" ) == 0 )
{
@ -723,6 +785,7 @@ breakContinue:
getFileLine(ip), newName.c_str() );
ip = failJump;
STR.popFrame();
CSTK.popFrame();
break;
}
else
@ -734,6 +797,7 @@ breakContinue:
getFileLine(ip), objectName);
ip = failJump;
STR.popFrame();
CSTK.popFrame();
break;
}
}
@ -741,16 +805,17 @@ breakContinue:
}
STR.popFrame();
CSTK.popFrame();
if(!currentNewObject)
{
// Well, looks like we have to create a new object.
ConsoleObject *object = ConsoleObject::create(callArgv[1]);
ConsoleObject *object = ConsoleObject::create((const char*)callArgv[1]);
// Deal with failure!
if(!object)
{
Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-conobject class %s.", getFileLine(ip), callArgv[1]);
Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-conobject class %s.", getFileLine(ip), (const char*)callArgv[1]);
ip = failJump;
break;
}
@ -766,7 +831,7 @@ breakContinue:
else
{
// They tried to make a non-datablock with a datablock keyword!
Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-datablock class %s.", getFileLine(ip), callArgv[1]);
Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-datablock class %s.", getFileLine(ip), (const char*)callArgv[1]);
// Clean up...
delete object;
ip = failJump;
@ -780,7 +845,7 @@ breakContinue:
// Deal with the case of a non-SimObject.
if(!currentNewObject)
{
Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-SimObject class %s.", getFileLine(ip), callArgv[1]);
Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-SimObject class %s.", getFileLine(ip), (const char*)callArgv[1]);
delete object;
ip = failJump;
break;
@ -807,7 +872,7 @@ breakContinue:
else
{
if ( Con::gObjectCopyFailures == -1 )
Con::errorf(ConsoleLogEntry::General, "%s: Unable to find parent object %s for %s.", getFileLine(ip), objParent, callArgv[1]);
Con::errorf(ConsoleLogEntry::General, "%s: Unable to find parent object %s for %s.", getFileLine(ip), objParent, (const char*)callArgv[1]);
else
++Con::gObjectCopyFailures;
@ -830,15 +895,30 @@ breakContinue:
currentNewObject->setOriginalName( objectName );
}
// Prevent stack value corruption
CSTK.pushFrame();
STR.pushFrame();
// --
// Do the constructor parameters.
if(!currentNewObject->processArguments(callArgc-3, callArgv+3))
{
delete currentNewObject;
currentNewObject = NULL;
ip = failJump;
// Prevent stack value corruption
CSTK.popFrame();
STR.popFrame();
// --
break;
}
// Prevent stack value corruption
CSTK.popFrame();
STR.popFrame();
// --
// If it's not a datablock, allow people to modify bits of it.
if(!isDataBlock)
{
@ -848,7 +928,7 @@ breakContinue:
}
// Advance the IP past the create info...
ip += 6;
ip += 7;
break;
}
@ -863,6 +943,11 @@ breakContinue:
// Con::printf("Adding object %s", currentNewObject->getName());
// Prevent stack value corruption
CSTK.pushFrame();
STR.pushFrame();
// --
// Make sure it wasn't already added, then add it.
if(currentNewObject->isProperlyAdded() == false)
{
@ -886,6 +971,10 @@ breakContinue:
Con::warnf(ConsoleLogEntry::General, "%s: Register object failed for object %s of class %s.", getFileLine(ip), currentNewObject->getName(), currentNewObject->getClassName());
delete currentNewObject;
ip = failJump;
// Prevent stack value corruption
CSTK.popFrame();
STR.popFrame();
// --
break;
}
}
@ -894,6 +983,8 @@ breakContinue:
SimDataBlock *dataBlock = dynamic_cast<SimDataBlock *>(currentNewObject);
static String errorStr;
// If so, preload it.
if(dataBlock && !dataBlock->preload(true, errorStr))
{
@ -901,6 +992,11 @@ breakContinue:
currentNewObject->getName(), errorStr.c_str());
dataBlock->deleteObject();
ip = failJump;
// Prevent stack value corruption
CSTK.popFrame();
STR.popFrame();
// --
break;
}
@ -955,6 +1051,10 @@ breakContinue:
else
intStack[++_UINT] = currentNewObject->getId();
// Prevent stack value corruption
CSTK.popFrame();
STR.popFrame();
// --
break;
}
@ -1037,6 +1137,29 @@ breakContinue:
// We're falling thru here on purpose.
case OP_RETURN:
retValue = STR.getStringValue();
if( iterDepth > 0 )
{
// Clear iterator state.
while( iterDepth > 0 )
{
iterStack[ -- _ITER ].mIsStringIter = false;
-- iterDepth;
}
STR.rewind();
STR.setStringValue( retValue ); // Not nice but works.
retValue = STR.getStringValue();
}
// Previously the return value was on the stack and would be returned using STR.getStringValue().
// Now though we need to wrap it in a ConsoleValueRef
returnValue.value = CSTK.pushStackString(retValue);
goto execFinished;
case OP_RETURN_FLT:
if( iterDepth > 0 )
{
@ -1047,10 +1170,27 @@ breakContinue:
-- iterDepth;
}
const char* returnValue = STR.getStringValue();
STR.rewind();
STR.setStringValue( returnValue ); // Not nice but works.
}
returnValue.value = CSTK.pushFLT(floatStack[_FLT]);
_FLT--;
goto execFinished;
case OP_RETURN_UINT:
if( iterDepth > 0 )
{
// Clear iterator state.
while( iterDepth > 0 )
{
iterStack[ -- _ITER ].mIsStringIter = false;
-- iterDepth;
}
}
returnValue.value = CSTK.pushUINT(intStack[_UINT]);
_UINT--;
goto execFinished;
@ -1170,8 +1310,8 @@ breakContinue:
break;
case OP_SETCURVAR:
var = U32toSTE(mCode[ip]);
ip++;
var = CodeToSTE(mCode, ip);
ip += 2;
// If a variable is set, then these must be NULL. It is necessary
// to set this here so that the vector parser can appropriately
@ -1190,10 +1330,10 @@ breakContinue:
break;
case OP_SETCURVAR_CREATE:
var = U32toSTE(mCode[ip]);
ip++;
var = CodeToSTE(mCode, ip);
ip += 2;
// See OP_SETCURVAR
// See OP_SETCURVAR
prevField = NULL;
prevObject = NULL;
curObject = NULL;
@ -1250,6 +1390,11 @@ breakContinue:
STR.setStringValue(val);
break;
case OP_LOADVAR_VAR:
// Sets current source of OP_SAVEVAR_VAR
gEvalState.copyVariable = gEvalState.currentVariable;
break;
case OP_SAVEVAR_UINT:
gEvalState.setIntVariable(intStack[_UINT]);
break;
@ -1261,6 +1406,11 @@ breakContinue:
case OP_SAVEVAR_STR:
gEvalState.setStringVariable(STR.getStringValue());
break;
case OP_SAVEVAR_VAR:
// this basically handles %var1 = %var2
gEvalState.setCopyVariable();
break;
case OP_SETCUROBJECT:
// Save the previous object for parsing vector fields.
@ -1310,9 +1460,9 @@ breakContinue:
// Save the previous field for parsing vector fields.
prevField = curField;
dStrcpy( prevFieldArray, curFieldArray );
curField = U32toSTE(mCode[ip]);
curField = CodeToSTE(mCode, ip);
curFieldArray[0] = 0;
ip++;
ip += 2;
break;
case OP_SETCURFIELD_ARRAY:
@ -1448,6 +1598,10 @@ breakContinue:
_UINT--;
break;
case OP_COPYVAR_TO_NONE:
gEvalState.copyVariable = NULL;
break;
case OP_LOADIMMED_UINT:
intStack[_UINT+1] = mCode[ip++];
_UINT++;
@ -1504,28 +1658,41 @@ breakContinue:
break;
case OP_LOADIMMED_IDENT:
STR.setStringValue(U32toSTE(mCode[ip++]));
STR.setStringValue(CodeToSTE(mCode, ip));
ip += 2;
break;
case OP_CALLFUNC_RESOLVE:
// This deals with a function that is potentially living in a namespace.
fnNamespace = U32toSTE(mCode[ip+1]);
fnName = U32toSTE(mCode[ip]);
fnNamespace = CodeToSTE(mCode, ip+2);
fnName = CodeToSTE(mCode, ip);
// Try to look it up.
ns = Namespace::find(fnNamespace);
nsEntry = ns->lookup(fnName);
if(!nsEntry)
{
ip+= 3;
ip+= 5;
Con::warnf(ConsoleLogEntry::General,
"%s: Unable to find function %s%s%s",
getFileLine(ip-4), fnNamespace ? fnNamespace : "",
getFileLine(ip-7), fnNamespace ? fnNamespace : "",
fnNamespace ? "::" : "", fnName);
STR.popFrame();
CSTK.popFrame();
break;
}
#ifdef COMPILER_OPTIMIZE_FUNCTION_CALLS
// Now fall through to OP_CALLFUNC...
// Now, rewrite our code a bit (ie, avoid future lookups) and fall
// through to OP_CALLFUNC
#ifdef TORQUE_CPU_X64
*((U64*)(code+ip+2)) = ((U64)nsEntry);
#else
code[ip+2] = ((U32)nsEntry);
#endif
code[ip-1] = OP_CALLFUNC;
#endif
case OP_CALLFUNC:
{
@ -1535,7 +1702,7 @@ breakContinue:
// or just on the object.
S32 routingId = 0;
fnName = U32toSTE(mCode[ip]);
fnName = CodeToSTE(mCode, ip);
//if this is called from inside a function, append the ip and codeptr
if( gEvalState.getStackDepth() > 0 )
@ -1544,10 +1711,10 @@ breakContinue:
gEvalState.getCurrentFrame().ip = ip - 1;
}
U32 callType = mCode[ip+2];
U32 callType = mCode[ip+4];
ip += 3;
STR.getArgcArgv(fnName, &callArgc, &callArgv);
ip += 5;
CSTK.getArgcArgv(fnName, &callArgc, &callArgv);
const char *componentReturnValue = "";
@ -1555,23 +1722,32 @@ breakContinue:
{
if( !nsEntry )
{
// We must not have come from OP_CALLFUNC_RESOLVE, so figure out
// our own entry.
#ifdef COMPILER_OPTIMIZE_FUNCTION_CALLS
#ifdef TORQUE_CPU_X64
nsEntry = ((Namespace::Entry *) *((U64*)(code+ip-3)));
#else
nsEntry = ((Namespace::Entry *) *(code+ip-3));
#endif
#else
nsEntry = Namespace::global()->lookup( fnName );
#endif
ns = NULL;
}
ns = NULL;
}
else if(callType == FuncCallExprNode::MethodCall)
{
saveObject = gEvalState.thisObject;
gEvalState.thisObject = Sim::findObject(callArgv[1]);
gEvalState.thisObject = Sim::findObject((const char*)callArgv[1]);
if(!gEvalState.thisObject)
{
// Go back to the previous saved object.
gEvalState.thisObject = saveObject;
Con::warnf(ConsoleLogEntry::General,"%s: Unable to find object: '%s' attempting to call function '%s'", getFileLine(ip-4), callArgv[1], fnName);
Con::warnf(ConsoleLogEntry::General,"%s: Unable to find object: '%s' attempting to call function '%s'", getFileLine(ip-4), (const char*)callArgv[1], fnName);
STR.popFrame();
CSTK.popFrame();
STR.setStringValue("");
break;
}
@ -1618,7 +1794,7 @@ breakContinue:
{
if(!noCalls && !( routingId == MethodOnComponent ) )
{
Con::warnf(ConsoleLogEntry::General,"%s: Unknown command %s.", getFileLine(ip-4), fnName);
Con::warnf(ConsoleLogEntry::General,"%s: Unknown command %s.", getFileLine(ip-6), fnName);
if(callType == FuncCallExprNode::MethodCall)
{
Con::warnf(ConsoleLogEntry::General, " Object %s(%d) %s",
@ -1627,6 +1803,7 @@ breakContinue:
}
}
STR.popFrame();
CSTK.popFrame();
if( routingId == MethodOnComponent )
STR.setStringValue( componentReturnValue );
@ -1637,12 +1814,33 @@ breakContinue:
}
if(nsEntry->mType == Namespace::Entry::ConsoleFunctionType)
{
const char *ret = "";
ConsoleValueRef ret;
if(nsEntry->mFunctionOffset)
ret = nsEntry->mCode->exec(nsEntry->mFunctionOffset, fnName, nsEntry->mNamespace, callArgc, callArgv, false, nsEntry->mPackage);
STR.popFrame();
STR.setStringValue(ret);
// Functions are assumed to return strings, so look ahead to see if we can skip the conversion
if(mCode[ip] == OP_STR_TO_UINT)
{
ip++;
intStack[++_UINT] = (U32)((S32)ret);
}
else if(mCode[ip] == OP_STR_TO_FLT)
{
ip++;
floatStack[++_FLT] = (F32)ret;
}
else if(mCode[ip] == OP_STR_TO_NONE)
{
STR.setStringValue(ret.getStringValue());
ip++;
}
else
STR.setStringValue((const char*)ret);
// This will clear everything including returnValue
CSTK.popFrame();
STR.clearFunctionOffset();
}
else
{
@ -1652,17 +1850,18 @@ breakContinue:
// which is useful behavior when debugging so I'm ifdefing this out for debug builds.
if(nsEntry->mToolOnly && ! Con::isCurrentScriptToolScript())
{
Con::errorf(ConsoleLogEntry::Script, "%s: %s::%s - attempting to call tools only function from outside of tools.", getFileLine(ip-4), nsName, fnName);
Con::errorf(ConsoleLogEntry::Script, "%s: %s::%s - attempting to call tools only function from outside of tools.", getFileLine(ip-6), nsName, fnName);
}
else
#endif
if((nsEntry->mMinArgs && S32(callArgc) < nsEntry->mMinArgs) || (nsEntry->mMaxArgs && S32(callArgc) > nsEntry->mMaxArgs))
{
Con::warnf(ConsoleLogEntry::Script, "%s: %s::%s - wrong number of arguments (got %i, expected min %i and max %i).",
getFileLine(ip-4), nsName, fnName,
getFileLine(ip-6), nsName, fnName,
callArgc, nsEntry->mMinArgs, nsEntry->mMaxArgs);
Con::warnf(ConsoleLogEntry::Script, "%s: usage: %s", getFileLine(ip-4), nsEntry->mUsage);
Con::warnf(ConsoleLogEntry::Script, "%s: usage: %s", getFileLine(ip-6), nsEntry->mUsage);
STR.popFrame();
CSTK.popFrame();
}
else
{
@ -1672,16 +1871,18 @@ breakContinue:
{
const char *ret = nsEntry->cb.mStringCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
STR.popFrame();
CSTK.popFrame();
if(ret != STR.getStringValue())
STR.setStringValue(ret);
else
STR.setLen(dStrlen(ret));
//else
// STR.setLen(dStrlen(ret));
break;
}
case Namespace::Entry::IntCallbackType:
{
S32 result = nsEntry->cb.mIntCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
STR.popFrame();
CSTK.popFrame();
if(mCode[ip] == OP_STR_TO_UINT)
{
ip++;
@ -1704,6 +1905,7 @@ breakContinue:
{
F64 result = nsEntry->cb.mFloatCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
STR.popFrame();
CSTK.popFrame();
if(mCode[ip] == OP_STR_TO_UINT)
{
ip++;
@ -1725,15 +1927,17 @@ breakContinue:
case Namespace::Entry::VoidCallbackType:
nsEntry->cb.mVoidCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
if( mCode[ ip ] != OP_STR_TO_NONE && Con::getBoolVariable( "$Con::warnVoidAssignment", true ) )
Con::warnf(ConsoleLogEntry::General, "%s: Call to %s in %s uses result of void function call.", getFileLine(ip-4), fnName, functionName);
Con::warnf(ConsoleLogEntry::General, "%s: Call to %s in %s uses result of void function call.", getFileLine(ip-6), fnName, functionName);
STR.popFrame();
CSTK.popFrame();
STR.setStringValue("");
break;
case Namespace::Entry::BoolCallbackType:
{
bool result = nsEntry->cb.mBoolCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
STR.popFrame();
CSTK.popFrame();
if(mCode[ip] == OP_STR_TO_UINT)
{
ip++;
@ -1788,10 +1992,26 @@ breakContinue:
break;
case OP_PUSH:
STR.push();
CSTK.pushString(STR.getPreviousStringValue());
break;
case OP_PUSH_UINT:
CSTK.pushUINT(intStack[_UINT]);
_UINT--;
break;
case OP_PUSH_FLT:
CSTK.pushFLT(floatStack[_FLT]);
_FLT--;
break;
case OP_PUSH_VAR:
if (gEvalState.currentVariable)
CSTK.pushValue(gEvalState.currentVariable->value);
else
CSTK.pushString("");
break;
case OP_PUSH_FRAME:
STR.pushFrame();
CSTK.pushFrame();
break;
case OP_ASSERT:
@ -1844,8 +2064,8 @@ breakContinue:
case OP_ITER_BEGIN:
{
StringTableEntry varName = U32toSTE( mCode[ ip ] );
U32 failIp = mCode[ ip + 1 ];
StringTableEntry varName = CodeToSTE(mCode, ip);
U32 failIp = mCode[ ip + 2 ];
IterStackRecord& iter = iterStack[ _ITER ];
@ -1880,7 +2100,7 @@ breakContinue:
STR.push();
ip += 2;
ip += 3;
break;
}
@ -2021,7 +2241,8 @@ execFinished:
AssertFatal(!(STR.mStartStackSize > stackStart), "String stack not popped enough in script exec");
AssertFatal(!(STR.mStartStackSize < stackStart), "String stack popped too much in script exec");
#endif
return STR.getStringValue();
return returnValue;
}
//------------------------------------------------------------

View file

@ -60,29 +60,27 @@ namespace Compiler
CompilerFloatTable *gCurrentFloatTable, gGlobalFloatTable, gFunctionFloatTable;
DataChunker gConsoleAllocator;
CompilerIdentTable gIdentTable;
CodeBlock *gCurBreakBlock;
//------------------------------------------------------------
CodeBlock *getBreakCodeBlock() { return gCurBreakBlock; }
void setBreakCodeBlock(CodeBlock *cb) { gCurBreakBlock = cb; }
//------------------------------------------------------------
U32 evalSTEtoU32(StringTableEntry ste, U32)
void evalSTEtoCode(StringTableEntry ste, U32 ip, U32 *ptr)
{
return *((U32 *) &ste);
#ifdef TORQUE_CPU_X64
*(U64*)(ptr) = (U64)ste;
#else
*ptr = (U32)ste;
#endif
}
U32 compileSTEtoU32(StringTableEntry ste, U32 ip)
void compileSTEtoCode(StringTableEntry ste, U32 ip, U32 *ptr)
{
if(ste)
getIdentTable().add(ste, ip);
return 0;
*ptr = 0;
*(ptr+1) = 0;
}
U32 (*STEtoU32)(StringTableEntry ste, U32 ip) = evalSTEtoU32;
void (*STEtoCode)(StringTableEntry ste, U32 ip, U32 *ptr) = evalSTEtoCode;
//------------------------------------------------------------
@ -286,3 +284,131 @@ void CompilerIdentTable::write(Stream &st)
st.write(el->ip);
}
}
//-------------------------------------------------------------------------
U8 *CodeStream::allocCode(U32 sz)
{
U8 *ptr = NULL;
if (mCodeHead)
{
const U32 bytesLeft = BlockSize - mCodeHead->size;
if (bytesLeft > sz)
{
ptr = mCodeHead->data + mCodeHead->size;
mCodeHead->size += sz;
return ptr;
}
}
CodeData *data = new CodeData;
data->data = (U8*)dMalloc(BlockSize);
data->size = sz;
data->next = NULL;
if (mCodeHead)
mCodeHead->next = data;
mCodeHead = data;
if (mCode == NULL)
mCode = data;
return data->data;
}
//-------------------------------------------------------------------------
void CodeStream::fixLoop(U32 loopBlockStart, U32 breakPoint, U32 continuePoint)
{
AssertFatal(mFixStack.size() > 0, "Fix stack mismatch");
U32 fixStart = mFixStack[mFixStack.size()-1];
for (U32 i=fixStart; i<mFixList.size(); i += 2)
{
FixType type = (FixType)mFixList[i+1];
U32 fixedIp = 0;
bool valid = true;
switch (type)
{
case FIXTYPE_LOOPBLOCKSTART:
fixedIp = loopBlockStart;
break;
case FIXTYPE_BREAK:
fixedIp = breakPoint;
break;
case FIXTYPE_CONTINUE:
fixedIp = continuePoint;
break;
default:
//Con::warnf("Address %u fixed as %u", mFixList[i], mFixList[i+1]);
valid = false;
break;
}
if (valid)
{
patch(mFixList[i], fixedIp);
}
}
}
//-------------------------------------------------------------------------
void CodeStream::emitCodeStream(U32 *size, U32 **stream, U32 **lineBreaks)
{
// Alloc stream
U32 numLineBreaks = getNumLineBreaks();
*stream = new U32[mCodePos + (numLineBreaks * 2)];
dMemset(*stream, '\0', mCodePos + (numLineBreaks * 2));
*size = mCodePos;
// Dump chunks & line breaks
U32 outBytes = mCodePos * sizeof(U32);
U8 *outPtr = *((U8**)stream);
for (CodeData *itr = mCode; itr != NULL; itr = itr->next)
{
U32 bytesToCopy = itr->size > outBytes ? outBytes : itr->size;
dMemcpy(outPtr, itr->data, bytesToCopy);
outPtr += bytesToCopy;
outBytes -= bytesToCopy;
}
*lineBreaks = *stream + mCodePos;
dMemcpy(*lineBreaks, mBreakLines.address(), sizeof(U32) * mBreakLines.size());
// Apply patches on top
for (U32 i=0; i<mPatchList.size(); i++)
{
PatchEntry &e = mPatchList[i];
(*stream)[e.addr] = e.value;
}
}
//-------------------------------------------------------------------------
void CodeStream::reset()
{
mCodePos = 0;
mFixStack.clear();
mFixLoopStack.clear();
mFixList.clear();
mBreakLines.clear();
// Pop down to one code block
CodeData *itr = mCode ? mCode->next : NULL;
while (itr != NULL)
{
CodeData *next = itr->next;
dFree(itr->data);
dFree(itr);
itr = next;
}
if (mCode)
{
mCode->size = 0;
mCode->next = NULL;
mCodeHead = mCode;
}
}

View file

@ -24,6 +24,12 @@
#ifndef _COMPILER_H_
#define _COMPILER_H_
//#define DEBUG_CODESTREAM
#ifdef DEBUG_CODESTREAM
#include <stdio.h>
#endif
class Stream;
class DataChunker;
@ -31,6 +37,9 @@ class DataChunker;
#include "console/ast.h"
#include "console/codeBlock.h"
#ifndef _TVECTOR_H_
#include "core/util/tVector.h"
#endif
namespace Compiler
{
@ -49,18 +58,21 @@ namespace Compiler
OP_JMPIFF,
OP_JMPIF,
OP_JMPIFNOT_NP,
OP_JMPIF_NP,
OP_JMPIF_NP, // 10
OP_JMP,
OP_RETURN,
// fixes a bug when not explicitly returning a value
OP_RETURN_VOID,
OP_RETURN_FLT,
OP_RETURN_UINT,
OP_CMPEQ,
OP_CMPGR,
OP_CMPGE,
OP_CMPLT,
OP_CMPLE,
OP_CMPNE,
OP_XOR,
OP_XOR, // 20
OP_MOD,
OP_BITAND,
OP_BITOR,
@ -71,7 +83,7 @@ namespace Compiler
OP_SHR,
OP_SHL,
OP_AND,
OP_OR,
OP_OR, // 30
OP_ADD,
OP_SUB,
@ -84,20 +96,22 @@ namespace Compiler
OP_SETCURVAR_ARRAY,
OP_SETCURVAR_ARRAY_CREATE,
OP_LOADVAR_UINT,
OP_LOADVAR_UINT,// 40
OP_LOADVAR_FLT,
OP_LOADVAR_STR,
OP_LOADVAR_VAR,
OP_SAVEVAR_UINT,
OP_SAVEVAR_FLT,
OP_SAVEVAR_STR,
OP_SAVEVAR_VAR,
OP_SETCUROBJECT,
OP_SETCUROBJECT_NEW,
OP_SETCUROBJECT_INTERNAL,
OP_SETCURFIELD,
OP_SETCURFIELD_ARRAY,
OP_SETCURFIELD_ARRAY, // 50
OP_SETCURFIELD_TYPE,
OP_LOADFIELD_UINT,
@ -110,18 +124,19 @@ namespace Compiler
OP_STR_TO_UINT,
OP_STR_TO_FLT,
OP_STR_TO_NONE,
OP_STR_TO_NONE, // 60
OP_FLT_TO_UINT,
OP_FLT_TO_STR,
OP_FLT_TO_NONE,
OP_UINT_TO_FLT,
OP_UINT_TO_STR,
OP_UINT_TO_NONE,
OP_COPYVAR_TO_NONE,
OP_LOADIMMED_UINT,
OP_LOADIMMED_FLT,
OP_TAG_TO_STR,
OP_LOADIMMED_STR,
OP_LOADIMMED_STR, // 70
OP_DOCBLOCK_STR,
OP_LOADIMMED_IDENT,
@ -133,11 +148,14 @@ namespace Compiler
OP_ADVANCE_STR_COMMA,
OP_ADVANCE_STR_NUL,
OP_REWIND_STR,
OP_TERMINATE_REWIND_STR,
OP_TERMINATE_REWIND_STR, // 80
OP_COMPARE_STR,
OP_PUSH,
OP_PUSH_FRAME,
OP_PUSH, // String
OP_PUSH_UINT, // Integer
OP_PUSH_FLT, // Float
OP_PUSH_VAR, // Variable
OP_PUSH_FRAME, // Frame
OP_ASSERT,
OP_BREAK,
@ -147,14 +165,14 @@ namespace Compiler
OP_ITER, ///< Enter foreach loop.
OP_ITER_END, ///< End foreach loop.
OP_INVALID
OP_INVALID // 90
};
//------------------------------------------------------------
F64 consoleStringToNumber(const char *str, StringTableEntry file = 0, U32 line = 0);
U32 precompileBlock(StmtNode *block, U32 loopCount);
U32 compileBlock(StmtNode *block, U32 *codeStream, U32 ip, U32 continuePoint, U32 breakPoint);
U32 compileBlock(StmtNode *block, CodeStream &codeStream, U32 ip);
//------------------------------------------------------------
@ -218,15 +236,19 @@ namespace Compiler
//------------------------------------------------------------
inline StringTableEntry U32toSTE(U32 u)
inline StringTableEntry CodeToSTE(U32 *code, U32 ip)
{
return *((StringTableEntry *) &u);
#ifdef TORQUE_CPU_X64
return (StringTableEntry)(*((U64*)(code+ip)));
#else
return (StringTableEntry)(*(code+ip));
#endif
}
extern U32 (*STEtoU32)(StringTableEntry ste, U32 ip);
U32 evalSTEtoU32(StringTableEntry ste, U32);
U32 compileSTEtoU32(StringTableEntry ste, U32 ip);
extern void (*STEtoCode)(StringTableEntry ste, U32 ip, U32 *ptr);
void evalSTEtoCode(StringTableEntry ste, U32 ip, U32 *ptr);
void compileSTEtoCode(StringTableEntry ste, U32 ip, U32 *ptr);
CompilerStringTable *getCurrentStringTable();
CompilerStringTable &getGlobalStringTable();
@ -244,9 +266,6 @@ namespace Compiler
void precompileIdent(StringTableEntry ident);
CodeBlock *getBreakCodeBlock();
void setBreakCodeBlock(CodeBlock *cb);
/// Helper function to reset the float, string, and ident tables to a base
/// starting state.
void resetTables();
@ -257,4 +276,170 @@ namespace Compiler
extern bool gSyntaxError;
};
/// Utility class to emit and patch bytecode
class CodeStream
{
public:
enum FixType
{
// For loops
FIXTYPE_LOOPBLOCKSTART,
FIXTYPE_BREAK,
FIXTYPE_CONTINUE
};
enum Constants
{
BlockSize = 16384,
};
protected:
typedef struct PatchEntry
{
U32 addr; ///< Address to patch
U32 value; ///< Value to place at addr
PatchEntry() {;}
PatchEntry(U32 a, U32 v) : addr(a), value(v) {;}
} PatchEntry;
typedef struct CodeData
{
U8 *data; ///< Allocated data (size is BlockSize)
U32 size; ///< Bytes used in data
CodeData *next; ///< Next block
};
/// @name Emitted code
/// {
CodeData *mCode;
CodeData *mCodeHead;
U32 mCodePos;
/// }
/// @name Code fixing stacks
/// {
Vector<U32> mFixList;
Vector<U32> mFixStack;
Vector<bool> mFixLoopStack;
Vector<PatchEntry> mPatchList;
/// }
Vector<U32> mBreakLines; ///< Line numbers
public:
CodeStream() : mCode(0), mCodeHead(NULL), mCodePos(0)
{
}
~CodeStream()
{
reset();
if (mCode)
{
dFree(mCode->data);
delete mCode;
}
}
U8 *allocCode(U32 sz);
inline U32 emit(U32 code)
{
U32 *ptr = (U32*)allocCode(4);
*ptr = code;
#ifdef DEBUG_CODESTREAM
printf("code[%u] = %u\n", mCodePos, code);
#endif
return mCodePos++;
}
inline void patch(U32 addr, U32 code)
{
#ifdef DEBUG_CODESTREAM
printf("patch[%u] = %u\n", addr, code);
#endif
mPatchList.push_back(PatchEntry(addr, code));
}
inline U32 emitSTE(const char *code)
{
U64 *ptr = (U64*)allocCode(8);
*ptr = 0;
Compiler::STEtoCode(code, mCodePos, (U32*)ptr);
#ifdef DEBUG_CODESTREAM
printf("code[%u] = %s\n", mCodePos, code);
#endif
mCodePos += 2;
return mCodePos-2;
}
inline U32 tell()
{
return mCodePos;
}
inline bool inLoop()
{
for (U32 i=0; i<mFixLoopStack.size(); i++)
{
if (mFixLoopStack[i])
return true;
}
return false;
}
inline U32 emitFix(FixType type)
{
U32 *ptr = (U32*)allocCode(4);
*ptr = (U32)type;
#ifdef DEBUG_CODESTREAM
printf("code[%u] = [FIX:%u]\n", mCodePos, (U32)type);
#endif
mFixList.push_back(mCodePos);
mFixList.push_back((U32)type);
return mCodePos++;
}
inline void pushFixScope(bool isLoop)
{
mFixStack.push_back(mFixList.size());
mFixLoopStack.push_back(isLoop);
}
inline void popFixScope()
{
AssertFatal(mFixStack.size() > 0, "Fix stack mismatch");
U32 newSize = mFixStack[mFixStack.size()-1];
while (mFixList.size() > newSize)
mFixList.pop_back();
mFixStack.pop_back();
mFixLoopStack.pop_back();
}
void fixLoop(U32 loopBlockStart, U32 breakPoint, U32 continuePoint);
inline void addBreakLine(U32 lineNumber, U32 ip)
{
mBreakLines.push_back(lineNumber);
mBreakLines.push_back(ip);
}
inline U32 getNumLineBreaks()
{
return mBreakLines.size() / 2;
}
void emitCodeStream(U32 *size, U32 **stream, U32 **lineBreaks);
void reset();
};
#endif

View file

@ -42,6 +42,7 @@
extern StringStack STR;
extern ConsoleValueStack CSTK;
ConsoleDocFragment* ConsoleDocFragment::smFirst;
ExprEvalState gEvalState;
@ -709,10 +710,11 @@ void errorf(const char* fmt,...)
//---------------------------------------------------------------------------
void setVariable(const char *name, const char *value)
bool getVariableObjectField(const char *name, SimObject **object, const char **field)
{
// get the field info from the object..
if(name[0] != '$' && dStrchr(name, '.') && !isFunction(name))
const char *dot = dStrchr(name, '.');
if(name[0] != '$' && dot)
{
S32 len = dStrlen(name);
AssertFatal(len < sizeof(scratchBuffer)-1, "Sim::getVariable - name too long");
@ -721,17 +723,17 @@ void setVariable(const char *name, const char *value)
char * token = dStrtok(scratchBuffer, ".");
SimObject * obj = Sim::findObject(token);
if(!obj)
return;
return false;
token = dStrtok(0, ".\0");
if(!token)
return;
return false;
while(token != NULL)
{
const char * val = obj->getDataField(StringTable->insert(token), 0);
if(!val)
return;
return false;
char *fieldToken = token;
token = dStrtok(0, ".\0");
@ -739,17 +741,72 @@ void setVariable(const char *name, const char *value)
{
obj = Sim::findObject(token);
if(!obj)
return;
return false;
}
else
{
obj->setDataField(StringTable->insert(fieldToken), 0, value);
*object = obj;
*field = fieldToken;
return true;
}
}
}
return false;
}
Dictionary::Entry *getLocalVariableEntry(const char *name)
{
name = prependPercent(name);
return gEvalState.getCurrentFrame().lookup(StringTable->insert(name));
}
Dictionary::Entry *getVariableEntry(const char *name)
{
name = prependDollar(name);
gEvalState.globalVars.setVariable(StringTable->insert(name), value);
return gEvalState.globalVars.lookup(StringTable->insert(name));
}
Dictionary::Entry *addVariableEntry(const char *name)
{
name = prependDollar(name);
return gEvalState.globalVars.add(StringTable->insert(name));
}
Dictionary::Entry *getAddVariableEntry(const char *name)
{
name = prependDollar(name);
StringTableEntry stName = StringTable->insert(name);
Dictionary::Entry *entry = gEvalState.globalVars.lookup(stName);
if (!entry)
entry = gEvalState.globalVars.add(stName);
return entry;
}
Dictionary::Entry *getAddLocalVariableEntry(const char *name)
{
name = prependPercent(name);
StringTableEntry stName = StringTable->insert(name);
Dictionary::Entry *entry = gEvalState.getCurrentFrame().lookup(stName);
if (!entry)
entry = gEvalState.getCurrentFrame().add(stName);
return entry;
}
void setVariable(const char *name, const char *value)
{
SimObject *obj = NULL;
const char *objField = NULL;
if (getVariableObjectField(name, &obj, &objField))
{
obj->setDataField(StringTable->insert(objField), 0, value);
}
else
{
name = prependDollar(name);
gEvalState.globalVars.setVariable(StringTable->insert(name), value);
}
}
void setLocalVariable(const char *name, const char *value)
@ -760,21 +817,57 @@ void setLocalVariable(const char *name, const char *value)
void setBoolVariable(const char *varName, bool value)
{
setVariable(varName, value ? "1" : "0");
SimObject *obj = NULL;
const char *objField = NULL;
if (getVariableObjectField(varName, &obj, &objField))
{
obj->setDataField(StringTable->insert(objField), 0, value ? "1" : "0");
}
else
{
varName = prependDollar(varName);
Dictionary::Entry *entry = getAddVariableEntry(varName);
entry->setStringValue(value ? "1" : "0");
}
}
void setIntVariable(const char *varName, S32 value)
{
char scratchBuffer[32];
dSprintf(scratchBuffer, sizeof(scratchBuffer), "%d", value);
setVariable(varName, scratchBuffer);
SimObject *obj = NULL;
const char *objField = NULL;
if (getVariableObjectField(varName, &obj, &objField))
{
char scratchBuffer[32];
dSprintf(scratchBuffer, sizeof(scratchBuffer), "%d", value);
obj->setDataField(StringTable->insert(objField), 0, scratchBuffer);
}
else
{
varName = prependDollar(varName);
Dictionary::Entry *entry = getAddVariableEntry(varName);
entry->setIntValue(value);
}
}
void setFloatVariable(const char *varName, F32 value)
{
char scratchBuffer[32];
dSprintf(scratchBuffer, sizeof(scratchBuffer), "%g", value);
setVariable(varName, scratchBuffer);
SimObject *obj = NULL;
const char *objField = NULL;
if (getVariableObjectField(varName, &obj, &objField))
{
char scratchBuffer[32];
dSprintf(scratchBuffer, sizeof(scratchBuffer), "%g", value);
obj->setDataField(StringTable->insert(objField), 0, scratchBuffer);
}
else
{
varName = prependDollar(varName);
Dictionary::Entry *entry = getAddVariableEntry(varName);
entry->setFloatValue(value);
}
}
//---------------------------------------------------------------------------
@ -825,13 +918,14 @@ void stripColorChars(char* line)
}
}
const char *getVariable(const char *name)
//
const char *getObjectTokenField(const char *name)
{
// get the field info from the object..
if(name[0] != '$' && dStrchr(name, '.') && !isFunction(name))
const char *dot = dStrchr(name, '.');
if(name[0] != '$' && dot)
{
S32 len = dStrlen(name);
AssertFatal(len < sizeof(scratchBuffer)-1, "Sim::getVariable - name too long");
AssertFatal(len < sizeof(scratchBuffer)-1, "Sim::getVariable - object name too long");
dMemcpy(scratchBuffer, name, len+1);
char * token = dStrtok(scratchBuffer, ".");
@ -861,8 +955,21 @@ const char *getVariable(const char *name)
}
}
name = prependDollar(name);
return gEvalState.globalVars.getVariable(StringTable->insert(name));
return NULL;
}
const char *getVariable(const char *name)
{
const char *objField = getObjectTokenField(name);
if (objField)
{
return objField;
}
else
{
Dictionary::Entry *entry = getVariableEntry(name);
return entry ? entry->getStringValue() : "";
}
}
const char *getLocalVariable(const char *name)
@ -874,20 +981,45 @@ const char *getLocalVariable(const char *name)
bool getBoolVariable(const char *varName, bool def)
{
const char *value = getVariable(varName);
return *value ? dAtob(value) : def;
const char *objField = getObjectTokenField(varName);
if (objField)
{
return *objField ? dAtob(objField) : def;
}
else
{
Dictionary::Entry *entry = getVariableEntry(varName);
objField = entry ? entry->getStringValue() : "";
return *objField ? dAtob(objField) : def;
}
}
S32 getIntVariable(const char *varName, S32 def)
{
const char *value = getVariable(varName);
return *value ? dAtoi(value) : def;
const char *objField = getObjectTokenField(varName);
if (objField)
{
return *objField ? dAtoi(objField) : def;
}
else
{
Dictionary::Entry *entry = getVariableEntry(varName);
return entry ? entry->getIntValue() : def;
}
}
F32 getFloatVariable(const char *varName, F32 def)
{
const char *value = getVariable(varName);
return *value ? dAtof(value) : def;
const char *objField = getObjectTokenField(varName);
if (objField)
{
return *objField ? dAtof(objField) : def;
}
else
{
Dictionary::Entry *entry = getVariableEntry(varName);
return entry ? entry->getFloatValue() : def;
}
}
//---------------------------------------------------------------------------
@ -1032,7 +1164,7 @@ const char *evaluatef(const char* string, ...)
return newCodeBlock->compileExec(NULL, buffer, false, 0);
}
const char *execute(S32 argc, const char *argv[])
const char *execute(S32 argc, ConsoleValueRef argv[])
{
#ifdef TORQUE_MULTITHREAD
if(isMainThread())
@ -1044,10 +1176,11 @@ const char *execute(S32 argc, const char *argv[])
if(!ent)
{
warnf(ConsoleLogEntry::Script, "%s: Unknown command.", argv[0]);
warnf(ConsoleLogEntry::Script, "%s: Unknown command.", (const char*)argv[0]);
// Clean up arg buffers, if any.
STR.clearFunctionOffset();
CSTK.resetFrame();
return "";
}
return ent->execute(argc, argv, &gEvalState);
@ -1064,10 +1197,15 @@ const char *execute(S32 argc, const char *argv[])
#endif
}
//------------------------------------------------------------------------------
const char *execute(SimObject *object, S32 argc, const char *argv[], bool thisCallOnly)
const char *execute(S32 argc, const char *argv[])
{
StringStackConsoleWrapper args(argc, argv);
return execute(args.count(), args);
}
//------------------------------------------------------------------------------
const char *execute(SimObject *object, S32 argc, ConsoleValueRef argv[], bool thisCallOnly)
{
static char idBuf[16];
if(argc < 2)
return "";
@ -1078,13 +1216,21 @@ const char *execute(SimObject *object, S32 argc, const char *argv[], bool thisCa
{
ICallMethod *com = dynamic_cast<ICallMethod *>(object);
if(com)
{
STR.pushFrame();
CSTK.pushFrame();
com->callMethodArgList(argc, argv, false);
STR.popFrame();
CSTK.popFrame();
}
}
if(object->getNamespace())
{
dSprintf(idBuf, sizeof(idBuf), "%d", object->getId());
argv[1] = idBuf;
ConsoleValueRef internalArgv[StringStack::MaxArgs];
U32 ident = object->getId();
ConsoleValueRef oldIdent = argv[1];
StringTableEntry funcName = StringTable->insert(argv[0]);
Namespace::Entry *ent = object->getNamespace()->lookup(funcName);
@ -1095,13 +1241,12 @@ const char *execute(SimObject *object, S32 argc, const char *argv[], bool thisCa
// Clean up arg buffers, if any.
STR.clearFunctionOffset();
CSTK.resetFrame();
return "";
}
// Twiddle %this argument
const char *oldArg1 = argv[1];
dSprintf(idBuf, sizeof(idBuf), "%d", object->getId());
argv[1] = idBuf;
argv[1] = (S32)ident;
SimObject *save = gEvalState.thisObject;
gEvalState.thisObject = object;
@ -1109,90 +1254,62 @@ const char *execute(SimObject *object, S32 argc, const char *argv[], bool thisCa
gEvalState.thisObject = save;
// Twiddle it back
argv[1] = oldArg1;
argv[1] = oldIdent;
return ret;
}
warnf(ConsoleLogEntry::Script, "Con::execute - %d has no namespace: %s", object->getId(), argv[0]);
warnf(ConsoleLogEntry::Script, "Con::execute - %d has no namespace: %s", object->getId(), (const char*)argv[0]);
return "";
}
#define B( a ) const char* a = NULL
#define A const char*
inline const char*_executef(SimObject *obj, S32 checkArgc, S32 argc,
A a, B(b), B(c), B(d), B(e), B(f), B(g), B(h), B(i), B(j), B(k))
const char *execute(SimObject *object, S32 argc, const char *argv[], bool thisCallOnly)
{
StringStackConsoleWrapper args(argc, argv);
return execute(object, args.count(), args, thisCallOnly);
}
inline const char*_executef(SimObject *obj, S32 checkArgc, S32 argc, ConsoleValueRef *argv)
{
#undef A
#undef B
const U32 maxArg = 12;
AssertWarn(checkArgc == argc, "Incorrect arg count passed to Con::executef(SimObject*)");
AssertFatal(argc <= maxArg - 1, "Too many args passed to Con::_executef(SimObject*). Please update the function to handle more.");
const char* argv[maxArg];
argv[0] = a;
argv[1] = a;
argv[2] = b;
argv[3] = c;
argv[4] = d;
argv[5] = e;
argv[6] = f;
argv[7] = g;
argv[8] = h;
argv[9] = i;
argv[10] = j;
argv[11] = k;
return execute(obj, argc+1, argv);
return execute(obj, argc, argv);
}
#define A const char*
#define A ConsoleValueRef
#define OBJ SimObject* obj
const char *executef(OBJ, A a) { return _executef(obj, 1, 1, a); }
const char *executef(OBJ, A a, A b) { return _executef(obj, 2, 2, a, b); }
const char *executef(OBJ, A a, A b, A c) { return _executef(obj, 3, 3, a, b, c); }
const char *executef(OBJ, A a, A b, A c, A d) { return _executef(obj, 4, 4, a, b, c, d); }
const char *executef(OBJ, A a, A b, A c, A d, A e) { return _executef(obj, 5, 5, a, b, c, d, e); }
const char *executef(OBJ, A a, A b, A c, A d, A e, A f) { return _executef(obj, 6, 6, a, b, c, d, e, f); }
const char *executef(OBJ, A a, A b, A c, A d, A e, A f, A g) { return _executef(obj, 7, 7, a, b, c, d, e, f, g); }
const char *executef(OBJ, A a, A b, A c, A d, A e, A f, A g, A h) { return _executef(obj, 8, 8, a, b, c, d, e, f, g, h); }
const char *executef(OBJ, A a, A b, A c, A d, A e, A f, A g, A h, A i) { return _executef(obj, 9, 9, a, b, c, d, e, f, g, h, i); }
const char *executef(OBJ, A a, A b, A c, A d, A e, A f, A g, A h, A i, A j) { return _executef(obj,10,10, a, b, c, d, e, f, g, h, i, j); }
const char *executef(OBJ, A a, A b, A c, A d, A e, A f, A g, A h, A i, A j, A k) { return _executef(obj,11,11, a, b, c, d, e, f, g, h, i, j, k); }
#undef A
const char *executef(OBJ, A a) { ConsoleValueRef params[] = {a,ConsoleValueRef()}; return _executef(obj, 2, 2, params); }
const char *executef(OBJ, A a, A b) { ConsoleValueRef params[] = {a,ConsoleValueRef(),b}; return _executef(obj, 3, 3, params); }
const char *executef(OBJ, A a, A b, A c) { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c}; return _executef(obj, 4, 4, params); }
const char *executef(OBJ, A a, A b, A c, A d) { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c,d}; return _executef(obj, 5, 5, params); }
const char *executef(OBJ, A a, A b, A c, A d, A e) { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c,d,e}; return _executef(obj, 6, 6, params); }
const char *executef(OBJ, A a, A b, A c, A d, A e, A f) { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c,d,e,f}; return _executef(obj, 7, 7, params); }
const char *executef(OBJ, A a, A b, A c, A d, A e, A f, A g) { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c,d,e,f,g}; return _executef(obj, 8, 8, params); }
const char *executef(OBJ, A a, A b, A c, A d, A e, A f, A g, A h) { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c,d,e,f,g,h}; return _executef(obj, 9, 9, params); }
const char *executef(OBJ, A a, A b, A c, A d, A e, A f, A g, A h, A i) { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c,d,e,f,g,h,i}; return _executef(obj, 10, 10, params); }
const char *executef(OBJ, A a, A b, A c, A d, A e, A f, A g, A h, A i, A j) { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c,d,e,f,g,h,i,j}; return _executef(obj, 11, 11, params); }
const char *executef(OBJ, A a, A b, A c, A d, A e, A f, A g, A h, A i, A j, A k) { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c,d,e,f,g,h,i,j,k}; return _executef(obj, 12, 12, params); }
//------------------------------------------------------------------------------
#define B( a ) const char* a = NULL
#define A const char*
inline const char*_executef(S32 checkArgc, S32 argc, A a, B(b), B(c), B(d), B(e), B(f), B(g), B(h), B(i), B(j))
inline const char*_executef(S32 checkArgc, S32 argc, ConsoleValueRef *argv)
{
#undef A
#undef B
const U32 maxArg = 10;
AssertFatal(checkArgc == argc, "Incorrect arg count passed to Con::executef()");
AssertFatal(argc <= maxArg, "Too many args passed to Con::_executef(). Please update the function to handle more.");
const char* argv[maxArg];
argv[0] = a;
argv[1] = b;
argv[2] = c;
argv[3] = d;
argv[4] = e;
argv[5] = f;
argv[6] = g;
argv[7] = h;
argv[8] = i;
argv[9] = j;
return execute(argc, argv);
}
#define A const char*
const char *executef(A a) { return _executef(1, 1, a); }
const char *executef(A a, A b) { return _executef(2, 2, a, b); }
const char *executef(A a, A b, A c) { return _executef(3, 3, a, b, c); }
const char *executef(A a, A b, A c, A d) { return _executef(4, 4, a, b, c, d); }
const char *executef(A a, A b, A c, A d, A e) { return _executef(5, 5, a, b, c, d, e); }
const char *executef(A a, A b, A c, A d, A e, A f) { return _executef(6, 6, a, b, c, d, e, f); }
const char *executef(A a, A b, A c, A d, A e, A f, A g) { return _executef(7, 7, a, b, c, d, e, f, g); }
const char *executef(A a, A b, A c, A d, A e, A f, A g, A h) { return _executef(8, 8, a, b, c, d, e, f, g, h); }
const char *executef(A a, A b, A c, A d, A e, A f, A g, A h, A i) { return _executef(9, 9, a, b, c, d, e, f, g, h, i); }
const char *executef(A a, A b, A c, A d, A e, A f, A g, A h, A i, A j) { return _executef(10,10,a, b, c, d, e, f, g, h, i, j); }
#define A ConsoleValueRef
const char *executef(A a) { ConsoleValueRef params[] = {a}; return _executef(1, 1, params); }
const char *executef(A a, A b) { ConsoleValueRef params[] = {a,b}; return _executef(2, 2, params); }
const char *executef(A a, A b, A c) { ConsoleValueRef params[] = {a,b,c}; return _executef(3, 3, params); }
const char *executef(A a, A b, A c, A d) { ConsoleValueRef params[] = {a,b,c,d}; return _executef(4, 4, params); }
const char *executef(A a, A b, A c, A d, A e) { ConsoleValueRef params[] = {a,b,c,d,e}; return _executef(5, 5, params); }
const char *executef(A a, A b, A c, A d, A e, A f) { ConsoleValueRef params[] = {a,b,c,d,e,f}; return _executef(1, 1, params); }
const char *executef(A a, A b, A c, A d, A e, A f, A g) { ConsoleValueRef params[] = {a,b,c,d,e,f,g}; return _executef(1, 1, params); }
const char *executef(A a, A b, A c, A d, A e, A f, A g, A h) { ConsoleValueRef params[] = {a,b,c,d,e,f,g,h}; return _executef(1, 1, params); }
const char *executef(A a, A b, A c, A d, A e, A f, A g, A h, A i) { ConsoleValueRef params[] = {a,b,c,d,e,f,g,h,i}; return _executef(1, 1, params); }
const char *executef(A a, A b, A c, A d, A e, A f, A g, A h, A i, A j) { ConsoleValueRef params[] = {a,b,c,d,e,f,g,h,i,j}; return _executef(1, 1, params); }
#undef A
@ -1313,8 +1430,9 @@ const char *getFormattedData(S32 type, const char *data, const EnumTable *tbl, B
Con::setData(type, variable, 0, 1, &data, tbl, flag);
const char* formattedVal = Con::getData(type, variable, 0, tbl, flag);
char* returnBuffer = Con::getReturnBuffer(2048);
dSprintf(returnBuffer, 2048, "%s\0", formattedVal );
static const U32 bufSize = 2048;
char* returnBuffer = Con::getReturnBuffer(bufSize);
dSprintf(returnBuffer, bufSize, "%s\0", formattedVal );
cbt->deleteNativeVariable(variable);
@ -1389,10 +1507,10 @@ StringTableEntry getModNameFromPath(const char *path)
void postConsoleInput( RawData data )
{
// Schedule this to happen at the next time event.
char *argv[2];
ConsoleValueRef argv[2];
argv[0] = "eval";
argv[1] = ( char* ) data.data;
Sim::postCurrentEvent(Sim::getRootGroup(), new SimConsoleEvent(2, const_cast<const char**>(argv), false));
argv[1] = ( const char* ) data.data;
Sim::postCurrentEvent(Sim::getRootGroup(), new SimConsoleEvent(2, argv, false));
}
//------------------------------------------------------------------------------
@ -1455,3 +1573,247 @@ DefineEngineFunction( logWarning, void, ( const char* message ),,
{
Con::warnf( "%s", message );
}
ConsoleValueRef::ConsoleValueRef(const ConsoleValueRef &ref)
{
value = ref.value;
stringStackValue = ref.stringStackValue;
}
ConsoleValueRef::ConsoleValueRef(const char *newValue) : value(NULL)
{
*this = newValue;
}
ConsoleValueRef::ConsoleValueRef(const String &newValue) : value(NULL)
{
*this = (const char*)(newValue.utf8());
}
ConsoleValueRef::ConsoleValueRef(U32 newValue) : value(NULL)
{
*this = newValue;
}
ConsoleValueRef::ConsoleValueRef(S32 newValue) : value(NULL)
{
*this = newValue;
}
ConsoleValueRef::ConsoleValueRef(F32 newValue) : value(NULL)
{
*this = newValue;
}
ConsoleValueRef::ConsoleValueRef(F64 newValue) : value(NULL)
{
*this = newValue;
}
StringStackWrapper::StringStackWrapper(int targc, ConsoleValueRef targv[])
{
argv = new const char*[targc];
argc = targc;
for (int i=0; i<targc; i++)
{
argv[i] = dStrdup(targv[i]);
}
}
StringStackWrapper::~StringStackWrapper()
{
for (int i=0; i<argc; i++)
{
dFree(argv[i]);
}
delete[] argv;
}
StringStackConsoleWrapper::StringStackConsoleWrapper(int targc, const char** targ)
{
argv = new ConsoleValueRef[targc];
argc = targc;
for (int i=0; i<targc; i++) {
argv[i] = ConsoleValueRef(targ[i]);
}
}
StringStackConsoleWrapper::~StringStackConsoleWrapper()
{
for (int i=0; i<argc; i++)
{
argv[i] = NULL;
}
delete[] argv;
}
S32 ConsoleValue::getSignedIntValue()
{
if(type <= TypeInternalString)
return (S32)fval;
else
return dAtoi(Con::getData(type, dataPtr, 0, enumTable));
}
U32 ConsoleValue::getIntValue()
{
if(type <= TypeInternalString)
return ival;
else
return dAtoi(Con::getData(type, dataPtr, 0, enumTable));
}
F32 ConsoleValue::getFloatValue()
{
if(type <= TypeInternalString)
return fval;
else
return dAtof(Con::getData(type, dataPtr, 0, enumTable));
}
const char *ConsoleValue::getStringValue()
{
if(type == TypeInternalString || type == TypeInternalStackString)
return sval;
if(type == TypeInternalFloat)
return Con::getData(TypeF32, &fval, 0);
else if(type == TypeInternalInt)
return Con::getData(TypeS32, &ival, 0);
else
return Con::getData(type, dataPtr, 0, enumTable);
}
bool ConsoleValue::getBoolValue()
{
if(type == TypeInternalString || type == TypeInternalStackString)
return dAtob(sval);
if(type == TypeInternalFloat)
return fval > 0;
else if(type == TypeInternalInt)
return ival > 0;
else {
const char *value = Con::getData(type, dataPtr, 0, enumTable);
return dAtob(value);
}
}
void ConsoleValue::setIntValue(S32 val)
{
setFloatValue(val);
}
void ConsoleValue::setIntValue(U32 val)
{
if(type <= TypeInternalString)
{
fval = (F32)val;
ival = val;
if(sval != typeValueEmpty)
{
if (type != TypeInternalStackString) dFree(sval);
sval = typeValueEmpty;
}
type = TypeInternalInt;
}
else
{
const char *dptr = Con::getData(TypeS32, &val, 0);
Con::setData(type, dataPtr, 0, 1, &dptr, enumTable);
}
}
void ConsoleValue::setBoolValue(bool val)
{
return setIntValue(val ? 1 : 0);
}
void ConsoleValue::setFloatValue(F32 val)
{
if(type <= TypeInternalString)
{
fval = val;
ival = static_cast<U32>(val);
if(sval != typeValueEmpty)
{
if (type != TypeInternalStackString) dFree(sval);
sval = typeValueEmpty;
}
type = TypeInternalFloat;
}
else
{
const char *dptr = Con::getData(TypeF32, &val, 0);
Con::setData(type, dataPtr, 0, 1, &dptr, enumTable);
}
}
const char *ConsoleValueRef::getStringArgValue()
{
if (value)
{
if (stringStackValue == NULL)
stringStackValue = Con::getStringArg(value->getStringValue());
return stringStackValue;
}
else
{
return "";
}
}
extern ConsoleValueStack CSTK;
ConsoleValueRef& ConsoleValueRef::operator=(const ConsoleValueRef &newValue)
{
value = newValue.value;
stringStackValue = newValue.stringStackValue;
return *this;
}
ConsoleValueRef& ConsoleValueRef::operator=(const char *newValue)
{
value = CSTK.pushStackString(newValue);
stringStackValue = NULL;
return *this;
}
ConsoleValueRef& ConsoleValueRef::operator=(S32 newValue)
{
value = CSTK.pushFLT(newValue);
stringStackValue = NULL;
return *this;
}
ConsoleValueRef& ConsoleValueRef::operator=(U32 newValue)
{
value = CSTK.pushUINT(newValue);
stringStackValue = NULL;
return *this;
}
ConsoleValueRef& ConsoleValueRef::operator=(F32 newValue)
{
value = CSTK.pushFLT(newValue);
stringStackValue = NULL;
return *this;
}
ConsoleValueRef& ConsoleValueRef::operator=(F64 newValue)
{
value = CSTK.pushFLT(newValue);
stringStackValue = NULL;
return *this;
}
namespace Con
{
void resetStackFrame()
{
CSTK.resetFrame();
}
}

View file

@ -29,15 +29,18 @@
#ifndef _BITSET_H_
#include "core/bitSet.h"
#endif
#ifndef _REFBASE_H_
#include "core/util/refBase.h"
#endif
#include <stdarg.h>
#include "core/util/str.h"
#include "core/util/journal/journaledSignal.h"
class SimObject;
class Namespace;
struct ConsoleFunctionHeader;
class EngineEnumTable;
typedef EngineEnumTable EnumTable;
@ -110,6 +113,185 @@ struct ConsoleLogEntry
};
typedef const char *StringTableEntry;
extern char *typeValueEmpty;
class ConsoleValue
{
public:
enum
{
TypeInternalInt = -4,
TypeInternalFloat = -3,
TypeInternalStackString = -2,
TypeInternalString = -1,
};
S32 type;
public:
// NOTE: This is protected to ensure no one outside
// of this structure is messing with it.
#pragma warning( push )
#pragma warning( disable : 4201 ) // warning C4201: nonstandard extension used : nameless struct/union
// An variable is either a real dynamic type or
// its one exposed from C++ using a data pointer.
//
// We use this nameless union and struct setup
// to optimize the memory usage.
union
{
struct
{
char *sval;
U32 ival; // doubles as strlen when type is TypeInternalString
F32 fval;
U32 bufferLen;
};
struct
{
/// The real data pointer.
void *dataPtr;
/// The enum lookup table for enumerated types.
const EnumTable *enumTable;
};
};
U32 getIntValue();
S32 getSignedIntValue();
F32 getFloatValue();
const char *getStringValue();
bool getBoolValue();
void setIntValue(U32 val);
void setIntValue(S32 val);
void setFloatValue(F32 val);
void setStringValue(const char *value);
void setStackStringValue(const char *value);
void setBoolValue(bool val);
void init()
{
ival = 0;
fval = 0;
sval = typeValueEmpty;
bufferLen = 0;
}
void cleanup()
{
if (type <= TypeInternalString &&
sval != typeValueEmpty && type != TypeInternalStackString )
dFree(sval);
sval = typeValueEmpty;
type = ConsoleValue::TypeInternalString;
ival = 0;
fval = 0;
bufferLen = 0;
}
};
// Proxy class for console variables
// Can point to existing console variables,
// or act like a free floating value.
class ConsoleValueRef
{
public:
ConsoleValue *value;
const char *stringStackValue;
ConsoleValueRef() : value(0), stringStackValue(0) { ; }
~ConsoleValueRef() { ; }
ConsoleValueRef(const ConsoleValueRef &ref);
ConsoleValueRef(const char *value);
ConsoleValueRef(const String &ref);
ConsoleValueRef(U32 value);
ConsoleValueRef(S32 value);
ConsoleValueRef(F32 value);
ConsoleValueRef(F64 value);
const char *getStringValue() { return value ? value->getStringValue() : ""; }
const char *getStringArgValue();
inline U32 getIntValue() { return value ? value->getIntValue() : 0; }
inline S32 getSignedIntValue() { return value ? value->getSignedIntValue() : 0; }
inline F32 getFloatValue() { return value ? value->getFloatValue() : 0.0f; }
inline bool getBoolValue() { return value ? value->getBoolValue() : false; }
inline operator const char*() { return getStringValue(); }
inline operator String() { return String(getStringValue()); }
inline operator U32() { return getIntValue(); }
inline operator S32() { return getSignedIntValue(); }
inline operator F32() { return getFloatValue(); }
inline bool isString() { return value ? value->type >= ConsoleValue::TypeInternalStackString : true; }
inline bool isInt() { return value ? value->type == ConsoleValue::TypeInternalInt : false; }
inline bool isFloat() { return value ? value->type == ConsoleValue::TypeInternalFloat : false; }
// Note: operators replace value
ConsoleValueRef& operator=(const ConsoleValueRef &other);
ConsoleValueRef& operator=(const char *newValue);
ConsoleValueRef& operator=(U32 newValue);
ConsoleValueRef& operator=(S32 newValue);
ConsoleValueRef& operator=(F32 newValue);
ConsoleValueRef& operator=(F64 newValue);
};
// Overrides to allow ConsoleValueRefs to be directly converted to S32&F32
inline S32 dAtoi(ConsoleValueRef &ref)
{
return ref.getSignedIntValue();
}
inline F32 dAtof(ConsoleValueRef &ref)
{
return ref.getFloatValue();
}
inline bool dAtob(ConsoleValue &ref)
{
return ref.getBoolValue();
}
// Transparently converts ConsoleValue[] to const char**
class StringStackWrapper
{
public:
const char **argv;
int argc;
StringStackWrapper(int targc, ConsoleValueRef targv[]);
~StringStackWrapper();
const char* operator[](int idx) { return argv[idx]; }
operator const char**() { return argv; }
int count() { return argc; }
};
// Transparently converts const char** to ConsoleValue
class StringStackConsoleWrapper
{
public:
ConsoleValueRef *argv;
int argc;
StringStackConsoleWrapper(int targc, const char **targv);
~StringStackConsoleWrapper();
ConsoleValueRef& operator[](int idx) { return argv[idx]; }
operator ConsoleValueRef*() { return argv; }
int count() { return argc; }
};
/// @defgroup console_callbacks Scripting Engine Callbacks
///
@ -129,11 +311,11 @@ typedef const char *StringTableEntry;
/// @{
///
typedef const char * (*StringCallback)(SimObject *obj, S32 argc, const char *argv[]);
typedef S32 (*IntCallback)(SimObject *obj, S32 argc, const char *argv[]);
typedef F32 (*FloatCallback)(SimObject *obj, S32 argc, const char *argv[]);
typedef void (*VoidCallback)(SimObject *obj, S32 argc, const char *argv[]); // We have it return a value so things don't break..
typedef bool (*BoolCallback)(SimObject *obj, S32 argc, const char *argv[]);
typedef const char * (*StringCallback)(SimObject *obj, S32 argc, ConsoleValueRef argv[]);
typedef S32 (*IntCallback)(SimObject *obj, S32 argc, ConsoleValueRef argv[]);
typedef F32 (*FloatCallback)(SimObject *obj, S32 argc, ConsoleValueRef argv[]);
typedef void (*VoidCallback)(SimObject *obj, S32 argc, ConsoleValueRef argv[]); // We have it return a value so things don't break..
typedef bool (*BoolCallback)(SimObject *obj, S32 argc, ConsoleValueRef argv[]);
typedef void (*ConsumerCallback)(U32 level, const char *consoleLine);
/// @}
@ -182,7 +364,9 @@ namespace Con
/// 09/12/07 - CAF - 43->44 remove newmsg operator
/// 09/27/07 - RDB - 44->45 Patch from Andreas Kirsch: Added opcode to support correct void return
/// 01/13/09 - TMS - 45->46 Added script assert
DSOVersion = 46,
/// 09/07/14 - jamesu - 46->47 64bit support
/// 10/14/14 - jamesu - 47->48 Added opcodes to reduce reliance on strings in function calls
DSOVersion = 48,
MaxLineLength = 512, ///< Maximum length of a line of console input.
MaxDataTypes = 256 ///< Maximum number of registered data types.
@ -415,6 +599,11 @@ namespace Con
/// @return The string value of the variable or "" if the variable does not exist.
const char* getVariable(const char* name);
/// Retrieve the string value of an object field
/// @param name "object.field" string to query
/// @return The string value of the variable or NULL if no object is specified
const char* getObjectField(const char* name);
/// Same as setVariable(), but for bools.
void setBoolVariable (const char* name,bool var);
@ -565,9 +754,11 @@ namespace Con
/// char* result = execute(2, argv);
/// @endcode
const char *execute(S32 argc, const char* argv[]);
const char *execute(S32 argc, ConsoleValueRef argv[]);
/// @see execute(S32 argc, const char* argv[])
#define ARG const char*
// Note: this can't be ConsoleValueRef& since the compiler will confuse it with SimObject*
#define ARG ConsoleValueRef
const char *executef( ARG);
const char *executef( ARG, ARG);
const char *executef( ARG, ARG, ARG);
@ -580,7 +771,6 @@ namespace Con
const char *executef( ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG);
#undef ARG
/// Call a Torque Script member function of a SimObject from C/C++ code.
/// @param object Object on which to execute the method call.
/// @param argc Number of elements in the argv parameter (must be >2, see argv)
@ -594,9 +784,10 @@ namespace Con
/// char* result = execute(mysimobject, 3, argv);
/// @endcode
const char *execute(SimObject *object, S32 argc, const char *argv[], bool thisCallOnly = false);
const char *execute(SimObject *object, S32 argc, ConsoleValueRef argv[], bool thisCallOnly = false);
/// @see execute(SimObject *, S32 argc, const char *argv[])
#define ARG const char*
/// @see execute(SimObject *, S32 argc, ConsoleValueRef argv[])
#define ARG ConsoleValueRef
const char *executef(SimObject *, ARG);
const char *executef(SimObject *, ARG, ARG);
const char *executef(SimObject *, ARG, ARG, ARG);
@ -640,12 +831,14 @@ namespace Con
char* getReturnBuffer( const StringBuilder& str );
char* getArgBuffer(U32 bufferSize);
char* getFloatArg(F64 arg);
char* getIntArg (S32 arg);
ConsoleValueRef getFloatArg(F64 arg);
ConsoleValueRef getIntArg (S32 arg);
char* getStringArg( const char *arg );
char* getStringArg( const String& arg );
/// @}
void resetStackFrame();
/// @name Namespaces
/// @{
@ -696,7 +889,7 @@ namespace Con
extern void expandEscape(char *dest, const char *src);
extern bool collapseEscape(char *buf);
extern S32 HashPointer(StringTableEntry ptr);
extern U32 HashPointer(StringTableEntry ptr);
/// Extended information about a console function.
@ -941,14 +1134,14 @@ struct ConsoleDocFragment
static ConsoleConstructor cfg_ConsoleFunctionGroup_##groupName##_GroupBegin(NULL,#groupName,usage)
# define ConsoleFunction(name,returnType,minArgs,maxArgs,usage1) \
returnType cf_##name(SimObject *, S32, const char **argv); \
returnType cf_##name(SimObject *, S32, ConsoleValueRef *argv); \
ConsoleConstructor cc_##name##_obj(NULL,#name,cf_##name,usage1,minArgs,maxArgs); \
returnType cf_##name(SimObject *, S32 argc, const char **argv)
returnType cf_##name(SimObject *, S32 argc, ConsoleValueRef *argv)
# define ConsoleToolFunction(name,returnType,minArgs,maxArgs,usage1) \
returnType ctf_##name(SimObject *, S32, const char **argv); \
returnType ctf_##name(SimObject *, S32, ConsoleValueRef *argv); \
ConsoleConstructor cc_##name##_obj(NULL,#name,ctf_##name,usage1,minArgs,maxArgs, true); \
returnType ctf_##name(SimObject *, S32 argc, const char **argv)
returnType ctf_##name(SimObject *, S32 argc, ConsoleValueRef *argv)
# define ConsoleFunctionGroupEnd(groupName) \
static ConsoleConstructor cfg_##groupName##_GroupEnd(NULL,#groupName,NULL)
@ -961,22 +1154,22 @@ struct ConsoleDocFragment
static ConsoleConstructor cc_##className##_##groupName##_GroupBegin(#className,#groupName,usage)
# define ConsoleMethod(className,name,returnType,minArgs,maxArgs,usage1) \
inline returnType cm_##className##_##name(className *, S32, const char **argv); \
returnType cm_##className##_##name##_caster(SimObject *object, S32 argc, const char **argv) { \
inline returnType cm_##className##_##name(className *, S32, ConsoleValueRef *argv); \
returnType cm_##className##_##name##_caster(SimObject *object, S32 argc, ConsoleValueRef *argv) { \
AssertFatal( dynamic_cast<className*>( object ), "Object passed to " #name " is not a " #className "!" ); \
conmethod_return_##returnType ) cm_##className##_##name(static_cast<className*>(object),argc,argv); \
}; \
ConsoleConstructor cc_##className##_##name##_obj(#className,#name,cm_##className##_##name##_caster,usage1,minArgs,maxArgs); \
inline returnType cm_##className##_##name(className *object, S32 argc, const char **argv)
inline returnType cm_##className##_##name(className *object, S32 argc, ConsoleValueRef *argv)
# define ConsoleStaticMethod(className,name,returnType,minArgs,maxArgs,usage1) \
inline returnType cm_##className##_##name(S32, const char **); \
returnType cm_##className##_##name##_caster(SimObject *object, S32 argc, const char **argv) { \
inline returnType cm_##className##_##name(S32, ConsoleValueRef *); \
returnType cm_##className##_##name##_caster(SimObject *object, S32 argc, ConsoleValueRef *argv) { \
conmethod_return_##returnType ) cm_##className##_##name(argc,argv); \
}; \
ConsoleConstructor \
cc_##className##_##name##_obj(#className,#name,cm_##className##_##name##_caster,usage1,minArgs,maxArgs); \
inline returnType cm_##className##_##name(S32 argc, const char **argv)
inline returnType cm_##className##_##name(S32 argc, ConsoleValueRef *argv)
# define ConsoleMethodGroupEnd(className, groupName) \
static ConsoleConstructor cc_##className##_##groupName##_GroupEnd(#className,#groupName,NULL)
@ -999,32 +1192,32 @@ struct ConsoleDocFragment
// These are identical to what's above, we just want to null out the usage strings.
# define ConsoleFunction(name,returnType,minArgs,maxArgs,usage1) \
static returnType c##name(SimObject *, S32, const char **); \
static returnType c##name(SimObject *, S32, ConsoleValueRef*); \
static ConsoleConstructor g##name##obj(NULL,#name,c##name,"",minArgs,maxArgs);\
static returnType c##name(SimObject *, S32 argc, const char **argv)
static returnType c##name(SimObject *, S32 argc, ConsoleValueRef *argv)
# define ConsoleToolFunction(name,returnType,minArgs,maxArgs,usage1) \
static returnType c##name(SimObject *, S32, const char **); \
static returnType c##name(SimObject *, S32, ConsoleValueRef*); \
static ConsoleConstructor g##name##obj(NULL,#name,c##name,"",minArgs,maxArgs, true);\
static returnType c##name(SimObject *, S32 argc, const char **argv)
static returnType c##name(SimObject *, S32 argc, ConsoleValueRef *argv)
# define ConsoleMethod(className,name,returnType,minArgs,maxArgs,usage1) \
static inline returnType c##className##name(className *, S32, const char **argv); \
static returnType c##className##name##caster(SimObject *object, S32 argc, const char **argv) { \
static inline returnType c##className##name(className *, S32, ConsoleValueRef *argv); \
static returnType c##className##name##caster(SimObject *object, S32 argc, ConsoleValueRef *argv) { \
conmethod_return_##returnType ) c##className##name(static_cast<className*>(object),argc,argv); \
}; \
static ConsoleConstructor \
className##name##obj(#className,#name,c##className##name##caster,"",minArgs,maxArgs); \
static inline returnType c##className##name(className *object, S32 argc, const char **argv)
static inline returnType c##className##name(className *object, S32 argc, ConsoleValueRef *argv)
# define ConsoleStaticMethod(className,name,returnType,minArgs,maxArgs,usage1) \
static inline returnType c##className##name(S32, const char **); \
static returnType c##className##name##caster(SimObject *object, S32 argc, const char **argv) { \
static inline returnType c##className##name(S32, ConsoleValueRef*); \
static returnType c##className##name##caster(SimObject *object, S32 argc, ConsoleValueRef *argv) { \
conmethod_return_##returnType ) c##className##name(argc,argv); \
}; \
static ConsoleConstructor \
className##name##obj(#className,#name,c##className##name##caster,"",minArgs,maxArgs); \
static inline returnType c##className##name(S32 argc, const char **argv)
static inline returnType c##className##name(S32 argc, ConsoleValueRef *argv)
#define ConsoleDoc( text )

View file

@ -75,7 +75,8 @@ DefineConsoleFunction( strformat, const char*, ( const char* format, const char*
"@ingroup Strings\n"
"@see http://en.wikipedia.org/wiki/Printf" )
{
char* pBuffer = Con::getReturnBuffer(64);
static const U32 bufSize = 64;
char* pBuffer = Con::getReturnBuffer(bufSize);
const char *pch = format;
pBuffer[0] = '\0';
@ -99,7 +100,7 @@ DefineConsoleFunction( strformat, const char*, ( const char* format, const char*
case 'u':
case 'x':
case 'X':
dSprintf( pBuffer, 64, format, dAtoi( value ) );
dSprintf( pBuffer, bufSize, format, dAtoi( value ) );
break;
case 'e':
@ -107,7 +108,7 @@ DefineConsoleFunction( strformat, const char*, ( const char* format, const char*
case 'f':
case 'g':
case 'G':
dSprintf( pBuffer, 64, format, dAtof( value ) );
dSprintf( pBuffer, bufSize, format, dAtof( value ) );
break;
default:
@ -1206,7 +1207,9 @@ ConsoleFunction( nextToken, const char *, 4, 4, "( string str, string token, str
"@endtsexample\n\n"
"@ingroup Strings" )
{
char *str = (char *) argv[1];
char buffer[4096];
dStrncpy(buffer, argv[1], 4096);
char *str = buffer;
const char *token = argv[2];
const char *delim = argv[3];
@ -1239,7 +1242,9 @@ ConsoleFunction( nextToken, const char *, 4, 4, "( string str, string token, str
str++;
}
return str;
char *ret = Con::getReturnBuffer(dStrlen(str)+1);
dStrncpy(ret, str, dStrlen(str)+1);
return ret;
}
//=============================================================================
@ -1301,16 +1306,17 @@ ConsoleFunction(getTag, const char *, 2, 2, "(string textTagString)"
TORQUE_UNUSED(argc);
if(argv[1][0] == StringTagPrefixByte)
{
const char *arg = argv[1];
const char * space = dStrchr(argv[1], ' ');
U32 len;
if(space)
len = space - argv[1];
len = space - arg;
else
len = dStrlen(argv[1]) + 1;
len = dStrlen(arg) + 1;
char * ret = Con::getReturnBuffer(len);
dStrncpy(ret, argv[1] + 1, len - 1);
dStrncpy(ret, arg + 1, len - 1);
ret[len - 1] = 0;
return(ret);
@ -1516,11 +1522,12 @@ ConsoleFunction( realQuit, void, 1, 1, "" )
//-----------------------------------------------------------------------------
DefineConsoleFunction( quitWithErrorMessage, void, ( const char* message ),,
DefineConsoleFunction( quitWithErrorMessage, void, ( const char* message, S32 status ), (0),
"Display an error message box showing the given @a message and then shut down the engine and exit its process.\n"
"This function cleanly uninitialized the engine and then exits back to the system with a process "
"exit status indicating an error.\n\n"
"@param message The message to log to the console and show in an error message box.\n\n"
"@param message The message to log to the console and show in an error message box.\n"
"@param status The status code to return to the OS.\n\n"
"@see quit\n\n"
"@ingroup Platform" )
{
@ -1531,7 +1538,20 @@ DefineConsoleFunction( quitWithErrorMessage, void, ( const char* message ),,
// as the script code should not be allowed to pretty much hard-crash the engine
// and prevent proper shutdown. Changed this to use postQuitMessage.
Platform::postQuitMessage( -1 );
Platform::postQuitMessage( status );
}
//-----------------------------------------------------------------------------
DefineConsoleFunction( quitWithStatus, void, ( S32 status ), (0),
"Shut down the engine and exit its process.\n"
"This function cleanly uninitializes the engine and then exits back to the system with a given "
"return status code.\n\n"
"@param status The status code to return to the OS.\n\n"
"@see quitWithErrorMessage\n\n"
"@ingroup Platform" )
{
Platform::postQuitMessage(status);
}
//-----------------------------------------------------------------------------
@ -1588,6 +1608,13 @@ DefineEngineFunction( displaySplashWindow, bool, (const char* path), ("art/gui/s
return Platform::displaySplashWindow(path);
}
DefineEngineFunction( closeSplashWindow, void, (),,
"Close our startup splash window.\n\n"
"@note This is currently only implemented on Windows.\n\n"
"@ingroup Platform" )
{
Platform::closeSplashWindow();
}
//-----------------------------------------------------------------------------
DefineEngineFunction( getWebDeployment, bool, (),,
@ -2360,7 +2387,7 @@ ConsoleFunction(isDefined, bool, 2, 3, "(string varName)"
if (dStrcmp(argv[1], "0") && dStrcmp(argv[1], "") && (Sim::findObject(argv[1]) != NULL))
return true;
else if (argc > 2)
Con::errorf("%s() - can't assign a value to a variable of the form \"%s\"", __FUNCTION__, argv[1]);
Con::errorf("%s() - can't assign a value to a variable of the form \"%s\"", __FUNCTION__, (const char*)argv[1]);
}
return false;
@ -2395,7 +2422,7 @@ ConsoleFunction( pushInstantGroup, void, 1, 2, "([group])"
"@internal")
{
if( argc > 1 )
Con::pushInstantGroup( argv[ 1 ] );
Con::pushInstantGroup( (const char*)argv[ 1 ] );
else
Con::pushInstantGroup();
}
@ -2415,7 +2442,7 @@ ConsoleFunction(getPrefsPath, const char *, 1, 2, "([relativeFileName])"
"@note Appears to be useless in Torque 3D, should be deprecated\n"
"@internal")
{
const char *filename = Platform::getPrefsPath(argc > 1 ? argv[1] : NULL);
const char *filename = Platform::getPrefsPath(argc > 1 ? (const char*)argv[1] : NULL);
if(filename == NULL || *filename == 0)
return "";

View file

@ -34,7 +34,6 @@
//#define DEBUG_SPEW
#define ST_INIT_SIZE 15
static char scratchBuffer[1024];
@ -168,13 +167,13 @@ void Dictionary::exportVariables(const char *varString, const char *fileName, bo
for(s = sortList.begin(); s != sortList.end(); s++)
{
switch((*s)->type)
switch((*s)->value.type)
{
case Entry::TypeInternalInt:
dSprintf(buffer, sizeof(buffer), "%s = %d;%s", (*s)->name, (*s)->ival, cat);
case ConsoleValue::TypeInternalInt:
dSprintf(buffer, sizeof(buffer), "%s = %d;%s", (*s)->name, (*s)->value.ival, cat);
break;
case Entry::TypeInternalFloat:
dSprintf(buffer, sizeof(buffer), "%s = %g;%s", (*s)->name, (*s)->fval, cat);
case ConsoleValue::TypeInternalFloat:
dSprintf(buffer, sizeof(buffer), "%s = %g;%s", (*s)->name, (*s)->value.fval, cat);
break;
default:
expandEscape(expandBuffer, (*s)->getStringValue());
@ -228,13 +227,13 @@ void Dictionary::exportVariables( const char *varString, Vector<String> *names,
if ( values )
{
switch ( (*s)->type )
switch ( (*s)->value.type )
{
case Entry::TypeInternalInt:
values->push_back( String::ToString( (*s)->ival ) );
case ConsoleValue::TypeInternalInt:
values->push_back( String::ToString( (*s)->value.ival ) );
break;
case Entry::TypeInternalFloat:
values->push_back( String::ToString( (*s)->fval ) );
case ConsoleValue::TypeInternalFloat:
values->push_back( String::ToString( (*s)->value.fval ) );
break;
default:
expandEscape( expandBuffer, (*s)->getStringValue() );
@ -262,9 +261,9 @@ void Dictionary::deleteVariables(const char *varString)
}
}
S32 HashPointer(StringTableEntry ptr)
U32 HashPointer(StringTableEntry ptr)
{
return (S32)(((dsize_t)ptr) >> 2);
return (U32)(((dsize_t)ptr) >> 2);
}
Dictionary::Entry *Dictionary::lookup(StringTableEntry name)
@ -284,6 +283,7 @@ Dictionary::Entry *Dictionary::lookup(StringTableEntry name)
Dictionary::Entry *Dictionary::add(StringTableEntry name)
{
// Try to find an existing match.
//printf("Add Variable %s\n", name);
Entry* ret = lookup( name );
if( ret )
@ -307,7 +307,7 @@ Dictionary::Entry *Dictionary::add(StringTableEntry name)
for( Entry* entry = hashTable->data[ i ]; entry != NULL; )
{
Entry* next = entry->nextEntry;
S32 index = HashPointer( entry->name ) % newTableSize;
U32 index = HashPointer( entry->name ) % newTableSize;
entry->nextEntry = newTableData[ index ];
newTableData[ index ] = entry;
@ -330,7 +330,7 @@ Dictionary::Entry *Dictionary::add(StringTableEntry name)
ret = hashTable->mChunker.alloc();
constructInPlace( ret, name );
S32 idx = HashPointer(name) % hashTable->size;
U32 idx = HashPointer(name) % hashTable->size;
ret->nextEntry = hashTable->data[idx];
hashTable->data[idx] = ret;
@ -454,7 +454,7 @@ char *typeValueEmpty = "";
Dictionary::Entry::Entry(StringTableEntry in_name)
{
name = in_name;
type = TypeInternalString;
value.type = ConsoleValue::TypeInternalString;
notify = NULL;
nextEntry = NULL;
mUsage = NULL;
@ -462,17 +462,12 @@ Dictionary::Entry::Entry(StringTableEntry in_name)
// NOTE: This is data inside a nameless
// union, so we don't need to init the rest.
ival = 0;
fval = 0;
sval = typeValueEmpty;
bufferLen = 0;
value.init();
}
Dictionary::Entry::~Entry()
{
if ( type <= TypeInternalString &&
sval != typeValueEmpty )
dFree(sval);
value.cleanup();
if ( notify )
delete notify;
@ -497,15 +492,11 @@ const char *Dictionary::getVariable(StringTableEntry name, bool *entValid)
return "";
}
void Dictionary::Entry::setStringValue(const char * value)
void ConsoleValue::setStringValue(const char * value)
{
if( mIsConstant )
{
Con::errorf( "Cannot assign value to constant '%s'.", name );
return;
}
if (value == NULL) value = typeValueEmpty;
if(type <= TypeInternalString)
if(type <= ConsoleValue::TypeInternalString)
{
// Let's not remove empty-string-valued global vars from the dict.
// If we remove them, then they won't be exported, and sometimes
@ -519,6 +510,16 @@ void Dictionary::Entry::setStringValue(const char * value)
return;
}
*/
if (value == typeValueEmpty)
{
if (sval && sval != typeValueEmpty && type != TypeInternalStackString) dFree(sval);
sval = typeValueEmpty;
bufferLen = 0;
fval = 0.f;
ival = 0;
type = TypeInternalString;
return;
}
U32 stringLen = dStrlen(value);
@ -537,25 +538,92 @@ void Dictionary::Entry::setStringValue(const char * value)
ival = 0;
}
type = TypeInternalString;
// may as well pad to the next cache line
U32 newLen = ((stringLen + 1) + 15) & ~15;
if(sval == typeValueEmpty)
if(sval == typeValueEmpty || type == TypeInternalStackString)
sval = (char *) dMalloc(newLen);
else if(newLen > bufferLen)
sval = (char *) dRealloc(sval, newLen);
type = TypeInternalString;
bufferLen = newLen;
dStrcpy(sval, value);
}
else
Con::setData(type, dataPtr, 0, 1, &value, enumTable);
}
// Fire off the notification if we have one.
if ( notify )
notify->trigger();
void ConsoleValue::setStackStringValue(const char * value)
{
if (value == NULL) value = typeValueEmpty;
if(type <= ConsoleValue::TypeInternalString)
{
if (value == typeValueEmpty)
{
if (sval && sval != typeValueEmpty && type != ConsoleValue::TypeInternalStackString) dFree(sval);
sval = typeValueEmpty;
bufferLen = 0;
fval = 0.f;
ival = 0;
type = TypeInternalString;
return;
}
U32 stringLen = dStrlen(value);
if(stringLen < 256)
{
fval = dAtof(value);
ival = dAtoi(value);
}
else
{
fval = 0.f;
ival = 0;
}
type = TypeInternalStackString;
sval = (char*)value;
bufferLen = stringLen;
}
else
Con::setData(type, dataPtr, 0, 1, &value, enumTable);
}
S32 Dictionary::getIntVariable(StringTableEntry name, bool *entValid)
{
Entry *ent = lookup(name);
if(ent)
{
if(entValid)
*entValid = true;
return ent->getIntValue();
}
if(entValid)
*entValid = false;
return 0;
}
F32 Dictionary::getFloatVariable(StringTableEntry name, bool *entValid)
{
Entry *ent = lookup(name);
if(ent)
{
if(entValid)
*entValid = true;
return ent->getFloatValue();
}
if(entValid)
*entValid = false;
return 0;
}
void Dictionary::setVariable(StringTableEntry name, const char *value)
@ -582,19 +650,19 @@ Dictionary::Entry* Dictionary::addVariable( const char *name,
Entry *ent = add(StringTable->insert(name));
if ( ent->type <= Entry::TypeInternalString &&
ent->sval != typeValueEmpty )
dFree(ent->sval);
if ( ent->value.type <= ConsoleValue::TypeInternalString &&
ent->value.sval != typeValueEmpty && ent->value.type != ConsoleValue::TypeInternalStackString )
dFree(ent->value.sval);
ent->type = type;
ent->dataPtr = dataPtr;
ent->value.type = type;
ent->value.dataPtr = dataPtr;
ent->mUsage = usage;
// Fetch enum table, if any.
ConsoleBaseType* conType = ConsoleBaseType::getType( type );
AssertFatal( conType, "Dictionary::addVariable - invalid console type" );
ent->enumTable = conType->getEnumTable();
ent->value.enumTable = conType->getEnumTable();
return ent;
}
@ -616,7 +684,7 @@ void Dictionary::addVariableNotify( const char *name, const Con::NotifyDelegate
return;
if ( !ent->notify )
ent->notify = new Entry::NotifySignal();
ent->notify = new Entry::NotifySignal();
ent->notify->notify( callback );
}
@ -1268,7 +1336,7 @@ void Namespace::markGroup(const char* name, const char* usage)
extern S32 executeBlock(StmtNode *block, ExprEvalState *state);
const char *Namespace::Entry::execute(S32 argc, const char **argv, ExprEvalState *state)
const char *Namespace::Entry::execute(S32 argc, ConsoleValueRef *argv, ExprEvalState *state)
{
if(mType == ConsoleFunctionType)
{

View file

@ -151,7 +151,7 @@ class Namespace
void clear();
///
const char *execute( S32 argc, const char** argv, ExprEvalState* state );
const char *execute( S32 argc, ConsoleValueRef* argv, ExprEvalState* state );
/// Return a one-line documentation text string for the function.
String getBriefDescription( String* outRemainingDocText = NULL ) const;
@ -275,7 +275,7 @@ class Namespace
typedef VectorPtr<Namespace::Entry *>::iterator NamespaceEntryListIterator;
extern char *typeValueEmpty;
class Dictionary
{
@ -283,16 +283,9 @@ public:
struct Entry
{
enum
{
TypeInternalInt = -3,
TypeInternalFloat = -2,
TypeInternalString = -1,
};
StringTableEntry name;
ConsoleValue value;
Entry *nextEntry;
S32 type;
typedef Signal<void()> NotifySignal;
@ -306,72 +299,42 @@ public:
/// Whether this is a constant that cannot be assigned to.
bool mIsConstant;
protected:
// NOTE: This is protected to ensure no one outside
// of this structure is messing with it.
#pragma warning( push )
#pragma warning( disable : 4201 ) // warning C4201: nonstandard extension used : nameless struct/union
// An variable is either a real dynamic type or
// its one exposed from C++ using a data pointer.
//
// We use this nameless union and struct setup
// to optimize the memory usage.
union
{
struct
{
char *sval;
U32 ival; // doubles as strlen when type is TypeInternalString
F32 fval;
U32 bufferLen;
};
struct
{
/// The real data pointer.
void *dataPtr;
/// The enum lookup table for enumerated types.
const EnumTable *enumTable;
};
};
#pragma warning( pop ) // C4201
public:
Entry() {
name = NULL;
notify = NULL;
nextEntry = NULL;
mUsage = NULL;
mIsConstant = false;
value.init();
}
Entry(StringTableEntry name);
~Entry();
U32 getIntValue()
{
if(type <= TypeInternalString)
return ival;
else
return dAtoi(Con::getData(type, dataPtr, 0, enumTable));
Entry *mNext;
void reset() {
name = NULL;
value.cleanup();
if ( notify )
delete notify;
}
F32 getFloatValue()
inline U32 getIntValue()
{
if(type <= TypeInternalString)
return fval;
else
return dAtof(Con::getData(type, dataPtr, 0, enumTable));
return value.getIntValue();
}
const char *getStringValue()
inline F32 getFloatValue()
{
if(type == TypeInternalString)
return sval;
if(type == TypeInternalFloat)
return Con::getData(TypeF32, &fval, 0);
else if(type == TypeInternalInt)
return Con::getData(TypeS32, &ival, 0);
else
return Con::getData(type, dataPtr, 0, enumTable);
return value.getFloatValue();
}
inline const char *getStringValue()
{
return value.getStringValue();
}
void setIntValue(U32 val)
@ -381,23 +344,8 @@ public:
Con::errorf( "Cannot assign value to constant '%s'.", name );
return;
}
if(type <= TypeInternalString)
{
fval = (F32)val;
ival = val;
if(sval != typeValueEmpty)
{
dFree(sval);
sval = typeValueEmpty;
}
type = TypeInternalInt;
}
else
{
const char *dptr = Con::getData(TypeS32, &val, 0);
Con::setData(type, dataPtr, 0, 1, &dptr, enumTable);
}
value.setIntValue(val);
// Fire off the notification if we have one.
if ( notify )
@ -411,159 +359,163 @@ public:
Con::errorf( "Cannot assign value to constant '%s'.", name );
return;
}
if(type <= TypeInternalString)
{
fval = val;
ival = static_cast<U32>(val);
if(sval != typeValueEmpty)
{
dFree(sval);
sval = typeValueEmpty;
}
type = TypeInternalFloat;
}
else
{
const char *dptr = Con::getData(TypeF32, &val, 0);
Con::setData(type, dataPtr, 0, 1, &dptr, enumTable);
}
value.setFloatValue(val);
// Fire off the notification if we have one.
if ( notify )
notify->trigger();
}
void setStringValue(const char *value);
void setStringValue(const char *newValue)
{
if( mIsConstant )
{
Con::errorf( "Cannot assign value to constant '%s'.", name );
return;
}
value.setStringValue(newValue);
// Fire off the notification if we have one.
if ( notify )
notify->trigger();
}
};
struct HashTableData
{
Dictionary* owner;
S32 size;
S32 count;
Entry **data;
FreeListChunker< Entry > mChunker;
HashTableData( Dictionary* owner )
: owner( owner ), size( 0 ), count( 0 ), data( NULL ) {}
};
struct HashTableData
{
Dictionary* owner;
S32 size;
S32 count;
Entry **data;
FreeListChunker< Entry > mChunker;
HashTableData( Dictionary* owner )
: owner( owner ), size( 0 ), count( 0 ), data( NULL ) {}
};
HashTableData* hashTable;
HashTableData ownHashTable;
ExprEvalState *exprState;
StringTableEntry scopeName;
Namespace *scopeNamespace;
CodeBlock *code;
U32 ip;
HashTableData* hashTable;
HashTableData ownHashTable;
ExprEvalState *exprState;
Dictionary();
~Dictionary();
StringTableEntry scopeName;
Namespace *scopeNamespace;
CodeBlock *code;
U32 ip;
Entry *lookup(StringTableEntry name);
Entry *add(StringTableEntry name);
void setState(ExprEvalState *state, Dictionary* ref=NULL);
void remove(Entry *);
void reset();
Dictionary();
~Dictionary();
void exportVariables( const char *varString, const char *fileName, bool append );
void exportVariables( const char *varString, Vector<String> *names, Vector<String> *values );
void deleteVariables( const char *varString );
Entry *lookup(StringTableEntry name);
Entry *add(StringTableEntry name);
void setState(ExprEvalState *state, Dictionary* ref=NULL);
void remove(Entry *);
void reset();
void setVariable(StringTableEntry name, const char *value);
const char *getVariable(StringTableEntry name, bool *valid = NULL);
U32 getCount() const
{
void exportVariables( const char *varString, const char *fileName, bool append );
void exportVariables( const char *varString, Vector<String> *names, Vector<String> *values );
void deleteVariables( const char *varString );
void setVariable(StringTableEntry name, const char *value);
const char *getVariable(StringTableEntry name, bool *valid = NULL);
S32 getIntVariable(StringTableEntry name, bool *valid = NULL);
F32 getFloatVariable(StringTableEntry name, bool *entValid = NULL);
U32 getCount() const
{
return hashTable->count;
}
bool isOwner() const
{
}
bool isOwner() const
{
return hashTable->owner;
}
}
/// @see Con::addVariable
Entry* addVariable( const char *name,
S32 type,
void *dataPtr,
const char* usage );
/// @see Con::addVariable
Entry* addVariable( const char *name,
S32 type,
void *dataPtr,
const char* usage );
/// @see Con::removeVariable
bool removeVariable(StringTableEntry name);
/// @see Con::removeVariable
bool removeVariable(StringTableEntry name);
/// @see Con::addVariableNotify
void addVariableNotify( const char *name, const Con::NotifyDelegate &callback );
/// @see Con::addVariableNotify
void addVariableNotify( const char *name, const Con::NotifyDelegate &callback );
/// @see Con::removeVariableNotify
void removeVariableNotify( const char *name, const Con::NotifyDelegate &callback );
/// @see Con::removeVariableNotify
void removeVariableNotify( const char *name, const Con::NotifyDelegate &callback );
/// Return the best tab completion for prevText, with the length
/// of the pre-tab string in baseLen.
const char *tabComplete(const char *prevText, S32 baseLen, bool);
/// Run integrity checks for debugging.
void validate();
/// Return the best tab completion for prevText, with the length
/// of the pre-tab string in baseLen.
const char *tabComplete(const char *prevText, S32 baseLen, bool);
/// Run integrity checks for debugging.
void validate();
};
class ExprEvalState
{
public:
/// @name Expression Evaluation
/// @{
/// @name Expression Evaluation
/// @{
///
SimObject *thisObject;
Dictionary::Entry *currentVariable;
bool traceOn;
U32 mStackDepth;
///
SimObject *thisObject;
Dictionary::Entry *currentVariable;
Dictionary::Entry *copyVariable;
bool traceOn;
ExprEvalState();
~ExprEvalState();
U32 mStackDepth;
/// @}
ExprEvalState();
~ExprEvalState();
/// @name Stack Management
/// @{
/// @}
/// The stack of callframes. The extra redirection is necessary since Dictionary holds
/// an interior pointer that will become invalid when the object changes address.
Vector< Dictionary* > stack;
/// @name Stack Management
/// @{
///
Dictionary globalVars;
void setCurVarName(StringTableEntry name);
void setCurVarNameCreate(StringTableEntry name);
S32 getIntVariable();
F64 getFloatVariable();
const char *getStringVariable();
void setIntVariable(S32 val);
void setFloatVariable(F64 val);
void setStringVariable(const char *str);
/// The stack of callframes. The extra redirection is necessary since Dictionary holds
/// an interior pointer that will become invalid when the object changes address.
Vector< Dictionary* > stack;
void pushFrame(StringTableEntry frameName, Namespace *ns);
void popFrame();
///
Dictionary globalVars;
/// Puts a reference to an existing stack frame
/// on the top of the stack.
void pushFrameRef(S32 stackIndex);
U32 getStackDepth() const
{
return mStackDepth;
}
Dictionary& getCurrentFrame()
{
void setCurVarName(StringTableEntry name);
void setCurVarNameCreate(StringTableEntry name);
S32 getIntVariable();
F64 getFloatVariable();
const char *getStringVariable();
void setIntVariable(S32 val);
void setFloatVariable(F64 val);
void setStringVariable(const char *str);
void setCopyVariable();
void pushFrame(StringTableEntry frameName, Namespace *ns);
void popFrame();
/// Puts a reference to an existing stack frame
/// on the top of the stack.
void pushFrameRef(S32 stackIndex);
U32 getStackDepth() const
{
return mStackDepth;
}
Dictionary& getCurrentFrame()
{
return *( stack[ mStackDepth - 1 ] );
}
}
/// @}
/// Run integrity checks for debugging.
void validate();
/// @}
/// Run integrity checks for debugging.
void validate();
};
namespace Con

View file

@ -79,7 +79,7 @@ void ConsoleLogger::initPersistFields()
//-----------------------------------------------------------------------------
bool ConsoleLogger::processArguments( S32 argc, const char **argv )
bool ConsoleLogger::processArguments( S32 argc, ConsoleValueRef *argv )
{
if( argc == 0 )
return false;

View file

@ -81,7 +81,7 @@ class ConsoleLogger : public SimObject
/// // Example script constructor usage.
/// %obj = new ConsoleLogger( objName, logFileName, [append = false] );
/// @endcode
bool processArguments( S32 argc, const char **argv );
bool processArguments( S32 argc, ConsoleValueRef *argv );
/// Default constructor, make sure to initalize
ConsoleLogger();

View file

@ -834,3 +834,44 @@ DefineEngineFunction( sizeof, S32, ( const char *objectOrClass ),,
Con::warnf("could not find a class rep for that object or class name.");
return 0;
}
DefineEngineFunction(linkNamespaces, bool, ( String childNSName, String parentNSName ),,
"@brief Links childNS to parentNS.\n\n"
"Links childNS to parentNS, or nothing if parentNS is NULL.\n"
"Will unlink the namespace from previous namespace if a parent already exists.\n"
"@internal\n")
{
StringTableEntry childNSSTE = StringTable->insert(childNSName.c_str());
StringTableEntry parentNSSTE = StringTable->insert(parentNSName.c_str());
Namespace *childNS = Namespace::find(childNSSTE);
Namespace *parentNS = Namespace::find(parentNSSTE);
Namespace *currentParent = childNS->getParent();
if (!childNS)
{
return false;
}
// Link to new NS if applicable
if (currentParent != parentNS)
{
if (currentParent != NULL)
{
if (!childNS->unlinkClass(currentParent))
{
return false;
}
}
if (parentNS != NULL)
{
return childNS->classLinkTo(parentNS);
}
}
return true;
}

View file

@ -29,6 +29,7 @@
#include "core/color.h"
#include "console/simBase.h"
#include "math/mRect.h"
#include "core/strings/stringUnit.h"
//-----------------------------------------------------------------------------
// TypeString
@ -288,8 +289,9 @@ ImplementConsoleTypeCasters( TypeS8, S8 )
ConsoleGetType( TypeS8 )
{
char* returnBuffer = Con::getReturnBuffer(256);
dSprintf(returnBuffer, 256, "%d", *((U8 *) dptr) );
static const U32 bufSize = 256;
char* returnBuffer = Con::getReturnBuffer(bufSize);
dSprintf(returnBuffer, bufSize, "%d", *((U8 *) dptr) );
return returnBuffer;
}
@ -309,8 +311,9 @@ ImplementConsoleTypeCasters(TypeS32, S32)
ConsoleGetType( TypeS32 )
{
char* returnBuffer = Con::getReturnBuffer(256);
dSprintf(returnBuffer, 256, "%d", *((S32 *) dptr) );
static const U32 bufSize = 512;
char* returnBuffer = Con::getReturnBuffer(bufSize);
dSprintf(returnBuffer, bufSize, "%d", *((S32 *) dptr) );
return returnBuffer;
}
@ -388,8 +391,9 @@ ImplementConsoleTypeCasters(TypeF32, F32)
ConsoleGetType( TypeF32 )
{
char* returnBuffer = Con::getReturnBuffer(256);
dSprintf(returnBuffer, 256, "%g", *((F32 *) dptr) );
static const U32 bufSize = 256;
char* returnBuffer = Con::getReturnBuffer(bufSize);
dSprintf(returnBuffer, bufSize, "%g", *((F32 *) dptr) );
return returnBuffer;
}
ConsoleSetType( TypeF32 )
@ -486,8 +490,9 @@ ImplementConsoleTypeCasters( TypeBoolVector, Vector< bool > )
ConsoleGetType( TypeBoolVector )
{
Vector<bool> *vec = (Vector<bool>*)dptr;
char* returnBuffer = Con::getReturnBuffer(1024);
S32 maxReturn = 1024;
static const U32 bufSize = 1024;
char* returnBuffer = Con::getReturnBuffer(bufSize);
S32 maxReturn = bufSize;
returnBuffer[0] = '\0';
S32 returnLeng = 0;
for (Vector<bool>::iterator itr = vec->begin(); itr < vec->end(); itr++)
@ -567,9 +572,20 @@ ImplementConsoleTypeCasters( TypeColorF, ColorF )
ConsoleGetType( TypeColorF )
{
ColorF * color = (ColorF*)dptr;
char* returnBuffer = Con::getReturnBuffer(256);
dSprintf(returnBuffer, 256, "%g %g %g %g", color->red, color->green, color->blue, color->alpha);
// Fetch color.
const ColorF* color = (ColorF*)dptr;
// Fetch stock color name.
StringTableEntry colorName = StockColor::name( *color );
// Write as color name if was found.
if ( colorName != StringTable->EmptyString() )
return colorName;
// Format as color components.
static const U32 bufSize = 256;
char* returnBuffer = Con::getReturnBuffer(bufSize);
dSprintf(returnBuffer, bufSize, "%g %g %g %g", color->red, color->green, color->blue, color->alpha);
return(returnBuffer);
}
@ -578,6 +594,22 @@ ConsoleSetType( TypeColorF )
ColorF *tmpColor = (ColorF *) dptr;
if(argc == 1)
{
// Is only a single argument passed?
if ( StringUnit::getUnitCount( argv[0], " " ) == 1 )
{
// Is this a stock color name?
if ( !StockColor::isColor(argv[0]) )
{
// No, so warn.
Con::warnf( "TypeColorF() - Invalid single argument of '%s' could not be interpreted as a stock color name. Using default.", argv[0] );
}
// Set stock color (if it's invalid we'll get the default.
tmpColor->set( argv[0] );
return;
}
tmpColor->set(0, 0, 0, 1);
F32 r,g,b,a;
S32 args = dSscanf(argv[0], "%g %g %g %g", &r, &g, &b, &a);
@ -602,7 +634,7 @@ ConsoleSetType( TypeColorF )
tmpColor->alpha = dAtof(argv[3]);
}
else
Con::printf("Color must be set as { r, g, b [,a] }");
Con::printf("Color must be set as { r, g, b [,a] }, { r g b [b] } or { stockColorName }");
}
//-----------------------------------------------------------------------------
@ -613,9 +645,20 @@ ImplementConsoleTypeCasters( TypeColorI, ColorI )
ConsoleGetType( TypeColorI )
{
ColorI *color = (ColorI *) dptr;
char* returnBuffer = Con::getReturnBuffer(256);
dSprintf(returnBuffer, 256, "%d %d %d %d", color->red, color->green, color->blue, color->alpha);
// Fetch color.
ColorI* color = (ColorI*)dptr;
// Fetch stock color name.
StringTableEntry colorName = StockColor::name( *color );
// Write as color name if was found.
if ( colorName != StringTable->EmptyString() )
return colorName;
// Format as color components.
static const U32 bufSize = 256;
char* returnBuffer = Con::getReturnBuffer(bufSize);
dSprintf(returnBuffer, bufSize, "%d %d %d %d", color->red, color->green, color->blue, color->alpha);
return returnBuffer;
}
@ -624,6 +667,22 @@ ConsoleSetType( TypeColorI )
ColorI *tmpColor = (ColorI *) dptr;
if(argc == 1)
{
// Is only a single argument passed?
if ( StringUnit::getUnitCount( argv[0], " " ) == 1 )
{
// Is this a stock color name?
if ( !StockColor::isColor(argv[0]) )
{
// No, so warn.
Con::warnf( "TypeColorF() - Invalid single argument of '%s' could not be interpreted as a stock color name. Using default.", argv[0] );
}
// Set stock color (if it's invalid we'll get the default.
tmpColor->set( argv[0] );
return;
}
tmpColor->set(0, 0, 0, 255);
S32 r,g,b,a;
S32 args = dSscanf(argv[0], "%d %d %d %d", &r, &g, &b, &a);
@ -648,7 +707,7 @@ ConsoleSetType( TypeColorI )
tmpColor->alpha = dAtoi(argv[3]);
}
else
Con::printf("Color must be set as { r, g, b [,a] }");
Con::printf("Color must be set as { r, g, b [,a] }, { r g b [b] } or { stockColorName }");
}
//-----------------------------------------------------------------------------
@ -670,8 +729,9 @@ ConsoleSetType( TypeSimObjectName )
ConsoleGetType( TypeSimObjectName )
{
SimObject **obj = (SimObject**)dptr;
char* returnBuffer = Con::getReturnBuffer(128);
dSprintf(returnBuffer, 128, "%s", *obj && (*obj)->getName() ? (*obj)->getName() : "");
static const U32 bufSize = 128;
char* returnBuffer = Con::getReturnBuffer(bufSize);
dSprintf(returnBuffer, bufSize, "%s", *obj && (*obj)->getName() ? (*obj)->getName() : "");
return returnBuffer;
}
@ -738,8 +798,9 @@ ConsoleType( int, TypeTerrainMaterialIndex, S32 )
ConsoleGetType( TypeTerrainMaterialIndex )
{
char* returnBuffer = Con::getReturnBuffer(256);
dSprintf(returnBuffer, 256, "%d", *((S32 *) dptr) );
static const U32 bufSize = 256;
char* returnBuffer = Con::getReturnBuffer(bufSize);
dSprintf(returnBuffer, bufSize, "%d", *((S32 *) dptr) );
return returnBuffer;
}
@ -800,8 +861,9 @@ ConsoleType( RectF, TypeRectUV, RectF )
ConsoleGetType( TypeRectUV )
{
RectF *rect = (RectF *) dptr;
char* returnBuffer = Con::getReturnBuffer(256);
dSprintf(returnBuffer, 256, "%g %g %g %g", rect->point.x, rect->point.y,
static const U32 bufSize = 256;
char* returnBuffer = Con::getReturnBuffer(bufSize);
dSprintf(returnBuffer, bufSize, "%g %g %g %g", rect->point.x, rect->point.y,
rect->extent.x, rect->extent.y);
return returnBuffer;
}

View file

@ -211,8 +211,9 @@ class BitfieldConsoleBaseType : public ConsoleBaseType
virtual const char* getData( void* dptr, const EnumTable*, BitSet32 )
{
char* returnBuffer = Con::getReturnBuffer(256);
dSprintf(returnBuffer, 256, "0x%08x", *((S32 *) dptr) );
static const U32 bufSize = 256;
char* returnBuffer = Con::getReturnBuffer(bufSize);
dSprintf(returnBuffer, bufSize, "0x%08x", *((S32 *) dptr) );
return returnBuffer;
}
virtual void setData( void* dptr, S32 argc, const char** argv, const EnumTable*, BitSet32 )

View file

@ -76,6 +76,7 @@
// Disable some VC warnings that are irrelevant to us.
#pragma warning( push )
#pragma warning( disable : 4510 ) // default constructor could not be generated; all the Args structures are never constructed by us
#pragma warning( disable : 4610 ) // can never be instantiated; again Args is never constructed by us
@ -145,12 +146,12 @@ inline const char* EngineMarshallData( U32 value )
/// Marshal data from native into client form stored directly in
/// client function invocation vector.
template< typename T >
inline void EngineMarshallData( const T& arg, S32& argc, const char** argv )
inline void EngineMarshallData( const T& arg, S32& argc, ConsoleValueRef *argv )
{
argv[ argc ] = Con::getStringArg( castConsoleTypeToString( arg ) );
argc ++;
}
inline void EngineMarshallData( bool arg, S32& argc, const char** argv )
inline void EngineMarshallData( bool arg, S32& argc, ConsoleValueRef *argv )
{
if( arg )
argv[ argc ] = "1";
@ -158,33 +159,33 @@ inline void EngineMarshallData( bool arg, S32& argc, const char** argv )
argv[ argc ] = "0";
argc ++;
}
inline void EngineMarshallData( S32 arg, S32& argc, const char** argv )
inline void EngineMarshallData( S32 arg, S32& argc, ConsoleValueRef *argv )
{
argv[ argc ] = Con::getIntArg( arg );
argv[ argc ] = arg;
argc ++;
}
inline void EngineMarshallData( U32 arg, S32& argc, const char** argv )
inline void EngineMarshallData( U32 arg, S32& argc, ConsoleValueRef *argv )
{
EngineMarshallData( S32( arg ), argc, argv );
}
inline void EngineMarshallData( F32 arg, S32& argc, const char** argv )
inline void EngineMarshallData( F32 arg, S32& argc, ConsoleValueRef *argv )
{
argv[ argc ] = Con::getFloatArg( arg );
argv[ argc ] = arg;
argc ++;
}
inline void EngineMarshallData( const char* arg, S32& argc, const char** argv )
inline void EngineMarshallData( const char* arg, S32& argc, ConsoleValueRef *argv )
{
argv[ argc ] = arg;
argc ++;
}
template< typename T >
inline void EngineMarshallData( T* object, S32& argc, const char** argv )
inline void EngineMarshallData( T* object, S32& argc, ConsoleValueRef *argv )
{
argv[ argc ] = ( object ? object->getIdString() : "0" );
argc ++;
}
template< typename T >
inline void EngineMarshallData( const T* object, S32& argc, const char** argv )
inline void EngineMarshallData( const T* object, S32& argc, ConsoleValueRef *argv )
{
argv[ argc ] = ( object ? object->getIdString() : "0" );
argc ++;
@ -207,6 +208,11 @@ struct EngineUnmarshallData
template<>
struct EngineUnmarshallData< S32 >
{
S32 operator()( ConsoleValueRef &ref ) const
{
return (S32)ref;
}
S32 operator()( const char* str ) const
{
return dAtoi( str );
@ -215,6 +221,11 @@ struct EngineUnmarshallData< S32 >
template<>
struct EngineUnmarshallData< U32 >
{
U32 operator()( ConsoleValueRef &ref ) const
{
return (U32)((S32)ref);
}
U32 operator()( const char* str ) const
{
return dAtoui( str );
@ -223,6 +234,11 @@ struct EngineUnmarshallData< U32 >
template<>
struct EngineUnmarshallData< F32 >
{
F32 operator()( ConsoleValueRef &ref ) const
{
return (F32)ref;
}
F32 operator()( const char* str ) const
{
return dAtof( str );
@ -1391,12 +1407,12 @@ struct _EngineConsoleThunk< startArgc, R() >
{
typedef typename _EngineConsoleThunkType< R >::ReturnType ReturnType;
static const S32 NUM_ARGS = 0;
static ReturnType thunk( S32 argc, const char** argv, R ( *fn )(), const _EngineFunctionDefaultArguments< void() >& )
static ReturnType thunk( S32 argc, ConsoleValueRef *argv, R ( *fn )(), const _EngineFunctionDefaultArguments< void() >& )
{
return _EngineConsoleThunkReturnValue( fn() );
}
template< typename Frame >
static ReturnType thunk( S32 argc, const char** argv, R ( Frame::*fn )() const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType* ) >& )
static ReturnType thunk( S32 argc, ConsoleValueRef *argv, R ( Frame::*fn )() const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType* ) >& )
{
return _EngineConsoleThunkReturnValue( ( frame->*fn )() );
}
@ -1406,12 +1422,12 @@ struct _EngineConsoleThunk< startArgc, void() >
{
typedef void ReturnType;
static const S32 NUM_ARGS = 0;
static void thunk( S32 argc, const char** argv, void ( *fn )(), const _EngineFunctionDefaultArguments< void() >& )
static void thunk( S32 argc, ConsoleValueRef *argv, void ( *fn )(), const _EngineFunctionDefaultArguments< void() >& )
{
fn();
}
template< typename Frame >
static void thunk( S32 argc, const char** argv, void ( Frame::*fn )() const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType* ) >& )
static void thunk( S32 argc, ConsoleValueRef *argv, void ( Frame::*fn )() const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType* ) >& )
{
return ( frame->*fn )();
}
@ -1422,13 +1438,13 @@ struct _EngineConsoleThunk< startArgc, R( A ) >
{
typedef typename _EngineConsoleThunkType< R >::ReturnType ReturnType;
static const S32 NUM_ARGS = 1 + startArgc;
static ReturnType thunk( S32 argc, const char** argv, R ( *fn )( A ), const _EngineFunctionDefaultArguments< void( A ) >& defaultArgs )
static ReturnType thunk( S32 argc, ConsoleValueRef *argv, R ( *fn )( A ), const _EngineFunctionDefaultArguments< void( A ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.a ) );
return _EngineConsoleThunkReturnValue( fn( a ) );
}
template< typename Frame >
static ReturnType thunk( S32 argc, const char** argv, R ( Frame::*fn )( A ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A ) >& defaultArgs )
static ReturnType thunk( S32 argc, ConsoleValueRef *argv, R ( Frame::*fn )( A ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.b ) );
return _EngineConsoleThunkReturnValue( ( frame->*fn )( a ) );
@ -1439,13 +1455,13 @@ struct _EngineConsoleThunk< startArgc, void( A ) >
{
typedef void ReturnType;
static const S32 NUM_ARGS = 1 + startArgc;
static void thunk( S32 argc, const char** argv, void ( *fn )( A ), const _EngineFunctionDefaultArguments< void( A ) >& defaultArgs )
static void thunk( S32 argc, ConsoleValueRef *argv, void ( *fn )( A ), const _EngineFunctionDefaultArguments< void( A ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.a ) );
fn( a );
}
template< typename Frame >
static void thunk( S32 argc, const char** argv, void ( Frame::*fn )( A ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A ) >& defaultArgs )
static void thunk( S32 argc, ConsoleValueRef *argv, void ( Frame::*fn )( A ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.b ) );
( frame->*fn )( a );
@ -1457,14 +1473,14 @@ struct _EngineConsoleThunk< startArgc, R( A, B ) >
{
typedef typename _EngineConsoleThunkType< R >::ReturnType ReturnType;
static const S32 NUM_ARGS = 2 + startArgc;
static ReturnType thunk( S32 argc, const char** argv, R ( *fn )( A, B ), const _EngineFunctionDefaultArguments< void( A, B ) >& defaultArgs )
static ReturnType thunk( S32 argc, ConsoleValueRef *argv, R ( *fn )( A, B ), const _EngineFunctionDefaultArguments< void( A, B ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.a ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.b ) );
return _EngineConsoleThunkReturnValue( fn( a, b ) );
}
template< typename Frame >
static ReturnType thunk( S32 argc, const char** argv, R ( Frame::*fn )( A, B ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B ) >& defaultArgs )
static ReturnType thunk( S32 argc, ConsoleValueRef *argv, R ( Frame::*fn )( A, B ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.b ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.c ) );
@ -1476,14 +1492,14 @@ struct _EngineConsoleThunk< startArgc, void( A, B ) >
{
typedef void ReturnType;
static const S32 NUM_ARGS = 2 + startArgc;
static void thunk( S32 argc, const char** argv, void ( *fn )( A, B ), const _EngineFunctionDefaultArguments< void( A, B ) >& defaultArgs )
static void thunk( S32 argc, ConsoleValueRef *argv, void ( *fn )( A, B ), const _EngineFunctionDefaultArguments< void( A, B ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.a ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.b ) );
fn( a, b );
}
template< typename Frame >
static void thunk( S32 argc, const char** argv, void ( Frame::*fn )( A, B ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B ) >& defaultArgs )
static void thunk( S32 argc, ConsoleValueRef *argv, void ( Frame::*fn )( A, B ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.b ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.c ) );
@ -1496,7 +1512,7 @@ struct _EngineConsoleThunk< startArgc, R( A, B, C ) >
{
typedef typename _EngineConsoleThunkType< R >::ReturnType ReturnType;
static const S32 NUM_ARGS = 3 + startArgc;
static ReturnType thunk( S32 argc, const char** argv, R ( *fn )( A, B, C ), const _EngineFunctionDefaultArguments< void( A, B, C ) >& defaultArgs )
static ReturnType thunk( S32 argc, ConsoleValueRef *argv, R ( *fn )( A, B, C ), const _EngineFunctionDefaultArguments< void( A, B, C ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.a ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.b ) );
@ -1504,7 +1520,7 @@ struct _EngineConsoleThunk< startArgc, R( A, B, C ) >
return _EngineConsoleThunkReturnValue( fn( a, b, c ) );
}
template< typename Frame >
static ReturnType thunk( S32 argc, const char** argv, R ( Frame::*fn )( A, B, C ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C ) >& defaultArgs )
static ReturnType thunk( S32 argc, ConsoleValueRef *argv, R ( Frame::*fn )( A, B, C ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.b ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.c ) );
@ -1517,7 +1533,7 @@ struct _EngineConsoleThunk< startArgc, void( A, B, C ) >
{
typedef void ReturnType;
static const S32 NUM_ARGS = 3 + startArgc;
static void thunk( S32 argc, const char** argv, void ( *fn )( A, B, C ), const _EngineFunctionDefaultArguments< void( A, B, C ) >& defaultArgs )
static void thunk( S32 argc, ConsoleValueRef *argv, void ( *fn )( A, B, C ), const _EngineFunctionDefaultArguments< void( A, B, C ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.a ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.b ) );
@ -1525,7 +1541,7 @@ struct _EngineConsoleThunk< startArgc, void( A, B, C ) >
fn( a, b, c );
}
template< typename Frame >
static void thunk( S32 argc, const char** argv, void ( Frame::*fn )( A, B, C ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C ) >& defaultArgs )
static void thunk( S32 argc, ConsoleValueRef *argv, void ( Frame::*fn )( A, B, C ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.b ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.c ) );
@ -1539,7 +1555,7 @@ struct _EngineConsoleThunk< startArgc, R( A, B, C, D ) >
{
typedef typename _EngineConsoleThunkType< R >::ReturnType ReturnType;
static const S32 NUM_ARGS = 4 + startArgc;
static ReturnType thunk( S32 argc, const char** argv, R ( *fn )( A, B, C, D ), const _EngineFunctionDefaultArguments< void( A, B, C, D ) >& defaultArgs )
static ReturnType thunk( S32 argc, ConsoleValueRef *argv, R ( *fn )( A, B, C, D ), const _EngineFunctionDefaultArguments< void( A, B, C, D ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.a ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.b ) );
@ -1548,7 +1564,7 @@ struct _EngineConsoleThunk< startArgc, R( A, B, C, D ) >
return _EngineConsoleThunkReturnValue( fn( a, b, c, d ) );
}
template< typename Frame >
static ReturnType thunk( S32 argc, const char** argv, R ( Frame::*fn )( A, B, C, D ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D ) >& defaultArgs )
static ReturnType thunk( S32 argc, ConsoleValueRef *argv, R ( Frame::*fn )( A, B, C, D ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.b ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.c ) );
@ -1562,7 +1578,7 @@ struct _EngineConsoleThunk< startArgc, void( A, B, C, D ) >
{
typedef void ReturnType;
static const S32 NUM_ARGS = 4 + startArgc;
static void thunk( S32 argc, const char** argv, void ( *fn )( A, B, C, D ), const _EngineFunctionDefaultArguments< void( A, B, C, D ) >& defaultArgs )
static void thunk( S32 argc, ConsoleValueRef *argv, void ( *fn )( A, B, C, D ), const _EngineFunctionDefaultArguments< void( A, B, C, D ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.a ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.b ) );
@ -1571,7 +1587,7 @@ struct _EngineConsoleThunk< startArgc, void( A, B, C, D ) >
fn( a, b, c, d );
}
template< typename Frame >
static void thunk( S32 argc, const char** argv, void ( Frame::*fn )( A, B, C, D ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D ) >& defaultArgs )
static void thunk( S32 argc, ConsoleValueRef *argv, void ( Frame::*fn )( A, B, C, D ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.b ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.c ) );
@ -1586,7 +1602,7 @@ struct _EngineConsoleThunk< startArgc, R( A, B, C, D, E ) >
{
typedef typename _EngineConsoleThunkType< R >::ReturnType ReturnType;
static const S32 NUM_ARGS = 5 + startArgc;
static ReturnType thunk( S32 argc, const char** argv, R ( *fn )( A, B, C, D, E ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E ) >& defaultArgs )
static ReturnType thunk( S32 argc, ConsoleValueRef *argv, R ( *fn )( A, B, C, D, E ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.a ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.b ) );
@ -1596,7 +1612,7 @@ struct _EngineConsoleThunk< startArgc, R( A, B, C, D, E ) >
return _EngineConsoleThunkReturnValue( fn( a, b, c, d, e ) );
}
template< typename Frame >
static ReturnType thunk( S32 argc, const char** argv, R ( Frame::*fn )( A, B, C, D, E ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E ) >& defaultArgs )
static ReturnType thunk( S32 argc, ConsoleValueRef *argv, R ( Frame::*fn )( A, B, C, D, E ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.b ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.c ) );
@ -1611,7 +1627,7 @@ struct _EngineConsoleThunk< startArgc, void( A, B, C, D, E ) >
{
typedef void ReturnType;
static const S32 NUM_ARGS = 5 + startArgc;
static void thunk( S32 argc, const char** argv, void ( *fn )( A, B, C, D, E ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E ) >& defaultArgs )
static void thunk( S32 argc, ConsoleValueRef *argv, void ( *fn )( A, B, C, D, E ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.a ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.b ) );
@ -1621,7 +1637,7 @@ struct _EngineConsoleThunk< startArgc, void( A, B, C, D, E ) >
fn( a, b, c, d, e );
}
template< typename Frame >
static void thunk( S32 argc, const char** argv, void ( Frame::*fn )( A, B, C, D, E ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E ) >& defaultArgs )
static void thunk( S32 argc, ConsoleValueRef *argv, void ( Frame::*fn )( A, B, C, D, E ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.b ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.c ) );
@ -1637,7 +1653,7 @@ struct _EngineConsoleThunk< startArgc, R( A, B, C, D, E, F ) >
{
typedef typename _EngineConsoleThunkType< R >::ReturnType ReturnType;
static const S32 NUM_ARGS = 6 + startArgc;
static ReturnType thunk( S32 argc, const char** argv, R ( *fn )( A, B, C, D, E, F ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E, F ) >& defaultArgs )
static ReturnType thunk( S32 argc, ConsoleValueRef *argv, R ( *fn )( A, B, C, D, E, F ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E, F ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.a ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.b ) );
@ -1648,7 +1664,7 @@ struct _EngineConsoleThunk< startArgc, R( A, B, C, D, E, F ) >
return _EngineConsoleThunkReturnValue( fn( a, b, c, d, e, f ) );
}
template< typename Frame >
static ReturnType thunk( S32 argc, const char** argv, R ( Frame::*fn )( A, B, C, D, E, F ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E, F ) >& defaultArgs )
static ReturnType thunk( S32 argc, ConsoleValueRef *argv, R ( Frame::*fn )( A, B, C, D, E, F ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E, F ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.b ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.c ) );
@ -1664,7 +1680,7 @@ struct _EngineConsoleThunk< startArgc, void( A, B, C, D, E, F ) >
{
typedef void ReturnType;
static const S32 NUM_ARGS = 6 + startArgc;
static void thunk( S32 argc, const char** argv, void ( *fn )( A, B, C, D, E, F ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E, F ) >& defaultArgs )
static void thunk( S32 argc, ConsoleValueRef *argv, void ( *fn )( A, B, C, D, E, F ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E, F ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.a ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.b ) );
@ -1675,7 +1691,7 @@ struct _EngineConsoleThunk< startArgc, void( A, B, C, D, E, F ) >
fn( a, b, c, d, e, f );
}
template< typename Frame >
static void thunk( S32 argc, const char** argv, void ( Frame::*fn )( A, B, C, D, E, F ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E, F ) >& defaultArgs )
static void thunk( S32 argc, ConsoleValueRef *argv, void ( Frame::*fn )( A, B, C, D, E, F ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E, F ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.b ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.c ) );
@ -1692,7 +1708,7 @@ struct _EngineConsoleThunk< startArgc, R( A, B, C, D, E, F, G ) >
{
typedef typename _EngineConsoleThunkType< R >::ReturnType ReturnType;
static const S32 NUM_ARGS = 7 + startArgc;
static ReturnType thunk( S32 argc, const char** argv, R ( *fn )( A, B, C, D, E, F, G ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E, F, G ) >& defaultArgs )
static ReturnType thunk( S32 argc, ConsoleValueRef *argv, R ( *fn )( A, B, C, D, E, F, G ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E, F, G ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.a ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.b ) );
@ -1704,7 +1720,7 @@ struct _EngineConsoleThunk< startArgc, R( A, B, C, D, E, F, G ) >
return _EngineConsoleThunkReturnValue( fn( a, b, c, d, e, f, g ) );
}
template< typename Frame >
static ReturnType thunk( S32 argc, const char** argv, R ( Frame::*fn )( A, B, C, D, E, F, G ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E, F, G ) >& defaultArgs )
static ReturnType thunk( S32 argc, ConsoleValueRef *argv, R ( Frame::*fn )( A, B, C, D, E, F, G ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E, F, G ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.b ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.c ) );
@ -1721,7 +1737,7 @@ struct _EngineConsoleThunk< startArgc, void( A, B, C, D, E, F, G ) >
{
typedef void ReturnType;
static const S32 NUM_ARGS = 7 + startArgc;
static void thunk( S32 argc, const char** argv, void ( *fn )( A, B, C, D, E, F, G ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E, F, G ) >& defaultArgs )
static void thunk( S32 argc, ConsoleValueRef *argv, void ( *fn )( A, B, C, D, E, F, G ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E, F, G ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.a ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.b ) );
@ -1733,7 +1749,7 @@ struct _EngineConsoleThunk< startArgc, void( A, B, C, D, E, F, G ) >
fn( a, b, c, d, e, f, g );
}
template< typename Frame >
static void thunk( S32 argc, const char** argv, void ( Frame::*fn )( A, B, C, D, E, F, G ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E, F, G ) >& defaultArgs )
static void thunk( S32 argc, ConsoleValueRef *argv, void ( Frame::*fn )( A, B, C, D, E, F, G ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E, F, G ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.b ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.c ) );
@ -1751,7 +1767,7 @@ struct _EngineConsoleThunk< startArgc, R( A, B, C, D, E, F, G, H ) >
{
typedef typename _EngineConsoleThunkType< R >::ReturnType ReturnType;
static const S32 NUM_ARGS = 8 + startArgc;
static ReturnType thunk( S32 argc, const char** argv, R ( *fn )( A, B, C, D, E, F, G, H ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E, F, G, H ) >& defaultArgs )
static ReturnType thunk( S32 argc, ConsoleValueRef *argv, R ( *fn )( A, B, C, D, E, F, G, H ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E, F, G, H ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.a ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.b ) );
@ -1764,7 +1780,7 @@ struct _EngineConsoleThunk< startArgc, R( A, B, C, D, E, F, G, H ) >
return _EngineConsoleThunkReturnValue( fn( a, b, c, d, e, f, g, h ) );
}
template< typename Frame >
static ReturnType thunk( S32 argc, const char** argv, R ( Frame::*fn )( A, B, C, D, E, F, G, H ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E, F, G, H ) >& defaultArgs )
static ReturnType thunk( S32 argc, ConsoleValueRef *argv, R ( Frame::*fn )( A, B, C, D, E, F, G, H ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E, F, G, H ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.b ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.c ) );
@ -1782,7 +1798,7 @@ struct _EngineConsoleThunk< startArgc, void( A, B, C, D, E, F, G, H ) >
{
typedef void ReturnType;
static const S32 NUM_ARGS = 8 + startArgc;
static void thunk( S32 argc, const char** argv, void ( *fn )( A, B, C, D, E, F, G, H ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E, F, G, H ) >& defaultArgs )
static void thunk( S32 argc, ConsoleValueRef *argv, void ( *fn )( A, B, C, D, E, F, G, H ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E, F, G, H ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.a ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.b ) );
@ -1795,7 +1811,7 @@ struct _EngineConsoleThunk< startArgc, void( A, B, C, D, E, F, G, H ) >
fn( a, b, c, d, e, f, g, h );
}
template< typename Frame >
static void thunk( S32 argc, const char** argv, void ( Frame::*fn )( A, B, C, D, E, F, G, H ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E, F, G, H ) >& defaultArgs )
static void thunk( S32 argc, ConsoleValueRef *argv, void ( Frame::*fn )( A, B, C, D, E, F, G, H ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E, F, G, H ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.b ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.c ) );
@ -1814,7 +1830,7 @@ struct _EngineConsoleThunk< startArgc, R( A, B, C, D, E, F, G, H, I ) >
{
typedef typename _EngineConsoleThunkType< R >::ReturnType ReturnType;
static const S32 NUM_ARGS = 9 + startArgc;
static ReturnType thunk( S32 argc, const char** argv, R ( *fn )( A, B, C, D, E, F, G, H, I ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E, F, G, H, I ) >& defaultArgs )
static ReturnType thunk( S32 argc, ConsoleValueRef *argv, R ( *fn )( A, B, C, D, E, F, G, H, I ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E, F, G, H, I ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.a ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.b ) );
@ -1828,7 +1844,7 @@ struct _EngineConsoleThunk< startArgc, R( A, B, C, D, E, F, G, H, I ) >
return _EngineConsoleThunkReturnValue( fn( a, b, c, d, e, f, g, h, i ) );
}
template< typename Frame >
static ReturnType thunk( S32 argc, const char** argv, R ( Frame::*fn )( A, B, C, D, E, F, G, H, I ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E, F, G, H, I ) >& defaultArgs )
static ReturnType thunk( S32 argc, ConsoleValueRef *argv, R ( Frame::*fn )( A, B, C, D, E, F, G, H, I ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E, F, G, H, I ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.b ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.c ) );
@ -1847,7 +1863,7 @@ struct _EngineConsoleThunk< startArgc, void( A, B, C, D, E, F, G, H, I ) >
{
typedef void ReturnType;
static const S32 NUM_ARGS = 9 + startArgc;
static void thunk( S32 argc, const char** argv, void ( *fn )( A, B, C, D, E, F, G, H, I ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E, F, G, H, I ) >& defaultArgs )
static void thunk( S32 argc, ConsoleValueRef *argv, void ( *fn )( A, B, C, D, E, F, G, H, I ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E, F, G, H, I ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.a ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.b ) );
@ -1861,7 +1877,7 @@ struct _EngineConsoleThunk< startArgc, void( A, B, C, D, E, F, G, H, I ) >
fn( a, b, c, d, e, f, g, h, i );
}
template< typename Frame >
static void thunk( S32 argc, const char** argv, void ( Frame::*fn )( A, B, C, D, E, F, G, H, I ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E, F, G, H, I ) >& defaultArgs )
static void thunk( S32 argc, ConsoleValueRef *argv, void ( Frame::*fn )( A, B, C, D, E, F, G, H, I ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E, F, G, H, I ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.b ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.c ) );
@ -1881,7 +1897,7 @@ struct _EngineConsoleThunk< startArgc, R( A, B, C, D, E, F, G, H, I, J ) >
{
typedef typename _EngineConsoleThunkType< R >::ReturnType ReturnType;
static const S32 NUM_ARGS = 10 + startArgc;
static ReturnType thunk( S32 argc, const char** argv, R ( *fn )( A, B, C, D, E, F, G, H, I, J ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E, F, G, H, I, J ) >& defaultArgs )
static ReturnType thunk( S32 argc, ConsoleValueRef *argv, R ( *fn )( A, B, C, D, E, F, G, H, I, J ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E, F, G, H, I, J ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.a ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.b ) );
@ -1896,7 +1912,7 @@ struct _EngineConsoleThunk< startArgc, R( A, B, C, D, E, F, G, H, I, J ) >
return _EngineConsoleThunkReturnValue( fn( a, b, c, d, e, f, g, h, i, j ) );
}
template< typename Frame >
static ReturnType thunk( S32 argc, const char** argv, R ( Frame::*fn )( A, B, C, D, E, F, G, H, I, J ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E, F, G, H, I, J ) >& defaultArgs )
static ReturnType thunk( S32 argc, ConsoleValueRef *argv, R ( Frame::*fn )( A, B, C, D, E, F, G, H, I, J ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E, F, G, H, I, J ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.b ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.c ) );
@ -1916,7 +1932,7 @@ struct _EngineConsoleThunk< startArgc, void( A, B, C, D, E, F, G, H, I, J ) >
{
typedef void ReturnType;
static const S32 NUM_ARGS = 10 + startArgc;
static void thunk( S32 argc, const char** argv, void ( *fn )( A, B, C, D, E, F, G, H, I, J ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E, F, G, H, I, J ) >& defaultArgs )
static void thunk( S32 argc, ConsoleValueRef *argv, void ( *fn )( A, B, C, D, E, F, G, H, I, J ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E, F, G, H, I, J ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.a ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.b ) );
@ -1931,7 +1947,7 @@ struct _EngineConsoleThunk< startArgc, void( A, B, C, D, E, F, G, H, I, J ) >
fn( a, b, c, d, e, f, g, h, i, j );
}
template< typename Frame >
static void thunk( S32 argc, const char** argv, void ( Frame::*fn )( A, B, C, D, E, F, G, H, I, J ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E, F, G, H, I, J ) >& defaultArgs )
static void thunk( S32 argc, ConsoleValueRef *argv, void ( Frame::*fn )( A, B, C, D, E, F, G, H, I, J ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E, F, G, H, I, J ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.b ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.c ) );
@ -1951,7 +1967,7 @@ struct _EngineConsoleThunk< startArgc, R( A, B, C, D, E, F, G, H, I, J, K ) >
{
typedef typename _EngineConsoleThunkType< R >::ReturnType ReturnType;
static const S32 NUM_ARGS = 11 + startArgc;
static ReturnType thunk( S32 argc, const char** argv, R ( *fn )( A, B, C, D, E, F, G, H, I, J, K ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E, F, G, H, I, J, K ) >& defaultArgs )
static ReturnType thunk( S32 argc, ConsoleValueRef *argv, R ( *fn )( A, B, C, D, E, F, G, H, I, J, K ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E, F, G, H, I, J, K ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.a ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.b ) );
@ -1967,7 +1983,7 @@ struct _EngineConsoleThunk< startArgc, R( A, B, C, D, E, F, G, H, I, J, K ) >
return _EngineConsoleThunkReturnValue( fn( a, b, c, d, e, f, g, h, i, j, k ) );
}
template< typename Frame >
static ReturnType thunk( S32 argc, const char** argv, R ( Frame::*fn )( A, B, C, D, E, F, G, H, I, J, K ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E, F, G, H, I, J, K ) >& defaultArgs )
static ReturnType thunk( S32 argc, ConsoleValueRef *argv, R ( Frame::*fn )( A, B, C, D, E, F, G, H, I, J, K ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E, F, G, H, I, J, K ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.b ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.c ) );
@ -1988,7 +2004,7 @@ struct _EngineConsoleThunk< startArgc, void( A, B, C, D, E, F, G, H, I, J, K ) >
{
typedef void ReturnType;
static const S32 NUM_ARGS = 11 + startArgc;
static void thunk( S32 argc, const char** argv, void ( *fn )( A, B, C, D, E, F, G, H, I, J, K ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E, F, G, H, I, J, K ) >& defaultArgs )
static void thunk( S32 argc, ConsoleValueRef *argv, void ( *fn )( A, B, C, D, E, F, G, H, I, J, K ), const _EngineFunctionDefaultArguments< void( A, B, C, D, E, F, G, H, I, J, K ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.a ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.b ) );
@ -2004,7 +2020,7 @@ struct _EngineConsoleThunk< startArgc, void( A, B, C, D, E, F, G, H, I, J, K ) >
fn( a, b, c, d, e, f, g, h, i, j, k );
}
template< typename Frame >
static void thunk( S32 argc, const char** argv, void ( Frame::*fn )( A, B, C, D, E, F, G, H, I, J, K ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E, F, G, H, I, J, K ) >& defaultArgs )
static void thunk( S32 argc, ConsoleValueRef *argv, void ( Frame::*fn )( A, B, C, D, E, F, G, H, I, J, K ) const, Frame* frame, const _EngineFunctionDefaultArguments< void( typename Frame::ObjectType*, A, B, C, D, E, F, G, H, I, J, K ) >& defaultArgs )
{
A a = ( startArgc < argc ? EngineUnmarshallData< A >()( argv[ startArgc ] ) : A( defaultArgs.b ) );
B b = ( startArgc + 1 < argc ? EngineUnmarshallData< B >()( argv[ startArgc + 1 ] ) : B( defaultArgs.c ) );
@ -2088,7 +2104,7 @@ struct _EngineConsoleThunk< startArgc, void( A, B, C, D, E, F, G, H, I, J, K ) >
( void* ) &fn ## name, \
0 \
); \
static _EngineConsoleThunkType< returnType >::ReturnType _ ## name ## caster( SimObject*, S32 argc, const char** argv ) \
static _EngineConsoleThunkType< returnType >::ReturnType _ ## name ## caster( SimObject*, S32 argc, ConsoleValueRef *argv ) \
{ \
return _EngineConsoleThunkType< returnType >::ReturnType( _EngineConsoleThunk< 1, returnType args >::thunk( \
argc, argv, &_fn ## name ## impl, _fn ## name ## DefaultArgs \
@ -2168,7 +2184,7 @@ struct _EngineConsoleThunk< startArgc, void( A, B, C, D, E, F, G, H, I, J, K ) >
( void* ) &fn ## className ## _ ## name, \
0 \
); \
static _EngineConsoleThunkType< returnType >::ReturnType _ ## className ## name ## caster( SimObject* object, S32 argc, const char** argv ) \
static _EngineConsoleThunkType< returnType >::ReturnType _ ## className ## name ## caster( SimObject* object, S32 argc, ConsoleValueRef *argv ) \
{ \
_ ## className ## name ## frame frame; \
frame.object = static_cast< className* >( object ); \
@ -2225,7 +2241,7 @@ struct _EngineConsoleThunk< startArgc, void( A, B, C, D, E, F, G, H, I, J, K ) >
( void* ) &fn ## className ## _ ## name, \
0 \
); \
static _EngineConsoleThunkType< returnType >::ReturnType _ ## className ## name ## caster( SimObject*, S32 argc, const char** argv )\
static _EngineConsoleThunkType< returnType >::ReturnType _ ## className ## name ## caster( SimObject*, S32 argc, ConsoleValueRef *argv )\
{ \
return _EngineConsoleThunkType< returnType >::ReturnType( _EngineConsoleThunk< 1, returnType args >::thunk( \
argc, argv, &_fn ## className ## name ## impl, _fn ## className ## name ## DefaultArgs \
@ -2249,7 +2265,7 @@ struct _EngineConsoleThunk< startArgc, void( A, B, C, D, E, F, G, H, I, J, K ) >
#define DefineConsoleFunction( name, returnType, args, defaultArgs, usage ) \
static inline returnType _fn ## name ## impl args; \
static _EngineFunctionDefaultArguments< void args > _fn ## name ## DefaultArgs defaultArgs; \
static _EngineConsoleThunkType< returnType >::ReturnType _ ## name ## caster( SimObject*, S32 argc, const char** argv ) \
static _EngineConsoleThunkType< returnType >::ReturnType _ ## name ## caster( SimObject*, S32 argc, ConsoleValueRef *argv ) \
{ \
return _EngineConsoleThunkType< returnType >::ReturnType( _EngineConsoleThunk< 1, returnType args >::thunk( \
argc, argv, &_fn ## name ## impl, _fn ## name ## DefaultArgs \
@ -2274,7 +2290,7 @@ struct _EngineConsoleThunk< startArgc, void( A, B, C, D, E, F, G, H, I, J, K ) >
}; \
static _EngineFunctionDefaultArguments< _EngineMethodTrampoline< _ ## className ## name ## frame, void args >::FunctionType > \
_fn ## className ## name ## DefaultArgs defaultArgs; \
static _EngineConsoleThunkType< returnType >::ReturnType _ ## className ## name ## caster( SimObject* object, S32 argc, const char** argv ) \
static _EngineConsoleThunkType< returnType >::ReturnType _ ## className ## name ## caster( SimObject* object, S32 argc, ConsoleValueRef *argv ) \
{ \
_ ## className ## name ## frame frame; \
frame.object = static_cast< className* >( object ); \
@ -2296,7 +2312,7 @@ struct _EngineConsoleThunk< startArgc, void( A, B, C, D, E, F, G, H, I, J, K ) >
#define DefineConsoleStaticMethod( className, name, returnType, args, defaultArgs, usage ) \
static inline returnType _fn ## className ## name ## impl args; \
static _EngineFunctionDefaultArguments< void args > _fn ## className ## name ## DefaultArgs defaultArgs; \
static _EngineConsoleThunkType< returnType >::ReturnType _ ## className ## name ## caster( SimObject*, S32 argc, const char** argv )\
static _EngineConsoleThunkType< returnType >::ReturnType _ ## className ## name ## caster( SimObject*, S32 argc, ConsoleValueRef *argv )\
{ \
return _EngineConsoleThunkType< returnType >::ReturnType( _EngineConsoleThunk< 1, returnType args >::thunk( \
argc, argv, &_fn ## className ## name ## impl, _fn ## className ## name ## DefaultArgs \
@ -2532,79 +2548,79 @@ struct _EngineCallbackHelper
R call() const
{
typedef R( FunctionType )( EngineObject* );
return R( reinterpret_cast< FunctionType* >( mFn )( mThis ) );
return R( reinterpret_cast< FunctionType* >( const_cast<void*>(mFn) )( mThis ) );
}
template< typename R, typename A >
R call( A a ) const
{
typedef R( FunctionType )( EngineObject*, A );
return R( reinterpret_cast< FunctionType* >( mFn )( mThis, a ) );
return R( reinterpret_cast< FunctionType* >( const_cast<void*>(mFn) )( mThis, a ) );
}
template< typename R, typename A, typename B >
R call( A a, B b ) const
{
typedef R( FunctionType )( EngineObject*, A, B );
return R( reinterpret_cast< FunctionType* >( mFn )( mThis, a, b ) );
return R( reinterpret_cast< FunctionType* >( const_cast<void*>(mFn) )( mThis, a, b ) );
}
template< typename R, typename A, typename B, typename C >
R call( A a, B b, C c ) const
{
typedef R( FunctionType )( EngineObject*, A, B, C );
return R( reinterpret_cast< FunctionType* >( mFn )( mThis, a, b, c ) );
return R( reinterpret_cast< FunctionType* >( const_cast<void*>(mFn) )( mThis, a, b, c ) );
}
template< typename R, typename A, typename B, typename C, typename D >
R call( A a, B b, C c, D d ) const
{
typedef R( FunctionType )( EngineObject*, A, B, C, D );
return R( reinterpret_cast< FunctionType* >( mFn )( mThis, a, b, c, d ) );
return R( reinterpret_cast< FunctionType* >( const_cast<void*>(mFn) )( mThis, a, b, c, d ) );
}
template< typename R, typename A, typename B, typename C, typename D, typename E >
R call( A a, B b, C c, D d, E e ) const
{
typedef R( FunctionType )( EngineObject*, A, B, C, D, E );
return R( reinterpret_cast< FunctionType* >( mFn )( mThis, a, b, c, d, e ) );
return R( reinterpret_cast< FunctionType* >( const_cast<void*>(mFn) )( mThis, a, b, c, d, e ) );
}
template< typename R, typename A, typename B, typename C, typename D, typename E, typename F >
R call( A a, B b, C c, D d, E e, F f ) const
{
typedef R( FunctionType )( EngineObject*, A, B, C, D, E, F );
return R( reinterpret_cast< FunctionType* >( mFn )( mThis, a, b, c, d, e, f ) );
return R( reinterpret_cast< FunctionType* >( const_cast<void*>(mFn) )( mThis, a, b, c, d, e, f ) );
}
template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G >
R call( A a, B b, C c, D d, E e, F f, G g ) const
{
typedef R( FunctionType )( EngineObject*, A, B, C, D, E, F, G );
return R( reinterpret_cast< FunctionType* >( mFn )( mThis, a, b, c, d, e, f, g ) );
return R( reinterpret_cast< FunctionType* >( const_cast<void*>(mFn) )( mThis, a, b, c, d, e, f, g ) );
}
template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H >
R call( A a, B b, C c, D d, E e, F f, G g, H h ) const
{
typedef R( FunctionType )( EngineObject*, A, B, C, D, E, F, G, H );
return R( reinterpret_cast< FunctionType* >( mFn )( mThis, a, b, c, d, e, f, g, h ) );
return R( reinterpret_cast< FunctionType* >( const_cast<void*>(mFn) )( mThis, a, b, c, d, e, f, g, h ) );
}
template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I >
R call( A a, B b, C c, D d, E e, F f, G g, H h, I i ) const
{
typedef R( FunctionType )( EngineObject*, A, B, C, D, E, F, G, H, I );
return R( reinterpret_cast< FunctionType* >( mFn )( mThis, a, b, c, d, e, f, g, h, i ) );
return R( reinterpret_cast< FunctionType* >( const_cast<void*>(mFn) )( mThis, a, b, c, d, e, f, g, h, i ) );
}
template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J >
R call( A a, B b, C c, D d, E e, F f, G g, H h, I i, J j ) const
{
typedef R( FunctionType )( EngineObject*, A, B, C, D, E, F, G, H, I, J );
return R( reinterpret_cast< FunctionType* >( mFn )( mThis, a, b, c, d, e, f, g, h, i, j ) );
return R( reinterpret_cast< FunctionType* >( const_cast<void*>(mFn) )( mThis, a, b, c, d, e, f, g, h, i, j ) );
}
template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K >
R call( A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k ) const
{
typedef R( FunctionType )( EngineObject*, A, B, C, D, E, F, G, H, I, J, K );
return R( reinterpret_cast< FunctionType* >( mFn )( mThis, a, b, c, d, e, f, g, h, i, j, k ) );
return R( reinterpret_cast< FunctionType* >( const_cast<void*>(mFn) )( mThis, a, b, c, d, e, f, g, h, i, j, k ) );
}
template< typename R, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L >
R call( A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l ) const
{
typedef R( FunctionType )( EngineObject*, A, B, C, D, E, F, G, H, I, J, K, L l );
return R( reinterpret_cast< FunctionType* >( mFn )( mThis, a, b, c, d, e, f, g, h, i, j, k, l ) );
return R( reinterpret_cast< FunctionType* >( const_cast<void*>(mFn) )( mThis, a, b, c, d, e, f, g, h, i, j, k, l ) );
}
};
@ -2619,14 +2635,19 @@ struct _EngineConsoleCallbackHelper
SimObject* mThis;
S32 mArgc;
const char* mArgv[ MAX_ARGUMENTS + 2 ];
ConsoleValueRef mArgv[ MAX_ARGUMENTS + 2 ];
const char* _exec()
{
if( mThis )
{
// Cannot invoke callback until object has been registered
return mThis->isProperlyAdded() ? Con::execute( mThis, mArgc, mArgv ) : "";
if (mThis->isProperlyAdded()) {
return Con::execute( mThis, mArgc, mArgv );
} else {
Con::resetStackFrame(); // We might have pushed some vars here
return "";
}
}
else
return Con::execute( mArgc, mArgv );
@ -2788,7 +2809,6 @@ struct _EngineConsoleCallbackHelper
// Re-enable some VC warnings we disabled for this file.
#pragma warning( default : 4510 )
#pragma warning( default : 4610 )
#pragma warning( pop ) // 4510 and 4610
#endif // !_ENGINEAPI_H_

View file

@ -114,7 +114,7 @@ static void dumpVariable( Stream& stream,
{
// Skip variables defined in script.
if( entry->type < 0 )
if( entry->value.type < 0 )
return;
// Skip internals... don't export them.
@ -149,7 +149,7 @@ static void dumpVariable( Stream& stream,
// Skip variables for which we can't decipher their type.
ConsoleBaseType* type = ConsoleBaseType::getType( entry->type );
ConsoleBaseType* type = ConsoleBaseType::getType( entry->value.type );
if( !type )
{
Con::errorf( "Can't find type for variable '%s'", entry->name );

View file

@ -383,7 +383,7 @@ ConsoleMethod(FieldBrushObject, copyFields, void, 3, 4, "(simObject, [fieldList]
}
// Fetch field list.
const char* pFieldList = (argc > 3 ) ? argv[3] : NULL;
const char* pFieldList = (argc > 3 ) ? (const char*)argv[3] : NULL;
// Copy Fields.
object->copyFields( pSimObject, pFieldList );

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