mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-03-02 20:10:32 +00:00
Merge branch 'Preview4_0' into alpha40_HiddenHugs
This commit is contained in:
commit
9c71d5eace
570 changed files with 17252 additions and 8836 deletions
|
|
@ -40,6 +40,8 @@
|
|||
#include "assets/assetPtr.h"
|
||||
#endif
|
||||
|
||||
#include "gfx/gfxStringEnumTranslate.h"
|
||||
|
||||
// Debug Profiling.
|
||||
#include "platform/profiler.h"
|
||||
|
||||
|
|
@ -128,7 +130,30 @@ void ImageAsset::initPersistFields()
|
|||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//Utility function to 'fill out' bindings and resources with a matching asset if one exists
|
||||
bool ImageAsset::getAssetByFilename(StringTableEntry fileName, AssetPtr<ImageAsset>* imageAsset)
|
||||
{
|
||||
AssetQuery query;
|
||||
S32 foundAssetcount = AssetDatabase.findAssetLooseFile(&query, fileName);
|
||||
if (foundAssetcount == 0)
|
||||
{
|
||||
//Didn't find any assets, so have us fall back to a placeholder asset
|
||||
imageAsset->setAssetId(StringTable->insert("Core_Rendering:noshape"));
|
||||
|
||||
if (!imageAsset->isNull())
|
||||
return true;
|
||||
|
||||
//That didn't work, so fail out
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//acquire and bind the asset, and return it out
|
||||
imageAsset->setAssetId(query.mAssetList[0]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void ImageAsset::copyTo(SimObject* object)
|
||||
{
|
||||
// Call to parent.
|
||||
|
|
@ -180,9 +205,49 @@ void ImageAsset::setImageFileName(const char* pScriptFile)
|
|||
mImageFileName = StringTable->insert(pScriptFile);
|
||||
}
|
||||
|
||||
GFXTexHandle ImageAsset::getImage(GFXTextureProfile requestedProfile)
|
||||
{
|
||||
/*if (mResourceMap.contains(requestedProfile))
|
||||
{
|
||||
return mResourceMap.find(requestedProfile)->value;
|
||||
}
|
||||
else
|
||||
{
|
||||
//If we don't have an existing map case to the requested format, we'll just create it and insert it in
|
||||
GFXTexHandle newImage;
|
||||
newImage.set(mImageFileName, &requestedProfile, avar("%s() - mImage (line %d)", __FUNCTION__, __LINE__));
|
||||
mResourceMap.insert(requestedProfile, newImage);
|
||||
|
||||
return newImage;
|
||||
}*/
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* ImageAsset::getImageInfo()
|
||||
{
|
||||
if (mIsValidImage)
|
||||
{
|
||||
static const U32 bufSize = 2048;
|
||||
char* returnBuffer = Con::getReturnBuffer(bufSize);
|
||||
dSprintf(returnBuffer, bufSize, "%s %d %d %d", GFXStringTextureFormat[mImage.getFormat()], mImage.getHeight(), mImage.getWidth(), mImage.getDepth());
|
||||
|
||||
return returnBuffer;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
DefineEngineMethod(ImageAsset, getImageFilename, const char*, (), ,
|
||||
"Creates an instance of the given GameObject given the asset definition.\n"
|
||||
"@return The GameObject entity created from the asset.")
|
||||
{
|
||||
return object->getImageFileName();
|
||||
}
|
||||
|
||||
DefineEngineMethod(ImageAsset, getImageInfo, const char*, (), ,
|
||||
"Creates an instance of the given GameObject given the asset definition.\n"
|
||||
"@return The GameObject entity created from the asset.")
|
||||
{
|
||||
return object->getImageInfo();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,9 @@
|
|||
#ifndef _ASSET_FIELD_TYPES_H_
|
||||
#include "assets/assetFieldTypes.h"
|
||||
#endif
|
||||
#ifndef _ASSET_PTR_H_
|
||||
#include "assets/assetPtr.h"
|
||||
#endif
|
||||
|
||||
#include "gfx/bitmap/gBitmap.h"
|
||||
#include "gfx/gfxTextureHandle.h"
|
||||
|
|
@ -74,6 +77,8 @@ protected:
|
|||
|
||||
ImageTypes mImageType;
|
||||
|
||||
Map<GFXTextureProfile, GFXTexHandle> mResourceMap;
|
||||
|
||||
public:
|
||||
ImageAsset();
|
||||
virtual ~ImageAsset();
|
||||
|
|
@ -90,7 +95,9 @@ public:
|
|||
|
||||
bool isValid() { return mIsValidImage; }
|
||||
|
||||
GFXTexHandle getImage() { return mImage; }
|
||||
GFXTexHandle getImage(GFXTextureProfile requestedProfile);
|
||||
|
||||
const char* getImageInfo();
|
||||
|
||||
protected:
|
||||
virtual void initializeAsset(void);
|
||||
|
|
@ -100,6 +107,8 @@ protected:
|
|||
static const char* getImageFileName(void* obj, const char* data) { return static_cast<ImageAsset*>(obj)->getImageFileName(); }
|
||||
|
||||
void loadImage();
|
||||
|
||||
bool getAssetByFilename(StringTableEntry fileName, AssetPtr<ImageAsset>* imageAsset);
|
||||
};
|
||||
|
||||
DefineConsoleType(TypeImageAssetPtr, ImageAsset)
|
||||
|
|
|
|||
|
|
@ -288,6 +288,66 @@ bool ShapeAsset::loadShape()
|
|||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//Utility function to 'fill out' bindings and resources with a matching asset if one exists
|
||||
bool ShapeAsset::getAssetByFilename(StringTableEntry fileName, AssetPtr<ShapeAsset>* shapeAsset)
|
||||
{
|
||||
AssetQuery query;
|
||||
S32 foundAssetcount = AssetDatabase.findAssetLooseFile(&query, fileName);
|
||||
if (foundAssetcount == 0)
|
||||
{
|
||||
//Didn't find any assets
|
||||
//If possible, see if we can run an in-place import and the get the asset from that
|
||||
#if TORQUE_DEBUG
|
||||
Con::warnf("ShapeAsset::getAssetByFilename - Attempted to in-place import a shapefile(%s) that had no associated asset", fileName);
|
||||
#endif
|
||||
|
||||
ConsoleValueRef result = Con::executef("importLooseFile", fileName, true);
|
||||
|
||||
if (result.getBoolValue())
|
||||
{
|
||||
StringTableEntry resultingAssetId = StringTable->insert(Con::getVariable("$importedLooseFileAsset"));
|
||||
|
||||
if (resultingAssetId != StringTable->EmptyString())
|
||||
{
|
||||
shapeAsset->setAssetId(resultingAssetId);
|
||||
|
||||
if (!shapeAsset->isNull())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//Didn't work, so have us fall back to a placeholder asset
|
||||
shapeAsset->setAssetId(StringTable->insert("Core_Rendering:noshape"));
|
||||
|
||||
if (!shapeAsset->isNull())
|
||||
return true;
|
||||
|
||||
//That didn't work, so fail out
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//acquire and bind the asset, and return it out
|
||||
shapeAsset->setAssetId(query.mAssetList[0]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool ShapeAsset::getAssetById(StringTableEntry assetId, AssetPtr<ShapeAsset>* shapeAsset)
|
||||
{
|
||||
shapeAsset->setAssetId(assetId);
|
||||
if (!shapeAsset->isNull())
|
||||
return true;
|
||||
|
||||
//Didn't work, so have us fall back to a placeholder asset
|
||||
shapeAsset->setAssetId(StringTable->insert("Core_Rendering:noshape"));
|
||||
|
||||
if (!shapeAsset->isNull())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void ShapeAsset::copyTo(SimObject* object)
|
||||
|
|
|
|||
|
|
@ -128,6 +128,9 @@ public:
|
|||
void setShapeConstructorFile(const char* pScriptFile);
|
||||
inline StringTableEntry getShapeConstructorFile(void) const { return mConstructorFileName; };
|
||||
|
||||
static bool getAssetByFilename(StringTableEntry fileName, AssetPtr<ShapeAsset>* shapeAsset);
|
||||
static bool getAssetById(StringTableEntry assetId, AssetPtr<ShapeAsset>* shapeAsset);
|
||||
|
||||
protected:
|
||||
virtual void onAssetRefresh(void);
|
||||
|
||||
|
|
|
|||
|
|
@ -948,7 +948,7 @@ void GroundCover::_initialize( U32 cellCount, U32 cellPlacementCount )
|
|||
if (!mat->mDiffuseMapFilename[0].isEmpty())
|
||||
tex = GFXTexHandle(mat->mDiffuseMapFilename[0], &GFXStaticTextureSRGBProfile, "GroundCover texture aspect ratio check");
|
||||
else if (!mat->mDiffuseMapAsset[0].isNull())
|
||||
tex = mat->mDiffuseMapAsset[0]->getImage();
|
||||
tex = mat->mDiffuseMapAsset[0]->getImage(GFXStaticTextureSRGBProfile);
|
||||
|
||||
if(tex.isValid())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1172,6 +1172,8 @@ void ParticleEmitter::prepRenderImage(SceneRenderState* state)
|
|||
|
||||
ri->bbModelViewProj = renderManager->allocUniqueXform( *ri->modelViewProj * mBBObjToWorld );
|
||||
|
||||
ri->wsPosition = getWorldTransform().getPosition();
|
||||
|
||||
ri->count = n_parts;
|
||||
|
||||
ri->blendStyle = mDataBlock->blendStyle;
|
||||
|
|
|
|||
|
|
@ -404,6 +404,12 @@ void GameBase::processTick(const Move * move)
|
|||
#endif
|
||||
}
|
||||
|
||||
void GameBase::interpolateTick(F32 dt)
|
||||
{
|
||||
// PATHSHAPE
|
||||
updateRenderChangesByParent();
|
||||
// PATHSHAPE END
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
F32 GameBase::getUpdatePriority(CameraScopeQuery *camInfo, U32 updateMask, S32 updateSkips)
|
||||
|
|
@ -471,14 +477,15 @@ F32 GameBase::getUpdatePriority(CameraScopeQuery *camInfo, U32 updateMask, S32 u
|
|||
// Weight by updateSkips
|
||||
F32 wSkips = updateSkips * 0.5;
|
||||
|
||||
// Calculate final priority, should total to about 1.0f
|
||||
// Calculate final priority, should total to about 1.0f (plus children)
|
||||
//
|
||||
return
|
||||
wFov * sUpFov +
|
||||
wDistance * sUpDistance +
|
||||
wVelocity * sUpVelocity +
|
||||
wSkips * sUpSkips +
|
||||
wInterest * sUpInterest;
|
||||
wInterest * sUpInterest +
|
||||
getNumChildren();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
|
@ -757,3 +764,44 @@ DefineEngineMethod( GameBase, applyRadialImpulse, void, ( Point3F origin, F32 ra
|
|||
{
|
||||
object->applyRadialImpulse( origin, radius, magnitude );
|
||||
}
|
||||
|
||||
// PATHSHAPE
|
||||
// Console Methods for attach children. can't put them in sceneobject because //
|
||||
// we want the processafter functions////////////////////////////////////////////
|
||||
|
||||
DefineEngineMethod(GameBase, attachChild, bool, (GameBase* _subObject), (nullAsType<GameBase*>()), "(SceneObject subObject)"
|
||||
"attach an object to this one, preserving its present transform.")
|
||||
{
|
||||
if (_subObject != nullptr)
|
||||
{
|
||||
if (_subObject->getParent() != object){
|
||||
Con::errorf("Object is (%d)", _subObject->getId());
|
||||
_subObject->clearProcessAfter();
|
||||
_subObject->processAfter(object);
|
||||
return object->attachChild(_subObject);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Con::errorf("Couldn't addObject()!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DefineEngineMethod(GameBase, detachChild, bool, (GameBase* _subObject), (nullAsType<GameBase*>()), "(SceneObject subObject)"
|
||||
"attach an object to this one, preserving its present transform.")
|
||||
{
|
||||
if (_subObject != nullptr)
|
||||
{
|
||||
_subObject->clearProcessAfter();
|
||||
return _subObject->attachToParent(NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}//end
|
||||
// PATHSHAPE END
|
||||
|
|
|
|||
|
|
@ -356,7 +356,7 @@ public:
|
|||
/// @name Network
|
||||
/// @see NetObject, NetConnection
|
||||
/// @{
|
||||
|
||||
void interpolateTick(F32 dt);
|
||||
F32 getUpdatePriority( CameraScopeQuery *focusObject, U32 updateMask, S32 updateSkips );
|
||||
U32 packUpdate ( NetConnection *conn, U32 mask, BitStream *stream );
|
||||
void unpackUpdate( NetConnection *conn, BitStream *stream );
|
||||
|
|
|
|||
|
|
@ -665,6 +665,9 @@ static void RegisterGameFunctions()
|
|||
Con::setIntVariable("$TypeMasks::DebrisObjectType", DebrisObjectType);
|
||||
Con::setIntVariable("$TypeMasks::PhysicalZoneObjectType", PhysicalZoneObjectType);
|
||||
Con::setIntVariable("$TypeMasks::LightObjectType", LightObjectType);
|
||||
// PATHSHAPE
|
||||
Con::setIntVariable("$TypeMasks::PathShapeObjectType", PathShapeObjectType);
|
||||
// PATHSHAPE END
|
||||
|
||||
Con::addVariable("Ease::InOut", TypeS32, &gEaseInOut,
|
||||
"InOut ease for curve movement.\n"
|
||||
|
|
|
|||
|
|
@ -618,6 +618,9 @@ void Item::interpolateTick(F32 dt)
|
|||
mat.setColumn(3,pos);
|
||||
setRenderTransform(mat);
|
||||
mDelta.dt = dt;
|
||||
// PATHSHAPE
|
||||
updateRenderChangesByParent();
|
||||
// PATHSHAPE END
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -98,8 +98,8 @@ void LightBase::initPersistFields()
|
|||
addField( "color", TypeColorF, Offset( mColor, LightBase ), "Changes the base color hue of the light." );
|
||||
addField( "brightness", TypeF32, Offset( mBrightness, LightBase ), "Adjusts the lights power, 0 being off completely." );
|
||||
addField( "castShadows", TypeBool, Offset( mCastShadows, LightBase ), "Enables/disabled shadow casts by this light." );
|
||||
addField( "staticRefreshFreq", TypeS32, Offset( mStaticRefreshFreq, LightBase ), "static shadow refresh rate (milliseconds)" );
|
||||
addField( "dynamicRefreshFreq", TypeS32, Offset( mDynamicRefreshFreq, LightBase ), "dynamic shadow refresh rate (milliseconds)");
|
||||
//addField( "staticRefreshFreq", TypeS32, Offset( mStaticRefreshFreq, LightBase ), "static shadow refresh rate (milliseconds)" );
|
||||
//addField( "dynamicRefreshFreq", TypeS32, Offset( mDynamicRefreshFreq, LightBase ), "dynamic shadow refresh rate (milliseconds)");
|
||||
addField( "priority", TypeF32, Offset( mPriority, LightBase ), "Used for sorting of lights by the light manager. "
|
||||
"Priority determines if a light has a stronger effect than, those with a lower value" );
|
||||
|
||||
|
|
|
|||
|
|
@ -162,6 +162,12 @@ enum SceneObjectTypes
|
|||
#if defined(AFX_CAP_AFXMODEL_TYPE)
|
||||
afxModelObjectType = BIT(26)
|
||||
#endif
|
||||
|
||||
// PATHSHAPE
|
||||
PathShapeObjectType = BIT( 28 ),
|
||||
// PATHSHAPE END
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
||||
enum SceneObjectTypeMasks : U32
|
||||
|
|
|
|||
588
Engine/source/T3D/pathShape.cpp
Normal file
588
Engine/source/T3D/pathShape.cpp
Normal file
|
|
@ -0,0 +1,588 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
// @author Stefan "Beffy" Moises
|
||||
// this is a modified version of PathCamera that allows to move shapes along paths
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "math/mMath.h"
|
||||
#include "math/mathIO.h"
|
||||
#include "console/simBase.h"
|
||||
#include "console/console.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "core/stream/bitStream.h"
|
||||
#include "core/dnet.h"
|
||||
#include "scene/pathManager.h"
|
||||
#include "T3D/gameFunctions.h"
|
||||
#include "T3D/gameBase/gameConnection.h"
|
||||
#include "gui/worldEditor/editor.h"
|
||||
#include "console/engineAPI.h"
|
||||
#include "math/mTransform.h"
|
||||
|
||||
#include "T3D/pathShape.h"
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_CO_DATABLOCK_V1(PathShapeData);
|
||||
|
||||
void PathShapeData::consoleInit()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool PathShapeData::preload(bool server, String &errorStr)
|
||||
{
|
||||
|
||||
if(!Parent::preload(server, errorStr))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PathShapeData::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
void PathShapeData::packData(BitStream* stream)
|
||||
{
|
||||
Parent::packData(stream);
|
||||
}
|
||||
|
||||
void PathShapeData::unpackData(BitStream* stream)
|
||||
{
|
||||
Parent::unpackData(stream);
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_CO_NETOBJECT_V1(PathShape);
|
||||
|
||||
PathShape::PathShape()
|
||||
{
|
||||
mNetFlags.set(Ghostable|ScopeAlways);
|
||||
mTypeMask |= PathShapeObjectType | StaticShapeObjectType;
|
||||
delta.time = 0;
|
||||
delta.timeVec = 0;
|
||||
mDataBlock = NULL;
|
||||
mState = Forward;
|
||||
mNodeBase = 0;
|
||||
mNodeCount = 0;
|
||||
mPosition = 0;
|
||||
mTarget = 0;
|
||||
mTargetSet = false;
|
||||
|
||||
MatrixF mat(1);
|
||||
mat.setPosition(Point3F(0,0,700));
|
||||
Parent::setTransform(mat);
|
||||
|
||||
mLastXform = mat;
|
||||
for (U32 i = 0; i < 4; i++)
|
||||
{
|
||||
mControl[i] = StringTable->insert("");
|
||||
}
|
||||
}
|
||||
|
||||
PathShape::~PathShape()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
bool PathShape::onAdd()
|
||||
{
|
||||
if(!Parent::onAdd() && !mDataBlock)
|
||||
return false;
|
||||
|
||||
mTypeMask |= PathShapeObjectType | StaticShapeObjectType;
|
||||
// Initialize from the current transform.
|
||||
if (!mNodeCount) {
|
||||
QuatF rot(getTransform());
|
||||
Point3F pos = getPosition();
|
||||
mSpline.removeAll();
|
||||
mSpline.push_back(new CameraSpline::Knot(pos,rot,1,
|
||||
CameraSpline::Knot::NORMAL, CameraSpline::Knot::SPLINE));
|
||||
mNodeCount = 1;
|
||||
}
|
||||
|
||||
if (isServerObject()) scriptOnAdd();
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void PathShape::onRemove()
|
||||
{
|
||||
scriptOnRemove();
|
||||
removeFromScene();
|
||||
|
||||
unmount();
|
||||
Parent::onRemove();
|
||||
|
||||
if (isGhost())
|
||||
for (S32 i = 0; i < MaxSoundThreads; i++)
|
||||
stopAudio(i);
|
||||
}
|
||||
|
||||
bool PathShape::onNewDataBlock(GameBaseData* dptr, bool reload)
|
||||
{
|
||||
mDataBlock = dynamic_cast<PathShapeData*>(dptr);
|
||||
if (!mDataBlock || !Parent::onNewDataBlock(dptr, reload))
|
||||
return false;
|
||||
|
||||
scriptOnNewDataBlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
PathShapeData::PathShapeData()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void PathShape::initPersistFields()
|
||||
{
|
||||
|
||||
addField( "Path", TYPEID< SimObjectRef<SimPath::Path> >(), Offset( mSimPath, PathShape ),
|
||||
"@brief Name of a Path to follow." );
|
||||
|
||||
addField("Controler", TypeString, Offset(mControl, PathShape), 4, "controlers");
|
||||
|
||||
Parent::initPersistFields();
|
||||
|
||||
}
|
||||
|
||||
void PathShape::consoleInit()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void PathShape::processTick(const Move* move)
|
||||
{
|
||||
// client and server
|
||||
Parent::processTick(move);
|
||||
|
||||
// Move to new time
|
||||
advancePosition(TickMs);
|
||||
|
||||
MatrixF mat;
|
||||
interpolateMat(mPosition,&mat);
|
||||
Parent::setTransform(mat);
|
||||
|
||||
updateContainer();
|
||||
}
|
||||
|
||||
void PathShape::interpolateTick(F32 dt)
|
||||
{
|
||||
Parent::interpolateTick(dt);
|
||||
MatrixF mat;
|
||||
interpolateMat(delta.time + (delta.timeVec * dt),&mat);
|
||||
Parent::setRenderTransform(mat);
|
||||
}
|
||||
|
||||
void PathShape::interpolateMat(F32 pos,MatrixF* mat)
|
||||
{
|
||||
CameraSpline::Knot knot;
|
||||
mSpline.value(pos - mNodeBase,&knot);
|
||||
knot.mRotation.setMatrix(mat);
|
||||
mat->setPosition(knot.mPosition);
|
||||
}
|
||||
|
||||
void PathShape::advancePosition(S32 ms)
|
||||
{
|
||||
delta.timeVec = mPosition;
|
||||
|
||||
// Advance according to current speed
|
||||
if (mState == Forward) {
|
||||
mPosition = mSpline.advanceTime(mPosition - mNodeBase,ms);
|
||||
if (mPosition > F32(mNodeCount - 1))
|
||||
mPosition = F32(mNodeCount - 1);
|
||||
mPosition += (F32)mNodeBase;
|
||||
if (mTargetSet && mPosition >= mTarget) {
|
||||
mTargetSet = false;
|
||||
mPosition = mTarget;
|
||||
mState = Stop;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (mState == Backward) {
|
||||
mPosition = mSpline.advanceTime(mPosition - mNodeBase,-ms);
|
||||
if (mPosition < 0)
|
||||
mPosition = 0;
|
||||
mPosition += mNodeBase;
|
||||
if (mTargetSet && mPosition <= mTarget) {
|
||||
mTargetSet = false;
|
||||
mPosition = mTarget;
|
||||
mState = Stop;
|
||||
}
|
||||
}
|
||||
|
||||
// Script callbacks
|
||||
if (int(mPosition) != int(delta.timeVec))
|
||||
onNode(int(mPosition));
|
||||
|
||||
// Set frame interpolation
|
||||
delta.time = mPosition;
|
||||
delta.timeVec -= mPosition;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
void PathShape::setPosition(F32 pos)
|
||||
{
|
||||
mPosition = mClampF(pos,mNodeBase,mNodeBase + mNodeCount - 1);
|
||||
MatrixF mat;
|
||||
interpolateMat(mPosition,&mat);
|
||||
Parent::setTransform(mat);
|
||||
setMaskBits(PositionMask);
|
||||
}
|
||||
|
||||
void PathShape::setTarget(F32 pos)
|
||||
{
|
||||
mTarget = pos;
|
||||
mTargetSet = true;
|
||||
if (mTarget > mPosition)
|
||||
mState = Forward;
|
||||
else
|
||||
if (mTarget < mPosition)
|
||||
mState = Backward;
|
||||
else {
|
||||
mTargetSet = false;
|
||||
mState = Stop;
|
||||
}
|
||||
setMaskBits(TargetMask | StateMask);
|
||||
}
|
||||
|
||||
void PathShape::setState(State s)
|
||||
{
|
||||
mState = s;
|
||||
setMaskBits(StateMask);
|
||||
}
|
||||
|
||||
S32 PathShape::getState()
|
||||
{
|
||||
return mState;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void PathShape::reset(F32 speed)
|
||||
{
|
||||
CameraSpline::Knot *knot = new CameraSpline::Knot;
|
||||
mSpline.value(mPosition - mNodeBase,knot);
|
||||
if (speed)
|
||||
knot->mSpeed = speed;
|
||||
mSpline.removeAll();
|
||||
mSpline.push_back(knot);
|
||||
|
||||
mNodeBase = 0;
|
||||
mNodeCount = 1;
|
||||
mPosition = 0;
|
||||
mTargetSet = false;
|
||||
mState = Forward;
|
||||
setMaskBits(StateMask | PositionMask | WindowMask | TargetMask);
|
||||
}
|
||||
|
||||
void PathShape::pushBack(CameraSpline::Knot *knot)
|
||||
{
|
||||
// Make room at the end
|
||||
if (mNodeCount == NodeWindow) {
|
||||
delete mSpline.remove(mSpline.getKnot(0));
|
||||
mNodeBase++;
|
||||
}
|
||||
else
|
||||
mNodeCount++;
|
||||
|
||||
// Fill in the new node
|
||||
mSpline.push_back(knot);
|
||||
setMaskBits(WindowMask);
|
||||
|
||||
// Make sure the position doesn't fall off
|
||||
if (mPosition < mNodeBase) {
|
||||
mPosition = mNodeBase;
|
||||
setMaskBits(PositionMask);
|
||||
}
|
||||
}
|
||||
|
||||
void PathShape::pushFront(CameraSpline::Knot *knot)
|
||||
{
|
||||
// Make room at the front
|
||||
if (mNodeCount == NodeWindow)
|
||||
delete mSpline.remove(mSpline.getKnot(mNodeCount));
|
||||
else
|
||||
mNodeCount++;
|
||||
mNodeBase--;
|
||||
|
||||
// Fill in the new node
|
||||
mSpline.push_front(knot);
|
||||
setMaskBits(WindowMask);
|
||||
|
||||
// Make sure the position doesn't fall off
|
||||
if (mPosition > mNodeBase + (NodeWindow - 1)) {
|
||||
mPosition = mNodeBase + (NodeWindow - 1);
|
||||
setMaskBits(PositionMask);
|
||||
}
|
||||
}
|
||||
|
||||
void PathShape::popFront()
|
||||
{
|
||||
if (mNodeCount < 2)
|
||||
return;
|
||||
|
||||
// Remove the first node. Node base and position are unaffected.
|
||||
mNodeCount--;
|
||||
delete mSpline.remove(mSpline.getKnot(0));
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void PathShape::onNode(S32 node)
|
||||
{
|
||||
if (!isGhost())
|
||||
Con::executef(mDataBlock,"onNode",getIdString(), Con::getIntArg(node));
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
U32 PathShape::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
|
||||
{
|
||||
|
||||
Parent::packUpdate(con,mask,stream);
|
||||
|
||||
if (stream->writeFlag(mask & StateMask))
|
||||
stream->writeInt(mState,StateBits);
|
||||
|
||||
if (stream->writeFlag(mask & PositionMask))
|
||||
stream->write(mPosition);
|
||||
|
||||
if (stream->writeFlag(mask & TargetMask))
|
||||
if (stream->writeFlag(mTargetSet))
|
||||
stream->write(mTarget);
|
||||
|
||||
if (stream->writeFlag(mask & WindowMask)) {
|
||||
stream->write(mNodeBase);
|
||||
stream->write(mNodeCount);
|
||||
for (S32 i = 0; i < mNodeCount; i++) {
|
||||
CameraSpline::Knot *knot = mSpline.getKnot(i);
|
||||
mathWrite(*stream, knot->mPosition);
|
||||
mathWrite(*stream, knot->mRotation);
|
||||
stream->write(knot->mSpeed);
|
||||
stream->writeInt(knot->mType, CameraSpline::Knot::NUM_TYPE_BITS);
|
||||
stream->writeInt(knot->mPath, CameraSpline::Knot::NUM_PATH_BITS);
|
||||
}
|
||||
}
|
||||
|
||||
// The rest of the data is part of the control object packet update.
|
||||
// If we're controlled by this client, we don't need to send it.
|
||||
if(stream->writeFlag(getControllingClient() == con && !(mask & InitialUpdateMask)))
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PathShape::unpackUpdate(NetConnection *con, BitStream *stream)
|
||||
{
|
||||
Parent::unpackUpdate(con,stream);
|
||||
|
||||
// StateMask
|
||||
if (stream->readFlag())
|
||||
mState = stream->readInt(StateBits);
|
||||
|
||||
// PositionMask
|
||||
if (stream->readFlag()) {
|
||||
stream->read(&mPosition);
|
||||
delta.time = mPosition;
|
||||
delta.timeVec = 0;
|
||||
}
|
||||
|
||||
// TargetMask
|
||||
if (stream->readFlag()) {
|
||||
mTargetSet = stream->readFlag();
|
||||
if (mTargetSet) {
|
||||
stream->read(&mTarget);
|
||||
}
|
||||
}
|
||||
|
||||
// WindowMask
|
||||
if (stream->readFlag()) {
|
||||
mSpline.removeAll();
|
||||
stream->read(&mNodeBase);
|
||||
stream->read(&mNodeCount);
|
||||
for (S32 i = 0; i < mNodeCount; i++) {
|
||||
CameraSpline::Knot *knot = new CameraSpline::Knot();
|
||||
mathRead(*stream, &knot->mPosition);
|
||||
mathRead(*stream, &knot->mRotation);
|
||||
stream->read(&knot->mSpeed);
|
||||
knot->mType = (CameraSpline::Knot::Type)stream->readInt(CameraSpline::Knot::NUM_TYPE_BITS);
|
||||
knot->mPath = (CameraSpline::Knot::Path)stream->readInt(CameraSpline::Knot::NUM_PATH_BITS);
|
||||
mSpline.push_back(knot);
|
||||
}
|
||||
}
|
||||
|
||||
// Controlled by the client?
|
||||
if (stream->readFlag()) return;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Console access methods
|
||||
//-----------------------------------------------------------------------------
|
||||
DefineEngineMethod(PathShape, setPosition, void, (F32 position), (0.0f), "Set the current position of the camera along the path.\n"
|
||||
"@param position Position along the path, from 0.0 (path start) - 1.0 (path end), to place the camera.\n"
|
||||
"@tsexample\n"
|
||||
"// Set the camera on a position along its path from 0.0 - 1.0.\n"
|
||||
"%position = \"0.35\";\n\n"
|
||||
"// Force the pathCamera to its new position along the path.\n"
|
||||
"%pathCamera.setPosition(%position);\n"
|
||||
"@endtsexample\n")
|
||||
{
|
||||
object->setPosition(position);
|
||||
}
|
||||
|
||||
DefineEngineMethod(PathShape, setTarget, void, (F32 position), (1.0f), "@brief Set the movement target for this camera along its path.\n\n"
|
||||
"The camera will attempt to move along the path to the given target in the direction provided "
|
||||
"by setState() (the default is forwards). Once the camera moves past this target it will come "
|
||||
"to a stop, and the target state will be cleared.\n"
|
||||
"@param position Target position, between 0.0 (path start) and 1.0 (path end), for the camera to move to along its path.\n"
|
||||
"@tsexample\n"
|
||||
"// Set the position target, between 0.0 (path start) and 1.0 (path end), for this camera to move to.\n"
|
||||
"%position = \"0.50\";\n\n"
|
||||
"// Inform the pathCamera of the new target position it will move to.\n"
|
||||
"%pathCamera.setTarget(%position);\n"
|
||||
"@endtsexample\n")
|
||||
{
|
||||
object->setTarget(position);
|
||||
}
|
||||
|
||||
DefineEngineMethod(PathShape, setState, void, (const char* newState), ("forward"), "Set the movement state for this path camera.\n"
|
||||
"@param newState New movement state type for this camera. Forward, Backward or Stop.\n"
|
||||
"@tsexample\n"
|
||||
"// Set the state type (forward, backward, stop).\n"
|
||||
"// In this example, the camera will travel from the first node\n"
|
||||
"// to the last node (or target if given with setTarget())\n"
|
||||
"%state = \"forward\";\n\n"
|
||||
"// Inform the pathCamera to change its movement state to the defined value.\n"
|
||||
"%pathCamera.setState(%state);\n"
|
||||
"@endtsexample\n")
|
||||
{
|
||||
if (!dStricmp(newState, "forward"))
|
||||
object->setState(PathShape::Forward);
|
||||
else
|
||||
if (!dStricmp(newState, "backward"))
|
||||
object->setState(PathShape::Backward);
|
||||
else
|
||||
object->setState(PathShape::Stop);
|
||||
}
|
||||
|
||||
DefineEngineMethod(PathShape, reset, void, (F32 speed), (1.0f), "@brief Clear the camera's path and set the camera's current transform as the start of the new path.\n\n"
|
||||
"What specifically occurs is a new knot is created from the camera's current transform. Then the current path "
|
||||
"is cleared and the new knot is pushed onto the path. Any previous target is cleared and the camera's movement "
|
||||
"state is set to Forward. The camera is now ready for a new path to be defined.\n"
|
||||
"@param speed Speed for the camera to move along its path after being reset.\n"
|
||||
"@tsexample\n"
|
||||
"//Determine the new movement speed of this camera. If not set, the speed will default to 1.0.\n"
|
||||
"%speed = \"0.50\";\n\n"
|
||||
"// Inform the path camera to start a new path at"
|
||||
"// the camera's current position, and set the new "
|
||||
"// path's speed value.\n"
|
||||
"%pathCamera.reset(%speed);\n"
|
||||
"@endtsexample\n")
|
||||
{
|
||||
object->reset(speed);
|
||||
}
|
||||
|
||||
static CameraSpline::Knot::Type resolveKnotType(const char *arg)
|
||||
{
|
||||
if (dStricmp(arg, "Position Only") == 0)
|
||||
return CameraSpline::Knot::POSITION_ONLY;
|
||||
if (dStricmp(arg, "Kink") == 0)
|
||||
return CameraSpline::Knot::KINK;
|
||||
return CameraSpline::Knot::NORMAL;
|
||||
}
|
||||
|
||||
static CameraSpline::Knot::Path resolveKnotPath(const char *arg)
|
||||
{
|
||||
if (!dStricmp(arg, "Linear"))
|
||||
return CameraSpline::Knot::LINEAR;
|
||||
return CameraSpline::Knot::SPLINE;
|
||||
}
|
||||
|
||||
DefineEngineMethod(PathShape, pushBack, void, (TransformF transform, F32 speed, const char* type, const char* path),
|
||||
(TransformF::Identity, 1.0f, "Normal", "Linear"),
|
||||
"@brief Adds a new knot to the back of a path camera's path.\n"
|
||||
"@param transform Transform for the new knot. In the form of \"x y z ax ay az aa\" such as returned by SceneObject::getTransform()\n"
|
||||
"@param speed Speed setting for this knot.\n"
|
||||
"@param type Knot type (Normal, Position Only, Kink).\n"
|
||||
"@param path %Path type (Linear, Spline).\n"
|
||||
"@tsexample\n"
|
||||
"// Transform vector for new knot. (Pos_X Pos_Y Pos_Z Rot_X Rot_Y Rot_Z Angle)\n"
|
||||
"%transform = \"15.0 5.0 5.0 1.4 1.0 0.2 1.0\"\n\n"
|
||||
"// Speed setting for knot.\n"
|
||||
"%speed = \"1.0\"\n\n"
|
||||
"// Knot type. (Normal, Position Only, Kink)\n"
|
||||
"%type = \"Normal\";\n\n"
|
||||
"// Path Type. (Linear, Spline)\n"
|
||||
"%path = \"Linear\";\n\n"
|
||||
"// Inform the path camera to add a new knot to the back of its path\n"
|
||||
"%pathCamera.pushBack(%transform,%speed,%type,%path);\n"
|
||||
"@endtsexample\n")
|
||||
{
|
||||
QuatF rot(transform.getOrientation());
|
||||
|
||||
object->pushBack(new CameraSpline::Knot(transform.getPosition(), rot, speed, resolveKnotType(type), resolveKnotPath(path)));
|
||||
}
|
||||
|
||||
DefineEngineMethod(PathShape, pushFront, void, (TransformF transform, F32 speed, const char* type, const char* path),
|
||||
(1.0f, "Normal", "Linear"),
|
||||
"@brief Adds a new knot to the front of a path camera's path.\n"
|
||||
"@param transform Transform for the new knot. In the form of \"x y z ax ay az aa\" such as returned by SceneObject::getTransform()\n"
|
||||
"@param speed Speed setting for this knot.\n"
|
||||
"@param type Knot type (Normal, Position Only, Kink).\n"
|
||||
"@param path %Path type (Linear, Spline).\n"
|
||||
"@tsexample\n"
|
||||
"// Transform vector for new knot. (Pos_X,Pos_Y,Pos_Z,Rot_X,Rot_Y,Rot_Z,Angle)\n"
|
||||
"%transform = \"15.0 5.0 5.0 1.4 1.0 0.2 1.0\"\n\n"
|
||||
"// Speed setting for knot.\n"
|
||||
"%speed = \"1.0\";\n\n"
|
||||
"// Knot type. (Normal, Position Only, Kink)\n"
|
||||
"%type = \"Normal\";\n\n"
|
||||
"// Path Type. (Linear, Spline)\n"
|
||||
"%path = \"Linear\";\n\n"
|
||||
"// Inform the path camera to add a new knot to the front of its path\n"
|
||||
"%pathCamera.pushFront(%transform, %speed, %type, %path);\n"
|
||||
"@endtsexample\n")
|
||||
{
|
||||
QuatF rot(transform.getOrientation());
|
||||
|
||||
object->pushFront(new CameraSpline::Knot(transform.getPosition(), rot, speed, resolveKnotType(type), resolveKnotPath(path)));
|
||||
}
|
||||
|
||||
DefineEngineMethod(PathShape, popFront, void, (), , "Removes the knot at the front of the camera's path.\n"
|
||||
"@tsexample\n"
|
||||
"// Remove the first knot in the camera's path.\n"
|
||||
"%pathCamera.popFront();\n"
|
||||
"@endtsexample\n")
|
||||
{
|
||||
object->popFront();
|
||||
}
|
||||
|
||||
DefineEngineMethod(PathShape, getState, S32, (), , "PathShape.getState()")
|
||||
{
|
||||
return object->getState();
|
||||
}
|
||||
114
Engine/source/T3D/pathShape.h
Normal file
114
Engine/source/T3D/pathShape.h
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _PATHSHAPE_H_
|
||||
#define _PATHSHAPE_H_
|
||||
|
||||
#ifndef _STATICSHAPE_H_
|
||||
#include "T3D/staticShape.h"
|
||||
#endif
|
||||
|
||||
#ifndef _CAMERASPLINE_H_
|
||||
#include "T3D/cameraSpline.h"
|
||||
#endif
|
||||
|
||||
#ifndef _SIMPATH_H_
|
||||
#include "scene/simPath.h"
|
||||
#endif
|
||||
//----------------------------------------------------------------------------
|
||||
struct PathShapeData: public StaticShapeData {
|
||||
typedef StaticShapeData Parent;
|
||||
|
||||
|
||||
PathShapeData();
|
||||
static void consoleInit();
|
||||
|
||||
DECLARE_CONOBJECT(PathShapeData);
|
||||
bool preload(bool server, String &errorStr);
|
||||
static void initPersistFields();
|
||||
virtual void packData(BitStream* stream);
|
||||
virtual void unpackData(BitStream* stream);
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
class PathShape: public StaticShape
|
||||
{
|
||||
public:
|
||||
enum State {
|
||||
Forward,
|
||||
Backward,
|
||||
Stop,
|
||||
StateBits = 3
|
||||
};
|
||||
|
||||
private:
|
||||
typedef StaticShape Parent;
|
||||
|
||||
enum MaskBits {
|
||||
WindowMask = Parent::NextFreeMask,
|
||||
PositionMask = WindowMask << 1,
|
||||
TargetMask = PositionMask << 1,
|
||||
StateMask = TargetMask << 1,
|
||||
NextFreeMask = StateMask << 1
|
||||
|
||||
};
|
||||
|
||||
struct StateDelta {
|
||||
F32 time;
|
||||
F32 timeVec;
|
||||
};
|
||||
StateDelta delta;
|
||||
|
||||
enum Constants {
|
||||
NodeWindow = 20 // Maximum number of active nodes
|
||||
};
|
||||
|
||||
PathShapeData* mDataBlock;
|
||||
CameraSpline mSpline;
|
||||
S32 mNodeBase;
|
||||
S32 mNodeCount;
|
||||
F32 mPosition;
|
||||
S32 mState;
|
||||
F32 mTarget;
|
||||
bool mTargetSet;
|
||||
void interpolateMat(F32 pos,MatrixF* mat);
|
||||
void advancePosition(S32 ms);
|
||||
|
||||
public:
|
||||
DECLARE_CONOBJECT(PathShape);
|
||||
|
||||
PathShape();
|
||||
~PathShape();
|
||||
|
||||
StringTableEntry mControl[4];
|
||||
|
||||
static void initPersistFields();
|
||||
static void consoleInit();
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
bool onNewDataBlock(GameBaseData* dptr, bool reload);
|
||||
void onNode(S32 node);
|
||||
|
||||
void processTick(const Move*);
|
||||
void interpolateTick(F32 dt);
|
||||
|
||||
U32 packUpdate(NetConnection *, U32 mask, BitStream *stream);
|
||||
void unpackUpdate(NetConnection *, BitStream *stream);
|
||||
|
||||
void reset(F32 speed = 1);
|
||||
void pushFront(CameraSpline::Knot *knot);
|
||||
void pushBack(CameraSpline::Knot *knot);
|
||||
void popFront();
|
||||
|
||||
void setPosition(F32 pos);
|
||||
void setTarget(F32 pos);
|
||||
void setState(State s);
|
||||
S32 getState();
|
||||
SimObjectRef< SimPath::Path > mSimPath;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -120,7 +120,10 @@ static U32 sCollisionMoveMask = TerrainObjectType |
|
|||
PlayerObjectType |
|
||||
StaticShapeObjectType |
|
||||
VehicleObjectType |
|
||||
PhysicalZoneObjectType;
|
||||
PhysicalZoneObjectType |
|
||||
// PATHSHAPE
|
||||
PathShapeObjectType;
|
||||
// PATHSHAPE END
|
||||
|
||||
static U32 sServerCollisionContactMask = sCollisionMoveMask |
|
||||
ItemObjectType |
|
||||
|
|
@ -2206,6 +2209,9 @@ void Player::processTick(const Move* move)
|
|||
}
|
||||
}
|
||||
}
|
||||
// PATHSHAPE
|
||||
if (!isGhost()) updateAttachment();
|
||||
// PATHSHAPE END
|
||||
}
|
||||
|
||||
void Player::interpolateTick(F32 dt)
|
||||
|
|
@ -2239,6 +2245,9 @@ void Player::interpolateTick(F32 dt)
|
|||
|
||||
updateLookAnimation(dt);
|
||||
mDelta.dt = dt;
|
||||
// PATHSHAPE
|
||||
updateRenderChangesByParent();
|
||||
// PATHSHAPE END
|
||||
}
|
||||
|
||||
void Player::advanceTime(F32 dt)
|
||||
|
|
@ -3658,7 +3667,10 @@ void Player::updateDeathOffsets()
|
|||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
static const U32 sPlayerConformMask = StaticShapeObjectType | StaticObjectType | TerrainObjectType;
|
||||
// PATHSHAPE
|
||||
static const U32 sPlayerConformMask = StaticShapeObjectType | StaticObjectType |
|
||||
TerrainObjectType | PathShapeObjectType;
|
||||
// PATHSHAPE END
|
||||
|
||||
static void accel(F32& from, F32 to, F32 rate)
|
||||
{
|
||||
|
|
@ -4780,6 +4792,45 @@ bool Player::step(Point3F *pos,F32 *maxStep,F32 time)
|
|||
return false;
|
||||
}
|
||||
|
||||
// PATHSHAPE
|
||||
// This Function does a ray cast down to see if a pathshape object is below
|
||||
// If so, it will attempt to attach to it.
|
||||
void Player::updateAttachment(){
|
||||
Point3F rot, pos;
|
||||
RayInfo rInfo;
|
||||
MatrixF mat = getTransform();
|
||||
mat.getColumn(3, &pos);
|
||||
if (gServerContainer.castRay(Point3F(pos.x, pos.y, pos.z + 0.1f),
|
||||
Point3F(pos.x, pos.y, pos.z - 1.0f ),
|
||||
PathShapeObjectType, &rInfo))
|
||||
{
|
||||
if( rInfo.object->getTypeMask() & PathShapeObjectType) //Ramen
|
||||
{
|
||||
if (getParent() == NULL)
|
||||
{ // ONLY do this if we are not parented
|
||||
//Con::printf("I'm on a pathshape object. Going to attempt attachment.");
|
||||
ShapeBase* col = static_cast<ShapeBase*>(rInfo.object);
|
||||
if (!isGhost())
|
||||
{
|
||||
this->attachToParent(col);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Con::printf("object %i",rInfo.object->getId());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (getParent() !=NULL)
|
||||
{
|
||||
clearProcessAfter();
|
||||
attachToParent(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
// PATHSHAPE END
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
inline Point3F createInterpPos(const Point3F& s, const Point3F& e, const F32 t, const F32 d)
|
||||
|
|
|
|||
|
|
@ -614,6 +614,9 @@ protected:
|
|||
void _handleCollision( const Collision &collision );
|
||||
virtual bool updatePos(const F32 travelTime = TickSec);
|
||||
|
||||
// PATHSHAPE
|
||||
void updateAttachment();
|
||||
// PATHSHAPE END
|
||||
///Update head animation
|
||||
void updateLookAnimation(F32 dT = 0.f);
|
||||
|
||||
|
|
|
|||
|
|
@ -1215,44 +1215,46 @@ on standard collision resolution formulas.
|
|||
bool RigidShape::resolveCollision(Rigid& ns,CollisionList& cList)
|
||||
{
|
||||
// Apply impulses to resolve collision
|
||||
bool colliding, collided = false;
|
||||
|
||||
do
|
||||
bool collided = false;
|
||||
for (S32 i = 0; i < cList.getCount(); i++)
|
||||
{
|
||||
colliding = false;
|
||||
for (S32 i = 0; i < cList.getCount(); i++)
|
||||
Collision& c = cList[i];
|
||||
if (c.distance < mDataBlock->collisionTol)
|
||||
{
|
||||
Collision& c = cList[i];
|
||||
if (c.distance < mDataBlock->collisionTol)
|
||||
// Velocity into surface
|
||||
Point3F v, r;
|
||||
ns.getOriginVector(c.point, &r);
|
||||
ns.getVelocity(r, &v);
|
||||
F32 vn = mDot(v, c.normal);
|
||||
|
||||
// Only interested in velocities greater than sContactTol,
|
||||
// velocities less than that will be dealt with as contacts
|
||||
// "constraints".
|
||||
if (vn < -mDataBlock->contactTol)
|
||||
{
|
||||
// Velocity into surface
|
||||
Point3F v,r;
|
||||
ns.getOriginVector(c.point,&r);
|
||||
ns.getVelocity(r,&v);
|
||||
F32 vn = mDot(v,c.normal);
|
||||
|
||||
// Only interested in velocities greater than sContactTol,
|
||||
// velocities less than that will be dealt with as contacts
|
||||
// "constraints".
|
||||
if (vn < -mDataBlock->contactTol)
|
||||
// Apply impulses to the rigid body to keep it from
|
||||
// penetrating the surface.
|
||||
if (c.object->getTypeMask() & VehicleObjectType)
|
||||
{
|
||||
RigidShape* otherRigid = dynamic_cast<RigidShape*>(c.object);
|
||||
if (otherRigid)
|
||||
ns.resolveCollision(cList[i].point, cList[i].normal, &otherRigid->mRigid);
|
||||
else
|
||||
ns.resolveCollision(cList[i].point, cList[i].normal);
|
||||
}
|
||||
else ns.resolveCollision(cList[i].point, cList[i].normal);
|
||||
collided = true;
|
||||
|
||||
// Apply impulses to the rigid body to keep it from
|
||||
// penetrating the surface.
|
||||
ns.resolveCollision(cList[i].point,
|
||||
cList[i].normal);
|
||||
colliding = collided = true;
|
||||
|
||||
// Keep track of objects we collide with
|
||||
if (!isGhost() && c.object->getTypeMask() & ShapeBaseObjectType)
|
||||
{
|
||||
ShapeBase* col = static_cast<ShapeBase*>(c.object);
|
||||
queueCollision(col,v - col->getVelocity());
|
||||
}
|
||||
// Keep track of objects we collide with
|
||||
if (!isGhost() && c.object->getTypeMask() & ShapeBaseObjectType)
|
||||
{
|
||||
ShapeBase* col = static_cast<ShapeBase*>(c.object);
|
||||
queueCollision(col, v - col->getVelocity());
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (colliding);
|
||||
}
|
||||
|
||||
return collided;
|
||||
}
|
||||
|
|
@ -1269,7 +1271,7 @@ bool RigidShape::resolveContacts(Rigid& ns,CollisionList& cList,F32 dt)
|
|||
Point3F t,p(0,0,0),l(0,0,0);
|
||||
for (S32 i = 0; i < cList.getCount(); i++)
|
||||
{
|
||||
Collision& c = cList[i];
|
||||
const Collision& c = cList[i];
|
||||
if (c.distance < mDataBlock->collisionTol)
|
||||
{
|
||||
|
||||
|
|
|
|||
|
|
@ -146,11 +146,6 @@ class RigidShape: public ShapeBase
|
|||
SimObjectPtr<ParticleEmitter> mDustTrailEmitter;
|
||||
|
||||
protected:
|
||||
enum CollisionFaceFlags
|
||||
{
|
||||
BodyCollision = BIT(0),
|
||||
WheelCollision = BIT(1),
|
||||
};
|
||||
enum MaskBits {
|
||||
PositionMask = Parent::NextFreeMask << 0,
|
||||
EnergyMask = Parent::NextFreeMask << 1,
|
||||
|
|
@ -193,7 +188,6 @@ class RigidShape: public ShapeBase
|
|||
|
||||
CollisionList mCollisionList;
|
||||
CollisionList mContacts;
|
||||
Rigid mRigid;
|
||||
ShapeBaseConvex mConvex;
|
||||
S32 restCount;
|
||||
|
||||
|
|
@ -238,6 +232,7 @@ class RigidShape: public ShapeBase
|
|||
public:
|
||||
// Test code...
|
||||
static ClippedPolyList* sPolyList;
|
||||
Rigid mRigid;
|
||||
|
||||
//
|
||||
RigidShape();
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ ShapeBaseImageData::ShapeBaseImageData()
|
|||
lightRadius = 10.f;
|
||||
lightBrightness = 1.0f;
|
||||
|
||||
shapeName = "core/shapes/noshape.dts";
|
||||
shapeName = "core/rendering/shapes/noshape.dts";
|
||||
shapeNameFP = "";
|
||||
imageAnimPrefix = "";
|
||||
imageAnimPrefixFP = "";
|
||||
|
|
|
|||
|
|
@ -246,6 +246,14 @@ void StaticShape::processTick(const Move* move)
|
|||
}
|
||||
}
|
||||
|
||||
void StaticShape::interpolateTick(F32 delta)
|
||||
{
|
||||
Parent::interpolateTick(delta);
|
||||
// PATHSHAPE
|
||||
updateRenderChangesByParent();
|
||||
// PATHSHAPE END
|
||||
}
|
||||
|
||||
void StaticShape::setTransform(const MatrixF& mat)
|
||||
{
|
||||
Parent::setTransform(mat);
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ public:
|
|||
bool onNewDataBlock(GameBaseData *dptr, bool reload);
|
||||
|
||||
void processTick(const Move *move);
|
||||
void interpolateTick(F32 delta);
|
||||
void setTransform(const MatrixF &mat);
|
||||
|
||||
U32 packUpdate (NetConnection *conn, U32 mask, BitStream *stream);
|
||||
|
|
|
|||
|
|
@ -101,9 +101,6 @@ ConsoleDocClass( TSStatic,
|
|||
);
|
||||
|
||||
TSStatic::TSStatic()
|
||||
:
|
||||
cubeDescId( 0 ),
|
||||
reflectorDesc( NULL )
|
||||
{
|
||||
mNetFlags.set(Ghostable | ScopeAlways);
|
||||
|
||||
|
|
@ -171,7 +168,7 @@ void TSStatic::initPersistFields()
|
|||
&TSStatic::_setShapeAsset, &defaultProtectedGetFn,
|
||||
"The source shape asset.");
|
||||
|
||||
addProtectedField("shapeName", TypeShapeFilename, Offset( mShapeName, TSStatic ), &TSStatic::_setShape, &defaultProtectedGetFn,
|
||||
addProtectedField("shapeName", TypeFilename, Offset( mShapeName, TSStatic ), &TSStatic::_setShape, &defaultProtectedGetFn,
|
||||
"%Path and filename of the model file (.DTS, .DAE) to use for this TSStatic."/*, AbstractClassRep::FieldFlags::FIELD_HideInInspectors*/ );
|
||||
|
||||
endGroup("Shape");
|
||||
|
|
@ -219,11 +216,6 @@ void TSStatic::initPersistFields()
|
|||
|
||||
endGroup("Rendering");
|
||||
|
||||
addGroup( "Reflection" );
|
||||
addField( "cubeReflectorDesc", TypeRealString, Offset( cubeDescName, TSStatic ),
|
||||
"References a ReflectorDesc datablock that defines performance and quality properties for dynamic reflections.\n");
|
||||
endGroup( "Reflection" );
|
||||
|
||||
addGroup("Collision");
|
||||
|
||||
addField( "collisionType", TypeTSMeshType, Offset( mCollisionType, TSStatic ),
|
||||
|
|
@ -265,18 +257,26 @@ bool TSStatic::_setShape(void* obj, const char* index, const char* data)
|
|||
{
|
||||
TSStatic* ts = static_cast<TSStatic*>(obj);// ->setFile(FileName(data));
|
||||
|
||||
//before we continue, lets hit up the Asset Database to see if this file is associated to an asset. If so, we grab the asset instead
|
||||
AssetQuery query;
|
||||
S32 foundAssetcount = AssetDatabase.findAssetLooseFile(&query, data);
|
||||
if (foundAssetcount == 0)
|
||||
if (ShapeAsset::getAssetByFilename(StringTable->insert(data), &ts->mShapeAsset))
|
||||
{
|
||||
//didn't find any assets. continue as normal
|
||||
ts->mShapeName = StringTable->insert(data);
|
||||
//Special exception case. If we've defaulted to the 'no shape' mesh, don't save it out, we'll retain the original ids/paths so it doesn't break
|
||||
//the TSStatic
|
||||
|
||||
if (ts->mShapeAsset.getAssetId() != StringTable->insert("Core_Rendering:noshape"))
|
||||
{
|
||||
//ts->mShapeAssetId = ts->mShapeAsset.getAssetId();
|
||||
ts->mShapeName = StringTable->EmptyString();
|
||||
}
|
||||
/*else
|
||||
{
|
||||
ts->mShapeAssetId = StringTable->EmptyString();
|
||||
}*/
|
||||
|
||||
ts->_createShape();
|
||||
}
|
||||
else
|
||||
{
|
||||
ts->setShapeAsset(query.mAssetList[0]);
|
||||
ts->mShapeName = StringTable->EmptyString();
|
||||
ts->mShapeAsset = StringTable->EmptyString();
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
@ -284,9 +284,9 @@ bool TSStatic::_setShape(void* obj, const char* index, const char* data)
|
|||
|
||||
bool TSStatic::_setShapeAsset(void* obj, const char* index, const char* data)
|
||||
{
|
||||
TSStatic* ts = static_cast<TSStatic*>(obj);// ->setFile(FileName(data));
|
||||
TSStatic* ts = static_cast<TSStatic*>(obj);
|
||||
|
||||
ts->setShapeAsset(StringTable->insert(data));
|
||||
ts->setShapeAsset(data);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -366,14 +366,6 @@ bool TSStatic::onAdd()
|
|||
|
||||
addToScene();
|
||||
|
||||
if ( isClientObject() )
|
||||
{
|
||||
mCubeReflector.unregisterReflector();
|
||||
|
||||
if ( reflectorDesc )
|
||||
mCubeReflector.registerReflector( this, reflectorDesc );
|
||||
}
|
||||
|
||||
_updateShouldTick();
|
||||
|
||||
// Accumulation and environment mapping
|
||||
|
|
@ -387,10 +379,23 @@ bool TSStatic::onAdd()
|
|||
|
||||
bool TSStatic::setShapeAsset(const StringTableEntry shapeAssetId)
|
||||
{
|
||||
mShapeAssetId = shapeAssetId;
|
||||
if (ShapeAsset::getAssetById(StringTable->insert(shapeAssetId), &mShapeAsset))
|
||||
{
|
||||
//Special exception case. If we've defaulted to the 'no shape' mesh, don't save it out, we'll retain the original ids/paths so it doesn't break
|
||||
//the TSStatic
|
||||
if (mShapeAsset.getAssetId() != StringTable->insert("Core_Rendering:noshape"))
|
||||
{
|
||||
mShapeName = StringTable->EmptyString();
|
||||
}
|
||||
|
||||
_createShape();
|
||||
return true;
|
||||
_createShape();
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool TSStatic::_createShape()
|
||||
|
|
@ -403,54 +408,30 @@ bool TSStatic::_createShape()
|
|||
SAFE_DELETE( mPhysicsRep );
|
||||
SAFE_DELETE( mShapeInstance );
|
||||
mAmbientThread = NULL;
|
||||
mShape = NULL;
|
||||
|
||||
if (mShapeAssetId != StringTable->EmptyString())
|
||||
if (mShapeAsset.isNull())
|
||||
{
|
||||
mShapeAsset = mShapeAssetId;
|
||||
|
||||
if (mShapeAsset.isNull())
|
||||
{
|
||||
Con::errorf("[TSStatic] Failed to load shape asset.");
|
||||
return false;
|
||||
}
|
||||
|
||||
mShape = mShapeAsset->getShapeResource();
|
||||
|
||||
if(!mShape)
|
||||
{
|
||||
Con::errorf("TSStatic::_createShape() - Shape Asset had no valid shape!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!mShapeName || mShapeName[0] == '\0')
|
||||
{
|
||||
Con::errorf("TSStatic::_createShape() - No shape name!");
|
||||
return false;
|
||||
}
|
||||
|
||||
mShapeHash = _StringTable::hashString(mShapeName);
|
||||
|
||||
mShape = ResourceManager::get().load(mShapeName);
|
||||
Con::errorf("[TSStatic] Failed to load shape asset.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( bool(mShape) == false )
|
||||
if(!mShapeAsset->getShapeResource())
|
||||
{
|
||||
Con::errorf( "TSStatic::_createShape() - Unable to load shape: %s", mShapeName );
|
||||
Con::errorf("TSStatic::_createShape() - Shape Asset had no valid shape!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( isClientObject() &&
|
||||
!mShape->preloadMaterialList(mShape.getPath()) &&
|
||||
!mShapeAsset->getShapeResource()->preloadMaterialList(mShapeAsset->getShapeFile()) &&
|
||||
NetConnection::filesWereDownloaded() )
|
||||
return false;
|
||||
|
||||
mObjBox = mShape->mBounds;
|
||||
TSShape* shape = mShapeAsset->getShapeResource();
|
||||
|
||||
mObjBox = shape->mBounds;
|
||||
resetWorldBox();
|
||||
|
||||
mShapeInstance = new TSShapeInstance( mShape, isClientObject() );
|
||||
mShapeInstance = new TSShapeInstance(shape, isClientObject() );
|
||||
if (isClientObject())
|
||||
{
|
||||
mShapeInstance->cloneMaterialList();
|
||||
|
|
@ -468,7 +449,7 @@ bool TSStatic::_createShape()
|
|||
prepCollision();
|
||||
|
||||
// Find the "ambient" animation if it exists
|
||||
S32 ambientSeq = mShape->findSequence("ambient");
|
||||
S32 ambientSeq = shape->findSequence("ambient");
|
||||
|
||||
if ( ambientSeq > -1 && !mAmbientThread )
|
||||
mAmbientThread = mShapeInstance->addThread();
|
||||
|
|
@ -476,18 +457,8 @@ bool TSStatic::_createShape()
|
|||
if ( mAmbientThread )
|
||||
mShapeInstance->setSequence( mAmbientThread, ambientSeq, 0);
|
||||
|
||||
// Resolve CubeReflectorDesc.
|
||||
if ( cubeDescName.isNotEmpty() )
|
||||
{
|
||||
Sim::findObject( cubeDescName, reflectorDesc );
|
||||
}
|
||||
else if( cubeDescId > 0 )
|
||||
{
|
||||
Sim::findObject( cubeDescId, reflectorDesc );
|
||||
}
|
||||
|
||||
//Set up the material slot vars for easy manipulation
|
||||
S32 materialCount = mShape->materialList->getMaterialNameList().size(); //mMeshAsset->getMaterialCount();
|
||||
S32 materialCount = shape->materialList->getMaterialNameList().size(); //mMeshAsset->getMaterialCount();
|
||||
|
||||
if (isServerObject())
|
||||
{
|
||||
|
|
@ -495,7 +466,7 @@ bool TSStatic::_createShape()
|
|||
|
||||
for (U32 i = 0; i < materialCount; i++)
|
||||
{
|
||||
StringTableEntry materialname = StringTable->insert(mShape->materialList->getMaterialName(i).c_str());
|
||||
StringTableEntry materialname = StringTable->insert(shape->materialList->getMaterialName(i).c_str());
|
||||
|
||||
dSprintf(matFieldName, 128, "MaterialSlot%d", i);
|
||||
StringTableEntry matFld = StringTable->insert(matFieldName);
|
||||
|
|
@ -572,22 +543,24 @@ void TSStatic::prepCollision()
|
|||
mLOSDetails.clear();
|
||||
mConvexList->nukeList();
|
||||
|
||||
TSShape* shape = mShapeAsset->getShapeResource();
|
||||
|
||||
if ( mCollisionType == CollisionMesh || mCollisionType == VisibleMesh )
|
||||
{
|
||||
mShape->findColDetails( mCollisionType == VisibleMesh, &mCollisionDetails, &mLOSDetails );
|
||||
shape->findColDetails( mCollisionType == VisibleMesh, &mCollisionDetails, &mLOSDetails );
|
||||
if ( mDecalType == mCollisionType )
|
||||
{
|
||||
mDecalDetailsPtr = &mCollisionDetails;
|
||||
}
|
||||
else if ( mDecalType == CollisionMesh || mDecalType == VisibleMesh )
|
||||
{
|
||||
mShape->findColDetails( mDecalType == VisibleMesh, &mDecalDetails, 0 );
|
||||
shape->findColDetails( mDecalType == VisibleMesh, &mDecalDetails, 0 );
|
||||
mDecalDetailsPtr = &mDecalDetails;
|
||||
}
|
||||
}
|
||||
else if ( mDecalType == CollisionMesh || mDecalType == VisibleMesh )
|
||||
{
|
||||
mShape->findColDetails( mDecalType == VisibleMesh, &mDecalDetails, 0 );
|
||||
shape->findColDetails( mDecalType == VisibleMesh, &mDecalDetails, 0 );
|
||||
mDecalDetailsPtr = &mDecalDetails;
|
||||
}
|
||||
|
||||
|
|
@ -601,16 +574,18 @@ void TSStatic::_updatePhysics()
|
|||
if ( !PHYSICSMGR || mCollisionType == None )
|
||||
return;
|
||||
|
||||
TSShape* shape = mShapeAsset->getShapeResource();
|
||||
|
||||
PhysicsCollision *colShape = NULL;
|
||||
if ( mCollisionType == Bounds )
|
||||
{
|
||||
MatrixF offset( true );
|
||||
offset.setPosition( mShape->center );
|
||||
offset.setPosition(shape->center );
|
||||
colShape = PHYSICSMGR->createCollision();
|
||||
colShape->addBox( getObjBox().getExtents() * 0.5f * mObjScale, offset );
|
||||
}
|
||||
else
|
||||
colShape = mShape->buildColShape( mCollisionType == VisibleMesh, getScale() );
|
||||
colShape = shape->buildColShape( mCollisionType == VisibleMesh, getScale() );
|
||||
|
||||
if ( colShape )
|
||||
{
|
||||
|
|
@ -643,8 +618,6 @@ void TSStatic::onRemove()
|
|||
mShapeInstance = NULL;
|
||||
|
||||
mAmbientThread = NULL;
|
||||
if ( isClientObject() )
|
||||
mCubeReflector.unregisterReflector();
|
||||
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
|
@ -800,12 +773,6 @@ void TSStatic::prepRenderImage( SceneRenderState* state )
|
|||
|
||||
F32 invScale = (1.0f/getMax(getMax(mObjScale.x,mObjScale.y),mObjScale.z));
|
||||
|
||||
// If we're currently rendering our own reflection we
|
||||
// don't want to render ourselves into it.
|
||||
if ( mCubeReflector.isRendering() )
|
||||
return;
|
||||
|
||||
|
||||
if ( mForceDetail == -1 )
|
||||
mShapeInstance->setDetailFromDistance( state, dist * invScale );
|
||||
else
|
||||
|
|
@ -822,9 +789,6 @@ void TSStatic::prepRenderImage( SceneRenderState* state )
|
|||
rdata.setFadeOverride( 1.0f );
|
||||
rdata.setOriginSort( mUseOriginSort );
|
||||
|
||||
if ( mCubeReflector.isEnabled() )
|
||||
rdata.setCubemap( mCubeReflector.getCubemap() );
|
||||
|
||||
// Acculumation
|
||||
rdata.setAccuTex(mAccuTex);
|
||||
|
||||
|
|
@ -852,20 +816,6 @@ void TSStatic::prepRenderImage( SceneRenderState* state )
|
|||
mat.scale( mObjScale );
|
||||
GFX->setWorldMatrix( mat );
|
||||
|
||||
if ( state->isDiffusePass() && mCubeReflector.isEnabled() && mCubeReflector.getOcclusionQuery() )
|
||||
{
|
||||
RenderPassManager *pass = state->getRenderPass();
|
||||
OccluderRenderInst *ri = pass->allocInst<OccluderRenderInst>();
|
||||
|
||||
ri->type = RenderPassManager::RIT_Occluder;
|
||||
ri->query = mCubeReflector.getOcclusionQuery();
|
||||
mObjToWorld.mulP( mObjBox.getCenter(), &ri->position );
|
||||
ri->scale.set( mObjBox.getExtents() );
|
||||
ri->orientation = pass->allocUniqueXform( mObjToWorld );
|
||||
ri->isSphere = false;
|
||||
state->getRenderPass()->addInst( ri );
|
||||
}
|
||||
|
||||
mShapeInstance->animate();
|
||||
if(mShapeInstance)
|
||||
{
|
||||
|
|
@ -969,8 +919,8 @@ U32 TSStatic::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
|
|||
|
||||
if (stream->writeFlag(mask & AdvancedStaticOptionsMask))
|
||||
{
|
||||
stream->writeString(mShapeAssetId);
|
||||
stream->writeString(mShapeName);
|
||||
if(mShapeAsset->isAssetValid())
|
||||
stream->writeString(mShapeAsset.getAssetId());
|
||||
|
||||
stream->write((U32)mDecalType);
|
||||
|
||||
|
|
@ -1002,11 +952,6 @@ U32 TSStatic::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
|
|||
if ( mLightPlugin )
|
||||
retMask |= mLightPlugin->packUpdate(this, AdvancedStaticOptionsMask, con, mask, stream);
|
||||
|
||||
if( stream->writeFlag( reflectorDesc != NULL ) )
|
||||
{
|
||||
stream->writeRangedU32( reflectorDesc->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast );
|
||||
}
|
||||
|
||||
stream->write(mOverrideColor);
|
||||
|
||||
if (stream->writeFlag(mask & MaterialMask))
|
||||
|
|
@ -1081,9 +1026,7 @@ void TSStatic::unpackUpdate(NetConnection *con, BitStream *stream)
|
|||
{
|
||||
char buffer[256];
|
||||
stream->readString(buffer);
|
||||
mShapeAssetId = StringTable->insert(buffer);
|
||||
|
||||
mShapeName = stream->readSTString();
|
||||
mShapeAsset = StringTable->insert(buffer);
|
||||
|
||||
stream->read((U32*)&mDecalType);
|
||||
|
||||
|
|
@ -1118,11 +1061,6 @@ void TSStatic::unpackUpdate(NetConnection *con, BitStream *stream)
|
|||
mLightPlugin->unpackUpdate(this, con, stream);
|
||||
}
|
||||
|
||||
if( stream->readFlag() )
|
||||
{
|
||||
cubeDescId = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast );
|
||||
}
|
||||
|
||||
stream->read(&mOverrideColor);
|
||||
|
||||
if (stream->readFlag())
|
||||
|
|
@ -1418,6 +1356,16 @@ void TSStatic::buildConvex(const Box3F& box, Convex* convex)
|
|||
}
|
||||
}
|
||||
|
||||
Resource<TSShape> TSStatic::getShape() const
|
||||
{
|
||||
if (mShapeAsset->isAssetValid())
|
||||
{
|
||||
return mShapeAsset->getShapeResource();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SceneObject* TSStaticPolysoupConvex::smCurObject = NULL;
|
||||
|
||||
TSStaticPolysoupConvex::TSStaticPolysoupConvex()
|
||||
|
|
@ -1586,7 +1534,7 @@ U32 TSStatic::getNumDetails()
|
|||
|
||||
void TSStatic::updateMaterials()
|
||||
{
|
||||
if (mChangingMaterials.empty() || !mShape)
|
||||
if (mChangingMaterials.empty() || !mShapeAsset->getShapeResource())
|
||||
return;
|
||||
|
||||
TSMaterialList* pMatList = mShapeInstance->getMaterialList();
|
||||
|
|
|
|||
|
|
@ -43,11 +43,6 @@
|
|||
#ifndef _TSSHAPE_H_
|
||||
#include "ts/tsShape.h"
|
||||
#endif
|
||||
|
||||
#ifndef _REFLECTOR_H_
|
||||
#include "scene/reflector.h"
|
||||
#endif
|
||||
|
||||
#ifndef _ASSET_PTR_H_
|
||||
#include "assets/assetPtr.h"
|
||||
#endif
|
||||
|
|
@ -179,18 +174,12 @@ protected:
|
|||
/// Start or stop processing ticks depending on our state.
|
||||
void _updateShouldTick();
|
||||
|
||||
String cubeDescName;
|
||||
U32 cubeDescId;
|
||||
ReflectorDesc *reflectorDesc;
|
||||
CubeReflector mCubeReflector;
|
||||
|
||||
protected:
|
||||
|
||||
Convex *mConvexList;
|
||||
|
||||
StringTableEntry mShapeName;
|
||||
U32 mShapeHash;
|
||||
Resource<TSShape> mShape;
|
||||
Vector<S32> mCollisionDetails;
|
||||
Vector<S32> mLOSDetails;
|
||||
TSShapeInstance *mShapeInstance;
|
||||
|
|
@ -261,7 +250,7 @@ public:
|
|||
|
||||
bool allowPlayerStep() const { return mAllowPlayerStep; }
|
||||
|
||||
Resource<TSShape> getShape() const { return mShape; }
|
||||
Resource<TSShape> getShape() const;
|
||||
StringTableEntry getShapeFileName() { return mShapeName; }
|
||||
void setShapeFileName(StringTableEntry shapeName) { mShapeName = shapeName; }
|
||||
|
||||
|
|
|
|||
|
|
@ -816,14 +816,6 @@ void Vehicle::onRemove()
|
|||
SAFE_DELETE(mPhysicsRep);
|
||||
|
||||
U32 i=0;
|
||||
for( i=0; i<VehicleData::VC_NUM_DUST_EMITTERS; i++ )
|
||||
{
|
||||
if( mDustEmitterList[i] )
|
||||
{
|
||||
mDustEmitterList[i]->deleteWhenEmpty();
|
||||
mDustEmitterList[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for( i=0; i<VehicleData::VC_NUM_DAMAGE_EMITTERS; i++ )
|
||||
{
|
||||
|
|
@ -834,15 +826,6 @@ void Vehicle::onRemove()
|
|||
}
|
||||
}
|
||||
|
||||
for( i=0; i<VehicleData::VC_NUM_SPLASH_EMITTERS; i++ )
|
||||
{
|
||||
if( mSplashEmitterList[i] )
|
||||
{
|
||||
mSplashEmitterList[i]->deleteWhenEmpty();
|
||||
mSplashEmitterList[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
mWorkingQueryBox.minExtents.set(-1e9f, -1e9f, -1e9f);
|
||||
mWorkingQueryBox.maxExtents.set(-1e9f, -1e9f, -1e9f);
|
||||
|
||||
|
|
@ -903,7 +886,9 @@ void Vehicle::processTick(const Move* move)
|
|||
// Update the physics based on the integration rate
|
||||
S32 count = mDataBlock->integration;
|
||||
--mWorkingQueryBoxCountDown;
|
||||
updateWorkingCollisionSet(getCollisionMask());
|
||||
|
||||
if (!mDisableMove)
|
||||
updateWorkingCollisionSet(getCollisionMask());
|
||||
for (U32 i = 0; i < count; i++)
|
||||
updatePos(TickSec / count);
|
||||
|
||||
|
|
@ -952,13 +937,6 @@ void Vehicle::advanceTime(F32 dt)
|
|||
|
||||
updateLiftoffDust( dt );
|
||||
updateDamageSmoke( dt );
|
||||
updateFroth(dt);
|
||||
|
||||
// Update 3rd person camera offset. Camera update is done
|
||||
// here as it's a client side only animation.
|
||||
mCameraOffset -=
|
||||
(mCameraOffset * mDataBlock->cameraDecay +
|
||||
mRigid.linVelocity * mDataBlock->cameraLag) * dt;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1244,7 +1222,8 @@ void Vehicle::updatePos(F32 dt)
|
|||
|
||||
// Update collision information based on our current pos.
|
||||
bool collided = false;
|
||||
if (!mRigid.atRest) {
|
||||
if (!mRigid.atRest && !mDisableMove)
|
||||
{
|
||||
collided = updateCollision(dt);
|
||||
|
||||
// Now that all the forces have been processed, lets
|
||||
|
|
@ -1265,7 +1244,7 @@ void Vehicle::updatePos(F32 dt)
|
|||
}
|
||||
|
||||
// Integrate forward
|
||||
if (!mRigid.atRest)
|
||||
if (!mRigid.atRest && !mDisableMove)
|
||||
mRigid.integrate(dt);
|
||||
|
||||
// Deal with client and server scripting, sounds, etc.
|
||||
|
|
@ -1376,163 +1355,6 @@ bool Vehicle::updateCollision(F32 dt)
|
|||
return collided;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/** Resolve collision impacts
|
||||
Handle collision impacts, as opposed to contacts. Impulses are calculated based
|
||||
on standard collision resolution formulas.
|
||||
*/
|
||||
bool Vehicle::resolveCollision(Rigid& ns,CollisionList& cList)
|
||||
{
|
||||
PROFILE_SCOPE( Vehicle_ResolveCollision );
|
||||
|
||||
// Apply impulses to resolve collision
|
||||
bool collided = false;
|
||||
for (S32 i = 0; i < cList.getCount(); i++)
|
||||
{
|
||||
Collision& c = cList[i];
|
||||
if (c.distance < mDataBlock->collisionTol)
|
||||
{
|
||||
// Velocity into surface
|
||||
Point3F v,r;
|
||||
ns.getOriginVector(c.point,&r);
|
||||
ns.getVelocity(r,&v);
|
||||
F32 vn = mDot(v,c.normal);
|
||||
|
||||
// Only interested in velocities greater than sContactTol,
|
||||
// velocities less than that will be dealt with as contacts
|
||||
// "constraints".
|
||||
if (vn < -mDataBlock->contactTol)
|
||||
{
|
||||
|
||||
// Apply impulses to the rigid body to keep it from
|
||||
// penetrating the surface.
|
||||
ns.resolveCollision(cList[i].point,
|
||||
cList[i].normal);
|
||||
collided = true;
|
||||
|
||||
// Keep track of objects we collide with
|
||||
if (!isGhost() && c.object->getTypeMask() & ShapeBaseObjectType)
|
||||
{
|
||||
ShapeBase* col = static_cast<ShapeBase*>(c.object);
|
||||
queueCollision(col,v - col->getVelocity());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return collided;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/** Resolve contact forces
|
||||
Resolve contact forces using the "penalty" method. Forces are generated based
|
||||
on the depth of penetration and the moment of inertia at the point of contact.
|
||||
*/
|
||||
bool Vehicle::resolveContacts(Rigid& ns,CollisionList& cList,F32 dt)
|
||||
{
|
||||
PROFILE_SCOPE( Vehicle_ResolveContacts );
|
||||
|
||||
// Use spring forces to manage contact constraints.
|
||||
bool collided = false;
|
||||
Point3F t,p(0,0,0),l(0,0,0);
|
||||
for (S32 i = 0; i < cList.getCount(); i++)
|
||||
{
|
||||
const Collision& c = cList[i];
|
||||
if (c.distance < mDataBlock->collisionTol)
|
||||
{
|
||||
|
||||
// Velocity into the surface
|
||||
Point3F v,r;
|
||||
ns.getOriginVector(c.point,&r);
|
||||
ns.getVelocity(r,&v);
|
||||
F32 vn = mDot(v,c.normal);
|
||||
|
||||
// Only interested in velocities less than mDataBlock->contactTol,
|
||||
// velocities greater than that are dealt with as collisions.
|
||||
if (mFabs(vn) < mDataBlock->contactTol)
|
||||
{
|
||||
collided = true;
|
||||
|
||||
// Penetration force. This is actually a spring which
|
||||
// will seperate the body from the collision surface.
|
||||
F32 zi = 2 * mFabs(mRigid.getZeroImpulse(r,c.normal));
|
||||
F32 s = (mDataBlock->collisionTol - c.distance) * zi - ((vn / mDataBlock->contactTol) * zi);
|
||||
Point3F f = c.normal * s;
|
||||
|
||||
// Friction impulse, calculated as a function of the
|
||||
// amount of force it would take to stop the motion
|
||||
// perpendicular to the normal.
|
||||
Point3F uv = v - (c.normal * vn);
|
||||
F32 ul = uv.len();
|
||||
if (s > 0 && ul)
|
||||
{
|
||||
uv /= -ul;
|
||||
F32 u = ul * ns.getZeroImpulse(r,uv);
|
||||
s *= mRigid.friction;
|
||||
if (u > s)
|
||||
u = s;
|
||||
f += uv * u;
|
||||
}
|
||||
|
||||
// Accumulate forces
|
||||
p += f;
|
||||
mCross(r,f,&t);
|
||||
l += t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Contact constraint forces act over time...
|
||||
ns.linMomentum += p * dt;
|
||||
ns.angMomentum += l * dt;
|
||||
ns.updateVelocity();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
bool Vehicle::resolveDisplacement(Rigid& ns,CollisionState *state, F32 dt)
|
||||
{
|
||||
PROFILE_SCOPE( Vehicle_ResolveDisplacement );
|
||||
|
||||
SceneObject* obj = (state->mA->getObject() == this)?
|
||||
state->mB->getObject(): state->mA->getObject();
|
||||
|
||||
if (obj->isDisplacable() && ((obj->getTypeMask() & ShapeBaseObjectType) != 0))
|
||||
{
|
||||
// Try to displace the object by the amount we're trying to move
|
||||
Point3F objNewMom = ns.linVelocity * obj->getMass() * 1.1f;
|
||||
Point3F objOldMom = obj->getMomentum();
|
||||
Point3F objNewVel = objNewMom / obj->getMass();
|
||||
|
||||
Point3F myCenter;
|
||||
Point3F theirCenter;
|
||||
getWorldBox().getCenter(&myCenter);
|
||||
obj->getWorldBox().getCenter(&theirCenter);
|
||||
if (mDot(myCenter - theirCenter, objNewMom) >= 0.0f || objNewVel.len() < 0.01)
|
||||
{
|
||||
objNewMom = (theirCenter - myCenter);
|
||||
objNewMom.normalize();
|
||||
objNewMom *= 1.0f * obj->getMass();
|
||||
objNewVel = objNewMom / obj->getMass();
|
||||
}
|
||||
|
||||
obj->setMomentum(objNewMom);
|
||||
if (obj->displaceObject(objNewVel * 1.1f * dt) == true)
|
||||
{
|
||||
// Queue collision and change in velocity
|
||||
VectorF dv = (objOldMom - objNewMom) / obj->getMass();
|
||||
queueCollision(static_cast<ShapeBase*>(obj), dv);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void Vehicle::updateWorkingCollisionSet(const U32 mask)
|
||||
|
|
|
|||
|
|
@ -24,13 +24,7 @@
|
|||
#define _VEHICLE_H_
|
||||
|
||||
#ifndef _SHAPEBASE_H_
|
||||
#include "T3D/shapeBase.h"
|
||||
#endif
|
||||
#ifndef _RIGID_H_
|
||||
#include "T3D/rigid.h"
|
||||
#endif
|
||||
#ifndef _BOXCONVEX_H_
|
||||
#include "collision/boxConvex.h"
|
||||
#include "T3D/rigidShape.h"
|
||||
#endif
|
||||
|
||||
class ParticleEmitter;
|
||||
|
|
@ -41,9 +35,9 @@ class Vehicle;
|
|||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
struct VehicleData: public ShapeBaseData
|
||||
struct VehicleData : public RigidShapeData
|
||||
{
|
||||
typedef ShapeBaseData Parent;
|
||||
typedef RigidShapeData Parent;
|
||||
|
||||
struct Body {
|
||||
enum Sounds {
|
||||
|
|
@ -146,20 +140,15 @@ struct VehicleData: public ShapeBaseData
|
|||
//----------------------------------------------------------------------------
|
||||
class PhysicsBody;
|
||||
|
||||
class Vehicle: public ShapeBase
|
||||
class Vehicle : public RigidShape
|
||||
{
|
||||
typedef ShapeBase Parent;
|
||||
typedef RigidShape Parent;
|
||||
|
||||
protected:
|
||||
enum CollisionFaceFlags {
|
||||
BodyCollision = 0x1,
|
||||
WheelCollision = 0x2,
|
||||
};
|
||||
enum MaskBits {
|
||||
PositionMask = Parent::NextFreeMask << 0,
|
||||
EnergyMask = Parent::NextFreeMask << 1,
|
||||
NextFreeMask = Parent::NextFreeMask << 2
|
||||
};
|
||||
|
||||
struct StateDelta {
|
||||
Move move; ///< Last move from server
|
||||
|
|
@ -205,7 +194,6 @@ class Vehicle: public ShapeBase
|
|||
|
||||
CollisionList mCollisionList;
|
||||
CollisionList mContacts;
|
||||
Rigid mRigid;
|
||||
ShapeBaseConvex mConvex;
|
||||
S32 restCount;
|
||||
|
||||
|
|
@ -217,9 +205,6 @@ class Vehicle: public ShapeBase
|
|||
virtual bool onNewDataBlock( GameBaseData *dptr, bool reload );
|
||||
void updatePos(F32 dt);
|
||||
bool updateCollision(F32 dt);
|
||||
bool resolveCollision(Rigid& ns,CollisionList& cList);
|
||||
bool resolveContacts(Rigid& ns,CollisionList& cList,F32 dt);
|
||||
bool resolveDisplacement(Rigid& ns,CollisionState *state,F32 dt);
|
||||
bool findContacts(Rigid& ns,CollisionList& cList);
|
||||
void checkTriggers();
|
||||
static void findCallback(SceneObject* obj,void * key);
|
||||
|
|
|
|||
|
|
@ -28,9 +28,9 @@
|
|||
#include "scene/mixin/sceneAmbientSoundObject.impl.h"
|
||||
#include "scene/mixin/scenePolyhedralObject.impl.h"
|
||||
|
||||
#include "scene/sceneManager.h"
|
||||
#include "gui/worldEditor/worldEditor.h"
|
||||
|
||||
|
||||
IMPLEMENT_CO_NETOBJECT_V1( Zone );
|
||||
|
||||
ConsoleDocClass( Zone,
|
||||
|
|
@ -103,27 +103,27 @@ bool Zone::_doSelect(void* object, const char* index, const char* data)
|
|||
void Zone::selectWithin()
|
||||
{
|
||||
SimpleQueryList sql;
|
||||
//getContainer()->polyhedronFindObjects(getPolyhedron(), 0xFFFFFFFF, SimpleQueryList::insertionCallback, &sql);
|
||||
|
||||
//replace the above with this once we stort out how to look up the managed zoneID from the insatnce itself
|
||||
Zone* zoneClient = (Zone*)getClientObject();
|
||||
SceneZoneSpaceManager* zoneManager = zoneClient->getSceneManager()->getZoneManager();
|
||||
if (zoneManager)
|
||||
if (zoneClient)
|
||||
{
|
||||
for (U32 zoneId = zoneClient->mZoneRangeStart; zoneId < zoneClient->mZoneRangeStart + zoneClient->mNumZones; ++zoneId)
|
||||
for (SceneZoneSpaceManager::ZoneContentIterator iter(zoneManager, zoneId, false); iter.isValid(); ++iter)
|
||||
{
|
||||
SceneObject* obj = (SceneObject*)iter->getServerObject();
|
||||
bool fullyEnclosed = true;
|
||||
SceneZoneSpaceManager* zoneManager = zoneClient->getSceneManager()->getZoneManager();
|
||||
if (zoneManager)
|
||||
{
|
||||
for (U32 zoneId = zoneClient->mZoneRangeStart; zoneId < zoneClient->mZoneRangeStart + zoneClient->mNumZones; ++zoneId)
|
||||
for (SceneZoneSpaceManager::ZoneContentIterator iter(zoneManager, zoneId, false); iter.isValid(); ++iter)
|
||||
{
|
||||
SceneObject* obj = (SceneObject*)iter->getServerObject();
|
||||
bool fullyEnclosed = true;
|
||||
|
||||
for (SceneObject::ObjectZonesIterator zoneIter(obj); zoneIter.isValid(); ++zoneIter)
|
||||
{
|
||||
if (*zoneIter != zoneId);
|
||||
if (*zoneIter != zoneId)
|
||||
fullyEnclosed = false;
|
||||
}
|
||||
if (fullyEnclosed)
|
||||
sql.insertObject(obj);
|
||||
}
|
||||
if (fullyEnclosed)
|
||||
sql.insertObject(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -167,8 +167,8 @@ void Sun::initPersistFields()
|
|||
addField( "castShadows", TypeBool, Offset( mCastShadows, Sun ),
|
||||
"Enables/disables shadows cast by objects due to Sun light");
|
||||
|
||||
addField("staticRefreshFreq", TypeS32, Offset(mStaticRefreshFreq, Sun), "static shadow refresh rate (milliseconds)");
|
||||
addField("dynamicRefreshFreq", TypeS32, Offset(mDynamicRefreshFreq, Sun), "dynamic shadow refresh rate (milliseconds)");
|
||||
//addField("staticRefreshFreq", TypeS32, Offset(mStaticRefreshFreq, Sun), "static shadow refresh rate (milliseconds)");
|
||||
//addField("dynamicRefreshFreq", TypeS32, Offset(mDynamicRefreshFreq, Sun), "dynamic shadow refresh rate (milliseconds)");
|
||||
|
||||
endGroup( "Lighting" );
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "core/util/dxt5nmSwizzle.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/engineAPI.h"
|
||||
#include "renderInstance/renderProbeMgr.h"
|
||||
|
||||
using namespace Torque;
|
||||
|
||||
|
|
@ -1554,4 +1555,5 @@ DefineEngineFunction( reloadTextures, void, (),,
|
|||
return;
|
||||
|
||||
TEXMGR->reloadTextures();
|
||||
PROBEMGR->reloadTextures();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ public:
|
|||
|
||||
/// Return the lightBinManager for this light manager.
|
||||
AdvancedLightBinManager* getLightBinManager() { return mLightBinManager; }
|
||||
RenderDeferredMgr* getDeferredRenderBin() { return mDeferredRenderBin; }
|
||||
|
||||
// LightManager
|
||||
virtual bool isCompatible() const;
|
||||
|
|
|
|||
|
|
@ -537,9 +537,9 @@ ShadowMapParams::ShadowMapParams( LightInfo *light )
|
|||
numSplits = 4;
|
||||
logWeight = 0.91f;
|
||||
texSize = 1024;
|
||||
shadowDistance = 400.0f;
|
||||
shadowSoftness = 0.15f;
|
||||
fadeStartDist = 0.0f;
|
||||
shadowDistance = 100.0f;
|
||||
shadowSoftness = 0.2f;
|
||||
fadeStartDist = 75.0f;
|
||||
lastSplitTerrainOnly = false;
|
||||
mQuery = GFX->createOcclusionQuery();
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,11 @@
|
|||
#include "core/volume.h"
|
||||
#include "console/simSet.h"
|
||||
|
||||
#include "scene/reflectionManager.h"
|
||||
#include "renderInstance/renderDeferredMgr.h"
|
||||
#include "lighting/advanced/advancedLightManager.h"
|
||||
#include "lighting/advanced/advancedLightBinManager.h"
|
||||
|
||||
|
||||
MaterialList::MaterialList()
|
||||
{
|
||||
|
|
@ -412,6 +417,17 @@ void MaterialList::initMatInstances( const FeatureSet &features,
|
|||
matInst->init( MATMGR->getDefaultFeatures(), vertexFormat );
|
||||
mMatInstList[ i ] = matInst;
|
||||
}
|
||||
else
|
||||
{
|
||||
AdvancedLightManager* lightMgr = dynamic_cast<AdvancedLightManager*>(LIGHTMGR);
|
||||
if (lightMgr)
|
||||
{
|
||||
REFLECTMGR->getReflectionMaterial(matInst);
|
||||
|
||||
// Hunt for the pre-pass manager/target
|
||||
lightMgr->getDeferredRenderBin()->getDeferredMaterial(matInst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -424,7 +424,7 @@ void ProcessedMaterial::_setStageData()
|
|||
}
|
||||
else if (mMaterial->mDiffuseMapAsset[i] && !mMaterial->mDiffuseMapAsset[i].isNull())
|
||||
{
|
||||
mStages[i].setTex(MFT_DiffuseMap, mMaterial->mDiffuseMapAsset[i]->getImage());
|
||||
mStages[i].setTex(MFT_DiffuseMap, mMaterial->mDiffuseMapAsset[i]->getImage(GFXStaticTextureSRGBProfile));
|
||||
if (!mStages[i].getTex(MFT_DiffuseMap))
|
||||
{
|
||||
// Load a debug texture to make it clear to the user
|
||||
|
|
|
|||
|
|
@ -449,6 +449,8 @@ struct ParticleRenderInst : public RenderInst
|
|||
/// Bounding box render transform
|
||||
const MatrixF *bbModelViewProj;
|
||||
|
||||
Point3F wsPosition;
|
||||
|
||||
/// The particle texture.
|
||||
GFXTextureObject *diffuseTex;
|
||||
|
||||
|
|
|
|||
|
|
@ -505,6 +505,17 @@ void RenderProbeMgr::updateProbeTexture(ProbeRenderInst* probeInfo)
|
|||
#endif
|
||||
}
|
||||
|
||||
void RenderProbeMgr::reloadTextures()
|
||||
{
|
||||
U32 probeCount = mRegisteredProbes.size();
|
||||
for (U32 i = 0; i < probeCount; i++)
|
||||
{
|
||||
updateProbeTexture(&mRegisteredProbes[i]);
|
||||
}
|
||||
|
||||
mProbesDirty = true;
|
||||
}
|
||||
|
||||
void RenderProbeMgr::_setupPerFrameParameters(const SceneRenderState *state)
|
||||
{
|
||||
PROFILE_SCOPE(RenderProbeMgr_SetupPerFrameParameters);
|
||||
|
|
@ -562,112 +573,33 @@ void RenderProbeMgr::_update4ProbeConsts(const SceneData &sgData,
|
|||
{
|
||||
PROFILE_SCOPE(ProbeManager_Update4ProbeConsts);
|
||||
|
||||
return;
|
||||
|
||||
// Skip over gathering lights if we don't have to!
|
||||
//if (probeShaderConsts->isValid())
|
||||
{
|
||||
PROFILE_SCOPE(ProbeManager_Update4ProbeConsts_setProbes);
|
||||
|
||||
const U32 MAX_FORWARD_PROBES = 4;
|
||||
|
||||
static AlignedArray<Point4F> probePositionArray(MAX_FORWARD_PROBES, sizeof(Point4F));
|
||||
static AlignedArray<Point4F> refBoxMinArray(MAX_FORWARD_PROBES, sizeof(Point4F));
|
||||
static AlignedArray<Point4F> refBoxMaxArray(MAX_FORWARD_PROBES, sizeof(Point4F));
|
||||
static AlignedArray<Point4F> probeRefPositionArray(MAX_FORWARD_PROBES, sizeof(Point4F));
|
||||
static AlignedArray<Point4F> probeConfigArray(MAX_FORWARD_PROBES, sizeof(Point4F));
|
||||
|
||||
Vector<MatrixF> probeWorldToObjArray;
|
||||
probeWorldToObjArray.setSize(MAX_FORWARD_PROBES);
|
||||
//static AlignedArray<CubemapData> probeCubemap(4, sizeof(CubemapData));
|
||||
//F32 range;
|
||||
|
||||
// Need to clear the buffers so that we don't leak
|
||||
// lights from previous passes or have NaNs.
|
||||
dMemset(probePositionArray.getBuffer(), 0, probePositionArray.getBufferSize());
|
||||
dMemset(refBoxMinArray.getBuffer(), 0, refBoxMinArray.getBufferSize());
|
||||
dMemset(refBoxMaxArray.getBuffer(), 0, refBoxMaxArray.getBufferSize());
|
||||
dMemset(probeRefPositionArray.getBuffer(), 0, probeRefPositionArray.getBufferSize());
|
||||
dMemset(probeConfigArray.getBuffer(), 0, probeConfigArray.getBufferSize());
|
||||
ProbeDataSet probeSet(MAX_FORWARD_PROBES);
|
||||
|
||||
matSet.restoreSceneViewProjection();
|
||||
|
||||
//Array rendering
|
||||
U32 probeCount = mRegisteredProbes.size();
|
||||
getBestProbes(sgData.objTrans->getPosition(), &probeSet);
|
||||
|
||||
S8 bestPickProbes[4] = { -1,-1,-1,-1 };
|
||||
shaderConsts->setSafe(probeShaderConsts->mProbeCountSC, (S32)probeSet.effectiveProbeCount);
|
||||
|
||||
S32 skyLightIdx = -1;
|
||||
|
||||
U32 effectiveProbeCount = 0;
|
||||
for (U32 i = 0; i < probeCount; i++)
|
||||
{
|
||||
//if (effectiveProbeCount >= MAX_FORWARD_PROBES)
|
||||
// break;
|
||||
|
||||
const ProbeRenderInst& curEntry = mRegisteredProbes[i];
|
||||
if (!curEntry.mIsEnabled)
|
||||
continue;
|
||||
|
||||
if (!curEntry.mIsSkylight)
|
||||
{
|
||||
F32 dist = Point3F(sgData.objTrans->getPosition() - curEntry.getPosition()).len();
|
||||
|
||||
if (dist > curEntry.mRadius || dist > curEntry.mExtents.len())
|
||||
continue;
|
||||
|
||||
if(bestPickProbes[0] == -1 || (Point3F(sgData.objTrans->getPosition() - mRegisteredProbes[bestPickProbes[0]].mPosition).len() > dist))
|
||||
bestPickProbes[0] = i;
|
||||
else if (bestPickProbes[1] == -1 || (Point3F(sgData.objTrans->getPosition() - mRegisteredProbes[bestPickProbes[1]].mPosition).len() > dist))
|
||||
bestPickProbes[1] = i;
|
||||
else if (bestPickProbes[2] == -1 || (Point3F(sgData.objTrans->getPosition() - mRegisteredProbes[bestPickProbes[2]].mPosition).len() > dist))
|
||||
bestPickProbes[2] = i;
|
||||
else if (bestPickProbes[3] == -1 || (Point3F(sgData.objTrans->getPosition() - mRegisteredProbes[bestPickProbes[3]].mPosition).len() > dist))
|
||||
bestPickProbes[3] = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
skyLightIdx = curEntry.mCubemapIndex;
|
||||
}
|
||||
}
|
||||
|
||||
//Grab our best probe picks
|
||||
for (U32 i = 0; i < 4; i++)
|
||||
{
|
||||
if (bestPickProbes[i] == -1)
|
||||
continue;
|
||||
|
||||
const ProbeRenderInst& curEntry = mRegisteredProbes[bestPickProbes[i]];
|
||||
|
||||
probePositionArray[effectiveProbeCount] = curEntry.getPosition();
|
||||
probeRefPositionArray[effectiveProbeCount] = curEntry.mProbeRefOffset;
|
||||
probeWorldToObjArray[effectiveProbeCount] = curEntry.getTransform();
|
||||
|
||||
Point3F refPos = curEntry.getPosition() + curEntry.mProbeRefOffset;
|
||||
Point3F refBoxMin = refPos - curEntry.mProbeRefScale * curEntry.getTransform().getScale();
|
||||
Point3F refBoxMax = refPos + curEntry.mProbeRefScale * curEntry.getTransform().getScale();
|
||||
|
||||
refBoxMinArray[effectiveProbeCount] = Point4F(refBoxMin.x, refBoxMin.y, refBoxMin.z, 0);
|
||||
refBoxMaxArray[effectiveProbeCount] = Point4F(refBoxMax.x, refBoxMax.y, refBoxMax.z, 0);
|
||||
probeConfigArray[effectiveProbeCount] = Point4F(curEntry.mProbeShapeType,
|
||||
curEntry.mRadius,
|
||||
curEntry.mAtten,
|
||||
curEntry.mCubemapIndex);
|
||||
|
||||
effectiveProbeCount++;
|
||||
}
|
||||
|
||||
shaderConsts->setSafe(probeShaderConsts->mProbeCountSC, (S32)effectiveProbeCount);
|
||||
|
||||
shaderConsts->setSafe(probeShaderConsts->mProbePositionSC, probePositionArray);
|
||||
shaderConsts->setSafe(probeShaderConsts->mProbeRefPosSC, probeRefPositionArray);
|
||||
shaderConsts->setSafe(probeShaderConsts->mProbePositionSC, probeSet.probePositionArray);
|
||||
shaderConsts->setSafe(probeShaderConsts->mProbeRefPosSC, probeSet.probeRefPositionArray);
|
||||
|
||||
if(probeShaderConsts->isValid())
|
||||
shaderConsts->set(probeShaderConsts->mWorldToObjArraySC, probeWorldToObjArray.address(), effectiveProbeCount, GFXSCT_Float4x4);
|
||||
shaderConsts->set(probeShaderConsts->mWorldToObjArraySC, probeSet.probeWorldToObjArray.address(), probeSet.effectiveProbeCount, GFXSCT_Float4x4);
|
||||
|
||||
shaderConsts->setSafe(probeShaderConsts->mRefBoxMinSC, refBoxMinArray);
|
||||
shaderConsts->setSafe(probeShaderConsts->mRefBoxMaxSC, refBoxMaxArray);
|
||||
shaderConsts->setSafe(probeShaderConsts->mProbeConfigDataSC, probeConfigArray);
|
||||
shaderConsts->setSafe(probeShaderConsts->mRefBoxMinSC, probeSet.refBoxMinArray);
|
||||
shaderConsts->setSafe(probeShaderConsts->mRefBoxMaxSC, probeSet.refBoxMaxArray);
|
||||
shaderConsts->setSafe(probeShaderConsts->mProbeConfigDataSC, probeSet.probeConfigArray);
|
||||
|
||||
shaderConsts->setSafe(probeShaderConsts->mSkylightCubemapIdxSC, (float)skyLightIdx);
|
||||
shaderConsts->setSafe(probeShaderConsts->mSkylightCubemapIdxSC, (float)probeSet.skyLightIdx);
|
||||
|
||||
if(probeShaderConsts->mBRDFTextureMap->getSamplerRegister() != -1 && mBRDFTexture.isValid())
|
||||
GFX->setTexture(probeShaderConsts->mBRDFTextureMap->getSamplerRegister(), mBRDFTexture);
|
||||
|
|
@ -679,6 +611,90 @@ void RenderProbeMgr::_update4ProbeConsts(const SceneData &sgData,
|
|||
}
|
||||
}
|
||||
|
||||
void RenderProbeMgr::getBestProbes(const Point3F& objPosition, ProbeDataSet* probeDataSet)
|
||||
{
|
||||
PROFILE_SCOPE(ProbeManager_getBestProbes);
|
||||
|
||||
// Skip over gathering lights if we don't have to!
|
||||
//if (probeShaderConsts->isValid())
|
||||
{
|
||||
//Array rendering
|
||||
U32 probeCount = mRegisteredProbes.size();
|
||||
|
||||
Vector<S8> bestPickProbes;
|
||||
|
||||
probeDataSet->effectiveProbeCount = 0;
|
||||
for (U32 i = 0; i < probeCount; i++)
|
||||
{
|
||||
const ProbeRenderInst& curEntry = mRegisteredProbes[i];
|
||||
if (!curEntry.mIsEnabled)
|
||||
continue;
|
||||
|
||||
if (!curEntry.mIsSkylight)
|
||||
{
|
||||
F32 dist = Point3F(objPosition - curEntry.getPosition()).len();
|
||||
|
||||
if (dist > curEntry.mRadius || dist > curEntry.mExtents.len())
|
||||
continue;
|
||||
|
||||
S32 bestPickIndex = -1;
|
||||
for (U32 p = 0; p < bestPickProbes.size(); p++)
|
||||
{
|
||||
if (p > probeDataSet->MAX_PROBE_COUNT)
|
||||
break;
|
||||
|
||||
if (bestPickProbes[p] == -1 || (Point3F(objPosition - mRegisteredProbes[bestPickProbes[p]].mPosition).len() > dist))
|
||||
bestPickIndex = p;
|
||||
}
|
||||
|
||||
//Can't have over our max count. Otherwise, if we haven't found a good slot for our best pick, insert it
|
||||
//if we have a best pick slot, update it
|
||||
if (bestPickIndex == -1 || bestPickProbes.size() >= probeDataSet->MAX_PROBE_COUNT)
|
||||
bestPickProbes.push_back(i);
|
||||
else
|
||||
bestPickProbes[bestPickIndex] = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
probeDataSet->skyLightIdx = curEntry.mCubemapIndex;
|
||||
}
|
||||
}
|
||||
|
||||
//Grab our best probe picks
|
||||
for (U32 i = 0; i < bestPickProbes.size(); i++)
|
||||
{
|
||||
if (bestPickProbes[i] == -1)
|
||||
continue;
|
||||
|
||||
const ProbeRenderInst& curEntry = mRegisteredProbes[bestPickProbes[i]];
|
||||
|
||||
probeDataSet->probePositionArray[probeDataSet->effectiveProbeCount] = curEntry.getPosition();
|
||||
probeDataSet->probeRefPositionArray[probeDataSet->effectiveProbeCount] = curEntry.mProbeRefOffset;
|
||||
probeDataSet->probeWorldToObjArray[probeDataSet->effectiveProbeCount] = curEntry.getTransform();
|
||||
|
||||
Point3F refPos = curEntry.getPosition() + curEntry.mProbeRefOffset;
|
||||
Point3F refBoxMin = refPos - curEntry.mProbeRefScale * curEntry.getTransform().getScale();
|
||||
Point3F refBoxMax = refPos + curEntry.mProbeRefScale * curEntry.getTransform().getScale();
|
||||
|
||||
probeDataSet->refBoxMinArray[probeDataSet->effectiveProbeCount] = Point4F(refBoxMin.x, refBoxMin.y, refBoxMin.z, 0);
|
||||
probeDataSet->refBoxMaxArray[probeDataSet->effectiveProbeCount] = Point4F(refBoxMax.x, refBoxMax.y, refBoxMax.z, 0);
|
||||
probeDataSet->probeConfigArray[probeDataSet->effectiveProbeCount] = Point4F(curEntry.mProbeShapeType,
|
||||
curEntry.mRadius,
|
||||
curEntry.mAtten,
|
||||
curEntry.mCubemapIndex);
|
||||
|
||||
probeDataSet->effectiveProbeCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderProbeMgr::getProbeTextureData(ProbeTextureArrayData* probeTextureSet)
|
||||
{
|
||||
probeTextureSet->BRDFTexture = mBRDFTexture;
|
||||
probeTextureSet->prefilterArray = mPrefilterArray;
|
||||
probeTextureSet->irradianceArray = mIrradianceArray;
|
||||
}
|
||||
|
||||
void RenderProbeMgr::setProbeInfo(ProcessedMaterial *pmat,
|
||||
const Material *mat,
|
||||
const SceneData &sgData,
|
||||
|
|
|
|||
|
|
@ -100,6 +100,8 @@ struct ProbeRenderInst
|
|||
|
||||
U32 mProbeIdx;
|
||||
|
||||
F32 mMultiplier;
|
||||
|
||||
public:
|
||||
|
||||
ProbeRenderInst();
|
||||
|
|
@ -165,6 +167,51 @@ struct ProbeShaderConstants
|
|||
|
||||
typedef Map<GFXShader*, ProbeShaderConstants*> ProbeConstantMap;
|
||||
|
||||
struct ProbeDataSet
|
||||
{
|
||||
AlignedArray<Point4F> probePositionArray;
|
||||
AlignedArray<Point4F> refBoxMinArray;
|
||||
AlignedArray<Point4F> refBoxMaxArray;
|
||||
AlignedArray<Point4F> probeRefPositionArray;
|
||||
AlignedArray<Point4F> probeConfigArray;
|
||||
|
||||
Vector<MatrixF> probeWorldToObjArray;
|
||||
|
||||
S32 skyLightIdx;
|
||||
|
||||
U32 effectiveProbeCount;
|
||||
|
||||
U32 MAX_PROBE_COUNT;
|
||||
|
||||
ProbeDataSet(U32 maxProbeCount)
|
||||
{
|
||||
MAX_PROBE_COUNT = maxProbeCount;
|
||||
|
||||
probePositionArray = AlignedArray<Point4F>(maxProbeCount, sizeof(Point4F));
|
||||
refBoxMinArray = AlignedArray<Point4F>(maxProbeCount, sizeof(Point4F));
|
||||
refBoxMaxArray = AlignedArray<Point4F>(maxProbeCount, sizeof(Point4F));
|
||||
probeRefPositionArray = AlignedArray<Point4F>(maxProbeCount, sizeof(Point4F));
|
||||
probeConfigArray = AlignedArray<Point4F>(maxProbeCount, sizeof(Point4F));
|
||||
|
||||
probeWorldToObjArray.setSize(maxProbeCount);
|
||||
|
||||
// Need to clear the buffers so that we don't leak
|
||||
// lights from previous passes or have NaNs.
|
||||
dMemset(probePositionArray.getBuffer(), 0, probePositionArray.getBufferSize());
|
||||
dMemset(refBoxMinArray.getBuffer(), 0, refBoxMinArray.getBufferSize());
|
||||
dMemset(refBoxMaxArray.getBuffer(), 0, refBoxMaxArray.getBufferSize());
|
||||
dMemset(probeRefPositionArray.getBuffer(), 0, probeRefPositionArray.getBufferSize());
|
||||
dMemset(probeConfigArray.getBuffer(), 0, probeConfigArray.getBufferSize());
|
||||
}
|
||||
};
|
||||
|
||||
struct ProbeTextureArrayData
|
||||
{
|
||||
GFXTexHandle BRDFTexture;
|
||||
GFXCubemapArrayHandle prefilterArray;
|
||||
GFXCubemapArrayHandle irradianceArray;
|
||||
};
|
||||
|
||||
//**************************************************************************
|
||||
// RenderObjectMgr
|
||||
//**************************************************************************
|
||||
|
|
@ -292,11 +339,18 @@ public:
|
|||
|
||||
void updateProbeTexture(ProbeRenderInst* probeInfo);
|
||||
|
||||
void reloadTextures();
|
||||
|
||||
/// Debug rendering
|
||||
static bool smRenderReflectionProbes;
|
||||
|
||||
void bakeProbe(ReflectionProbe *probeInfo);
|
||||
void bakeProbes();
|
||||
|
||||
void getProbeTextureData(ProbeTextureArrayData* probeTextureSet);
|
||||
S32 getSkylightIndex() { return mSkylightCubemapIdx; }
|
||||
//accumulates the best fit of probes given the object position
|
||||
void getBestProbes(const Point3F& objPosition, ProbeDataSet* probeDataSet);
|
||||
};
|
||||
|
||||
RenderProbeMgr* RenderProbeMgr::getProbeManager()
|
||||
|
|
|
|||
|
|
@ -149,6 +149,13 @@ SceneObject::SceneObject()
|
|||
mSceneObjectLinks = NULL;
|
||||
|
||||
mObjectFlags.set( RenderEnabledFlag | SelectionEnabledFlag );
|
||||
// PATHSHAPE
|
||||
// init the scenegraph relationships to indicate no parent, no children, and no siblings
|
||||
mGraph.parent = NULL;
|
||||
mGraph.nextSibling = NULL;
|
||||
mGraph.firstChild = NULL;
|
||||
mGraph.objToParent.identity();
|
||||
// PATHSHAPE END
|
||||
mIsScopeAlways = false;
|
||||
|
||||
mAccuTex = NULL;
|
||||
|
|
@ -330,6 +337,9 @@ void SceneObject::onRemove()
|
|||
plUnlink();
|
||||
|
||||
Parent::onRemove();
|
||||
// PATHSHAPE
|
||||
if ( getParent() != NULL) attachToParent( NULL);
|
||||
// PATHSHAPE END
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -401,6 +411,9 @@ void SceneObject::setTransform( const MatrixF& mat )
|
|||
#endif
|
||||
|
||||
PROFILE_SCOPE( SceneObject_setTransform );
|
||||
// PATHSHAPE
|
||||
PerformUpdatesForChildren(mat);
|
||||
// PATHSHAPE END
|
||||
|
||||
// Update the transforms.
|
||||
|
||||
|
|
@ -875,6 +888,36 @@ U32 SceneObject::packUpdate( NetConnection* conn, U32 mask, BitStream* stream )
|
|||
if ( stream->writeFlag( mask & FlagMask ) )
|
||||
stream->writeRangedU32( (U32)mObjectFlags, 0, getObjectFlagMax() );
|
||||
|
||||
// PATHSHAPE
|
||||
//Begin attachment
|
||||
retMask = 0; //retry mask
|
||||
|
||||
if (stream->writeFlag(getParent() != NULL)) {
|
||||
stream->writeAffineTransform(mGraph.objToParent);
|
||||
}
|
||||
if (stream->writeFlag(mask & MountedMask))
|
||||
{
|
||||
// Check to see if we need to write an object ID
|
||||
if (stream->writeFlag(mGraph.parent)) {
|
||||
S32 t = conn->getGhostIndex(mGraph.parent);
|
||||
// Check to see if we can actually ghost this...
|
||||
if (t == -1) {
|
||||
// Cant, try again later
|
||||
retMask |= MountedMask;
|
||||
stream->writeFlag(false);
|
||||
}
|
||||
else {
|
||||
// Can, write it.
|
||||
stream->writeFlag(true);
|
||||
stream->writeRangedU32(U32(t), 0, NetConnection::MaxGhostCount);
|
||||
stream->writeAffineTransform(mGraph.objToParent);
|
||||
//Con::errorf("%d: sent mounted on %d", getId(), mGraph.parent->getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
// End of Attachment
|
||||
// PATHSHAPE END
|
||||
|
||||
if ( mask & MountedMask )
|
||||
{
|
||||
if ( mMount.object )
|
||||
|
|
@ -914,6 +957,44 @@ void SceneObject::unpackUpdate( NetConnection* conn, BitStream* stream )
|
|||
if ( stream->readFlag() )
|
||||
mObjectFlags = stream->readRangedU32( 0, getObjectFlagMax() );
|
||||
|
||||
// PATHSHAPE
|
||||
// begin of attachment
|
||||
if (stream->readFlag())
|
||||
{
|
||||
MatrixF m;
|
||||
stream->readAffineTransform(&m);
|
||||
mGraph.objToParent = m;
|
||||
}
|
||||
if (stream->readFlag())
|
||||
{
|
||||
// Check to see if we need to read an object ID
|
||||
if (stream->readFlag())
|
||||
{
|
||||
// Check to see if we can actually ghost this...
|
||||
if (stream->readFlag())
|
||||
{
|
||||
GameBase *newParent = static_cast<GameBase*>(conn->resolveGhost(stream->readRangedU32(0, NetConnection::MaxGhostCount)));
|
||||
MatrixF m;
|
||||
stream->readAffineTransform(&m);
|
||||
|
||||
if (getParent() != newParent)
|
||||
{
|
||||
clearProcessAfter();
|
||||
processAfter(newParent);
|
||||
}
|
||||
|
||||
attachToParent(newParent, &m);
|
||||
//Con::errorf("%d: got mounted on %d", getId(), mParentObject->getId());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
attachToParent(NULL);
|
||||
}
|
||||
}
|
||||
// End of attachment
|
||||
// PATHSHAPE END
|
||||
|
||||
// MountedMask
|
||||
if ( stream->readFlag() )
|
||||
{
|
||||
|
|
@ -1478,6 +1559,9 @@ DefineEngineMethod( SceneObject, setTransform, void, ( TransformF txfm ),,
|
|||
"Set the object's transform (orientation and position)."
|
||||
"@param txfm object transform to set" )
|
||||
{
|
||||
// PATHSHAPE
|
||||
object->PerformUpdatesForChildren(txfm.getMatrix());
|
||||
// PATHSHAPE END
|
||||
if ( !txfm.hasRotation() )
|
||||
object->setPosition( txfm.getPosition() );
|
||||
else
|
||||
|
|
@ -1551,3 +1635,356 @@ DefineEngineMethod(SceneObject, setForwardVector, void, (VectorF newForward, Vec
|
|||
{
|
||||
object->setForwardVector(newForward, upVector);
|
||||
}
|
||||
|
||||
// PATHSHAPE
|
||||
// Move RenderTransform by set amount
|
||||
// no longer used
|
||||
|
||||
void SceneObject::moveRender(const Point3F &delta)
|
||||
{
|
||||
Point3F pos;
|
||||
|
||||
const MatrixF& tmat = getRenderTransform();
|
||||
tmat.getColumn(3,&pos);
|
||||
AngAxisF aa(tmat);
|
||||
pos += delta;
|
||||
|
||||
MatrixF mat;
|
||||
aa.setMatrix(&mat);
|
||||
mat.setColumn(3,pos);
|
||||
setRenderTransform(mat);
|
||||
}
|
||||
|
||||
void SceneObject::PerformUpdatesForChildren(MatrixF mat){
|
||||
UpdateXformChange(mat);
|
||||
for (U32 i=0; i < getNumChildren(); i++) {
|
||||
SceneObject *o = getChild(i);
|
||||
o->updateChildTransform(); //update the position of the child object
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// This function will move the players based on how much it's
|
||||
// parent have moved
|
||||
void SceneObject::updateChildTransform(){
|
||||
if (getParent() != NULL){
|
||||
MatrixF one;
|
||||
MatrixF two;
|
||||
MatrixF three;
|
||||
MatrixF four;
|
||||
MatrixF mat;
|
||||
one= getTransform();
|
||||
two = getParent()->getTransform();
|
||||
one.affineInverse();
|
||||
four.mul(two,one);
|
||||
mat.mul(getParent()->mLastXform,getTransform());
|
||||
setTransform(mat);
|
||||
}
|
||||
}
|
||||
|
||||
// This function will move the rendered image based on how much it's
|
||||
// parent have moved since the processtick.
|
||||
// For some reason the player object must be updated via it's GetRenderTransform seen below,
|
||||
// Other objects seem to require getTransform() only
|
||||
void SceneObject::updateRenderChangesByParent(){
|
||||
if (getParent() != NULL){
|
||||
MatrixF renderXform = getParent()->getRenderTransform();
|
||||
MatrixF xform = getParent()->getTransform();
|
||||
xform.affineInverse();
|
||||
|
||||
MatrixF offset;
|
||||
offset.mul(renderXform, xform);
|
||||
|
||||
MatrixF mat;
|
||||
|
||||
//add the "offset" caused by the parents change, and add it to it's own
|
||||
// This is needed by objects that update their own render transform thru interpolate tick
|
||||
// Mostly for stationary objects.
|
||||
|
||||
if (getClassName() == "Player")
|
||||
mat.mul(offset,getRenderTransform());
|
||||
else
|
||||
mat.mul(offset,getTransform());
|
||||
setRenderTransform(mat);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//Ramen - Move Transform by set amount
|
||||
//written by Anthony Lovell
|
||||
void SceneObject::move(F32 x, F32 y, F32 z)
|
||||
{
|
||||
Point3F delta;
|
||||
delta.x = x;
|
||||
delta.y = y;
|
||||
delta.z = z;
|
||||
move(delta);
|
||||
}
|
||||
// move by a specified delta in root coordinate space
|
||||
void SceneObject::move(const Point3F &delta)
|
||||
{
|
||||
Point3F pos;
|
||||
|
||||
const MatrixF& tmat = getTransform();
|
||||
tmat.getColumn(3,&pos);
|
||||
AngAxisF aa(tmat);
|
||||
|
||||
pos += delta;
|
||||
|
||||
MatrixF mat;
|
||||
aa.setMatrix(&mat);
|
||||
mat.setColumn(3,pos);
|
||||
setTransform(mat);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//written by Anthony Lovell ----------------------------------------------------------
|
||||
U32
|
||||
SceneObject::getNumChildren() const
|
||||
{
|
||||
U32 num = 0;
|
||||
for (SceneObject *cur = mGraph.firstChild; cur; cur = cur->mGraph.nextSibling)
|
||||
num++;
|
||||
return num;
|
||||
}
|
||||
//written by Anthony Lovell ----------------------------------------------------------
|
||||
SceneObject *
|
||||
SceneObject::getChild(U32 index) const
|
||||
{
|
||||
SceneObject *cur = mGraph.firstChild;
|
||||
for (U32 i = 0;
|
||||
cur && i < index;
|
||||
i++)
|
||||
cur = cur->mGraph.nextSibling;
|
||||
return cur;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void SceneObject::UpdateXformChange(const MatrixF &mat){
|
||||
// This function gets the difference between the Transform and current Render transform
|
||||
// Used for Interpolation matching with the child objects who rely on this data.
|
||||
|
||||
MatrixF oldxform = getTransform();
|
||||
|
||||
oldxform.affineInverse();
|
||||
mLastXform.mul(mat,oldxform);
|
||||
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------
|
||||
bool
|
||||
SceneObject::attachChildAt(SceneObject *subObject, MatrixF atThisOffset, S32 node)
|
||||
{
|
||||
AssertFatal(subObject, "attaching a null subObject");
|
||||
AssertFatal(!isChildOf(subObject), "cyclic attachChild()");
|
||||
bool b = subObject->attachToParent(this, &atThisOffset, node);
|
||||
if (!b)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
bool
|
||||
SceneObject::attachChildAt(SceneObject *subObject, Point3F atThisPosition)
|
||||
{
|
||||
AssertFatal(subObject, "attaching a null subObject");
|
||||
AssertFatal(!isChildOf(subObject), "cyclic attachChild()");
|
||||
bool b = subObject->attachToParent(this);
|
||||
if (!b)
|
||||
return false;
|
||||
|
||||
subObject->mGraph.objToParent.setColumn(3, atThisPosition);
|
||||
// calcTransformFromLocalTransform();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
bool
|
||||
SceneObject::attachChild(SceneObject *child)
|
||||
{
|
||||
AssertFatal(child, "attaching a null subObject");
|
||||
AssertFatal(!isChildOf(child), "cyclic attachChild()");
|
||||
|
||||
return child->attachToParent(this);
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------
|
||||
/// returns a count of children plus their children, recursively
|
||||
U32
|
||||
SceneObject::getNumProgeny() const
|
||||
{
|
||||
U32 num = 0;
|
||||
for (SceneObject *cur = mGraph.firstChild; cur; cur = cur->mGraph.nextSibling) {
|
||||
num += 1 + cur->getNumProgeny();
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
DefineEngineMethod(SceneObject, getNumChildren, S32, (),, "returns number of direct child objects")
|
||||
{
|
||||
return object->getNumChildren();
|
||||
}
|
||||
|
||||
DefineEngineMethod(SceneObject, getNumProgeny, S32, (),, "returns number of recursively-nested child objects")
|
||||
{
|
||||
return object->getNumProgeny();
|
||||
}
|
||||
|
||||
DefineEngineMethod(SceneObject, getChild, S32, (S32 _index), (0), "getChild(S32 index) -- returns child SceneObject at given index")
|
||||
{
|
||||
SceneObject *s = object->getChild(_index);
|
||||
return s ? s->getId() : 0;
|
||||
}
|
||||
|
||||
DefineEngineMethod(SceneObject, attachChildAt, bool, (SceneObject* _subObject, MatrixF _offset, S32 _node), (nullAsType<SceneObject*>(), MatrixF::Identity, 0), "(SceneObject subObject, MatrixF offset, S32 offset)"
|
||||
"Mount object to this one with the specified offset expressed in our coordinate space.")
|
||||
{
|
||||
if (_subObject != nullptr)
|
||||
{
|
||||
return object->attachChildAt(_subObject, _offset, _node);
|
||||
}
|
||||
else
|
||||
{
|
||||
Con::errorf("Couldn't addObject()!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
DefineEngineMethod(SceneObject, attachToParent, bool, (const char*_sceneObject), ,"attachToParent(SceneObject)"
|
||||
"specify a null or non-null parent")
|
||||
{
|
||||
SceneObject * t;
|
||||
|
||||
if(Sim::findObject(_sceneObject, t))
|
||||
{
|
||||
return object->attachToParent(t);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((!dStrcmp("0", _sceneObject))|| (!dStrcmp("", _sceneObject)))
|
||||
return object->attachToParent(NULL);
|
||||
else
|
||||
{
|
||||
Con::errorf("Couldn't setParent()!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DefineEngineMethod(SceneObject, getParent, S32, (),, "returns ID of parent SceneObject")
|
||||
{
|
||||
SceneObject *p = object->getParent();
|
||||
return p ? p->getId() : -1;
|
||||
}
|
||||
|
||||
DefineEngineMethod(SceneObject, attachChild, bool, (const char*_subObject),, "(SceneObject subObject)"
|
||||
"attach an object to this one, preserving its present transform.")
|
||||
{
|
||||
SceneObject * t;
|
||||
MatrixF m;
|
||||
if(Sim::findObject(_subObject, t))
|
||||
return object->attachChild(t);
|
||||
|
||||
Con::errorf("Couldn't addObject()!");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SceneObject::isChildOf(SceneObject *so)
|
||||
{
|
||||
SceneObject *p = mGraph.parent;
|
||||
if (p) {
|
||||
if (p == so)
|
||||
return true;
|
||||
else
|
||||
return p->isChildOf(so);
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool SceneObject::attachToParent(SceneObject *newParent, MatrixF *atThisOffset/* = NULL */, S32 node )
|
||||
{
|
||||
SceneObject *oldParent = mGraph.parent;
|
||||
|
||||
if (oldParent == newParent)
|
||||
return true;
|
||||
|
||||
// cycles in the scene hierarchy are forbidden!
|
||||
// that is: a SceneObject cannot be a child of its progeny
|
||||
if (newParent && newParent->isChildOf(this))
|
||||
return false;
|
||||
|
||||
mGraph.parent = newParent;
|
||||
|
||||
if (oldParent) {
|
||||
|
||||
clearNotify(oldParent);
|
||||
|
||||
// remove this SceneObject from the list of children of oldParent
|
||||
SceneObject *cur = oldParent->mGraph.firstChild;
|
||||
if (cur == this) { // if we are the first child, this is easy
|
||||
oldParent->mGraph.firstChild = mGraph.nextSibling;
|
||||
} else {
|
||||
while (cur->mGraph.nextSibling != this) {
|
||||
cur = cur->mGraph.nextSibling;
|
||||
// ASSERT cur != NULL;
|
||||
}
|
||||
cur->mGraph.nextSibling = mGraph.nextSibling;
|
||||
}
|
||||
oldParent->onLostChild(this);
|
||||
}
|
||||
|
||||
if (newParent) {
|
||||
|
||||
deleteNotify(newParent); // if we are deleted, inform our parent
|
||||
|
||||
// add this SceneObject to the list of children of oldParent
|
||||
mGraph.nextSibling = newParent->mGraph.firstChild;
|
||||
newParent->mGraph.firstChild = this;
|
||||
mGraph.parent = newParent;
|
||||
|
||||
newParent->onNewChild(this);
|
||||
|
||||
if (atThisOffset)
|
||||
mGraph.objToParent = *atThisOffset;
|
||||
} else {
|
||||
mGraph.parent = NULL;
|
||||
mGraph.nextSibling = NULL;
|
||||
mGraph.objToParent = mObjToWorld;
|
||||
}
|
||||
|
||||
onLostParent(oldParent);
|
||||
onNewParent(newParent);
|
||||
|
||||
setMaskBits(MountedMask);
|
||||
return true;
|
||||
}
|
||||
|
||||
DefineEngineMethod(SceneObject, detachChild, bool, (const char*_subObject),, "SceneObject subObject")
|
||||
{
|
||||
SceneObject * t;
|
||||
if(Sim::findObject(_subObject, t)) {
|
||||
return t->attachToParent(NULL);
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
// subclasses can do something with these if they care to
|
||||
void SceneObject::onNewParent(SceneObject *newParent) {}
|
||||
void SceneObject::onLostParent(SceneObject *oldParent){}
|
||||
void SceneObject::onNewChild(SceneObject *newKid){}
|
||||
void SceneObject::onLostChild(SceneObject *lostKid){}
|
||||
|
|
|
|||
|
|
@ -287,6 +287,10 @@ class SceneObject : public NetObject, private SceneContainer::Link, public Proce
|
|||
/// @name Transform and Collision Members
|
||||
/// @{
|
||||
|
||||
// PATHSHAPE
|
||||
MatrixF mLastXform;
|
||||
// PATHSHAPE END
|
||||
|
||||
/// Transform from object space to world space.
|
||||
MatrixF mObjToWorld;
|
||||
|
||||
|
|
@ -818,6 +822,27 @@ class SceneObject : public NetObject, private SceneContainer::Link, public Proce
|
|||
static bool _setAccuEnabled( void *object, const char *index, const char *data );
|
||||
|
||||
/// @}
|
||||
// PATHSHAPE
|
||||
/// @}
|
||||
//Anthony's Original Code, still used so i keep it here
|
||||
/// TGE uses the term "mount" in a quirky, staticky way relating to its limited use to have
|
||||
/// riders and guns mounted on a vehicle (and similar)
|
||||
/// I did not alter that code at all (yet) and did not want to keep its terminology for other reasons
|
||||
/// I decided to support a hierarchy of scene objects and dubbed the operations
|
||||
/// attaching and removing child SceneObjects
|
||||
protected:
|
||||
|
||||
// this member struct tracks the relationship to parent and children
|
||||
// sceneObjects in a hierarchical scene graph whose root is the entire Scene
|
||||
struct AttachInfo {
|
||||
SceneObject* firstChild; ///< Objects mounted on this object
|
||||
SimObjectPtr<SceneObject> parent; ///< Object this object is mounted on.
|
||||
SceneObject* nextSibling; ///< Link to next child object of this object's parent
|
||||
MatrixF objToParent; ///< this obects transformation in the parent object's space
|
||||
MatrixF RenderobjToParent; ///< this obects Render Offset transformation to the parent object
|
||||
} mGraph;
|
||||
// PATHSHAPE END
|
||||
|
||||
|
||||
// Accumulation Texture
|
||||
// Note: This was placed in SceneObject to both ShapeBase and TSStatic could support it.
|
||||
|
|
@ -840,6 +865,83 @@ class SceneObject : public NetObject, private SceneContainer::Link, public Proce
|
|||
// as opposed to something like a Player that has a built-in camera that requires
|
||||
// special calculations to determine the view transform.
|
||||
virtual bool isCamera() const { return false; }
|
||||
// AFX CODE BLOCK (is-camera) >>
|
||||
// PATHSHAPE
|
||||
// Added for dynamic attaching
|
||||
void UpdateXformChange(const MatrixF &mat);
|
||||
/// this is useful for setting NULL parent (making SceneObject a root object)
|
||||
virtual bool attachToParent(SceneObject *parent, MatrixF *atThisOffset = NULL, S32 node=0);
|
||||
SceneObject *getParent() { return mGraph.parent; };
|
||||
|
||||
|
||||
/// attach a subobject, but do not alter the subObject's present absolute position or orientation
|
||||
bool attachChild(SceneObject* subObject);
|
||||
/// attach a subobject, at the specified offset expressed in our local coordinate space
|
||||
bool attachChildAt(SceneObject* subObject, MatrixF atThisTransform, S32 node);
|
||||
|
||||
/// attach a subobject, at the specified position expressed in our local coordinate space
|
||||
bool attachChildAt(SceneObject* subObject, Point3F atThisPosition);
|
||||
|
||||
/// how many child SceneObjects are (directly) attached to this one?
|
||||
U32 getNumChildren() const;
|
||||
|
||||
/// how many child objects does this SceneObject have when we count them recursively?
|
||||
U32 getNumProgeny() const;
|
||||
|
||||
/// returns the (direct) child SceneObject at the given index (0 <= index <= getNumChildren() - 1)
|
||||
SceneObject *getChild(U32 index) const;
|
||||
|
||||
/// is this SceneObject a child (directly or indirectly) of the given object?
|
||||
bool isChildOf(SceneObject *);
|
||||
|
||||
/// set position in parent SceneObject's coordinate space (or in world space if no parent)
|
||||
//void setLocalPosition(const Point3F &pos);
|
||||
|
||||
/// move the object in parent SceneObject's coordinate space (or in world space if no parent)
|
||||
//void localMove(const Point3F &delta);
|
||||
/// as localMove(const Point3F &delta), with different signature
|
||||
//void localMove(F32 x, F32 y, F32 z);
|
||||
|
||||
/// move the object in world space, without altering place in scene hierarchy
|
||||
void move(const Point3F &delta);
|
||||
|
||||
// Does checks for children objects and updates their positions
|
||||
void PerformUpdatesForChildren(MatrixF mat);
|
||||
|
||||
// Move the RenderTransform
|
||||
void moveRender(const Point3F &delta);
|
||||
//Calculate how much to adjust the render transform - Called by the child objects
|
||||
void updateRenderChangesByParent();
|
||||
//Calculate how much to adjust the transform - Called by the parent object
|
||||
void updateChildTransform();
|
||||
/// as move(const Point3F &delta), with different signature
|
||||
void move(F32 x, F32 y, F32 z);
|
||||
|
||||
/// returns the transform relative to parent SceneObject transform (or world transform if no parent)
|
||||
//const MatrixF& getLocalTransform() const;
|
||||
/// returns the position within parent SceneObject space (or world space if no parent)
|
||||
//Point3F getLocalPosition() const;
|
||||
|
||||
|
||||
// virtual void onParentScaleChanged();
|
||||
// virtual void onParentTransformChanged();
|
||||
|
||||
/// Sets the Object -> Parent transform. If no parent SceneObject, this is equivalent to
|
||||
/// setTransform()
|
||||
///
|
||||
/// @param mat New transform matrix
|
||||
//virtual void setLocalTransform(const MatrixF & mat);
|
||||
|
||||
|
||||
/// Called to let instance specific code happen
|
||||
virtual void onLostParent(SceneObject *oldParent);
|
||||
/// Called to let instance specific code happen
|
||||
virtual void onNewParent(SceneObject *newParent);
|
||||
/// notification that a direct child object has been attached
|
||||
virtual void onNewChild(SceneObject *subObject);
|
||||
/// notification that a direct child object has been detached
|
||||
virtual void onLostChild(SceneObject *subObject);
|
||||
// PATHSHAPE END
|
||||
};
|
||||
|
||||
#endif // _SCENEOBJECT_H_
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "core/stream/bitStream.h"
|
||||
#include "renderInstance/renderPassManager.h"
|
||||
#include "console/engineAPI.h"
|
||||
#include "T3D/pathShape.h"
|
||||
|
||||
#include "T3D/Scene.h"
|
||||
|
||||
|
|
@ -155,6 +156,11 @@ Path::Path()
|
|||
{
|
||||
mPathIndex = NoPathIndex;
|
||||
mIsLooping = true;
|
||||
mPathSpeed = 1.0f;
|
||||
mDataBlock = NULL;
|
||||
mSpawnCount = 1;
|
||||
mMinDelay = 0;
|
||||
mMaxDelay = 0;
|
||||
}
|
||||
|
||||
Path::~Path()
|
||||
|
|
@ -166,6 +172,13 @@ Path::~Path()
|
|||
void Path::initPersistFields()
|
||||
{
|
||||
addField("isLooping", TypeBool, Offset(mIsLooping, Path), "If this is true, the loop is closed, otherwise it is open.\n");
|
||||
addField("Speed", TypeF32, Offset(mPathSpeed, Path), "Speed.\n");
|
||||
addProtectedField("mPathShape", TYPEID< PathShapeData >(), Offset(mDataBlock, Path),
|
||||
&setDataBlockProperty, &defaultProtectedGetFn,
|
||||
"@brief Spawned PathShape.\n\n");
|
||||
addField("spawnCount", TypeS32, Offset(mSpawnCount, Path), "Spawn Count.\n");
|
||||
addField("minDelay", TypeS32, Offset(mMinDelay, Path), "Spawn Delay (min).\n");
|
||||
addField("maxDelay", TypeS32, Offset(mMaxDelay, Path), "Spawn Delay (max).\n");
|
||||
|
||||
Parent::initPersistFields();
|
||||
//
|
||||
|
|
@ -179,9 +192,14 @@ bool Path::onAdd()
|
|||
if(!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
onAdd_callback(getId());
|
||||
return true;
|
||||
}
|
||||
|
||||
IMPLEMENT_CALLBACK(Path, onAdd, void, (SimObjectId ID), (ID),
|
||||
"Called when this ScriptGroup is added to the system.\n"
|
||||
"@param ID Unique object ID assigned when created (%this in script).\n"
|
||||
);
|
||||
|
||||
void Path::onRemove()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -36,17 +36,21 @@
|
|||
#include "gfx/gfxPrimitiveBuffer.h"
|
||||
#endif
|
||||
|
||||
class BaseMatInstance;
|
||||
#ifndef _STATICSHAPE_H_
|
||||
#include "T3D/staticShape.h"
|
||||
#endif
|
||||
|
||||
class BaseMatInstance;
|
||||
struct PathShapeData;
|
||||
|
||||
namespace SimPath
|
||||
{
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/// A path!
|
||||
class Path : public SimGroup
|
||||
class Path : public GameBase
|
||||
{
|
||||
typedef SimGroup Parent;
|
||||
typedef GameBase Parent;
|
||||
|
||||
public:
|
||||
enum : U32
|
||||
|
|
@ -57,8 +61,12 @@ class Path : public SimGroup
|
|||
|
||||
private:
|
||||
U32 mPathIndex;
|
||||
F32 mPathSpeed;
|
||||
bool mIsLooping;
|
||||
|
||||
PathShapeData* mDataBlock;
|
||||
S32 mSpawnCount;
|
||||
S32 mMinDelay;
|
||||
S32 mMaxDelay;
|
||||
protected:
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
|
|
@ -77,6 +85,7 @@ class Path : public SimGroup
|
|||
|
||||
DECLARE_CONOBJECT(Path);
|
||||
static void initPersistFields();
|
||||
DECLARE_CALLBACK(void, onAdd, (SimObjectId ID));
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -2143,7 +2143,7 @@ template<> void *Resource<TSShape>::create(const Torque::Path &path)
|
|||
ret = new TSShape;
|
||||
readSuccess = ret->read(&stream);
|
||||
}
|
||||
else if ( extension.equal( "dae", String::NoCase ) || extension.equal( "kmz", String::NoCase ) )
|
||||
/*else if ( extension.equal( "dae", String::NoCase ) || extension.equal( "kmz", String::NoCase ) )
|
||||
{
|
||||
#ifdef TORQUE_COLLADA
|
||||
// Attempt to load the DAE file
|
||||
|
|
@ -2164,7 +2164,7 @@ template<> void *Resource<TSShape>::create(const Torque::Path &path)
|
|||
ret = new TSShape;
|
||||
readSuccess = ret->read(&stream);
|
||||
#endif
|
||||
}
|
||||
}*/
|
||||
else
|
||||
{
|
||||
//Con::errorf( "Resource<TSShape>::create - '%s' has an unknown file format", path.getFullPath().c_str() );
|
||||
|
|
|
|||
|
|
@ -76,6 +76,8 @@ void FPSTracker::update()
|
|||
F32 update = fpsRealLast - fpsNext;
|
||||
if (update > 0.5f)
|
||||
{
|
||||
F32 delta = realSeconds - fpsNext;
|
||||
Con::setVariable( "fps::frameDelta",avar("%g", delta));
|
||||
Con::setVariable( "fps::real", avar( "%4.1f", 1.0f / fpsReal ) );
|
||||
Con::setVariable( "fps::realMin", avar( "%4.1f", 1.0f / fpsRealMin ) );
|
||||
Con::setVariable( "fps::realMax", avar( "%4.1f", 1.0f / fpsRealMax ) );
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue