truly a community project, this has been kicking around since 2003 in various forms. adds a path following shape that can be ridden.

This commit is contained in:
AzaezelX 2020-01-11 23:58:30 -06:00
parent f007700646
commit f7f8faf47e
14 changed files with 1399 additions and 8 deletions

View file

@ -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
}
//-----------------------------------------------------------------------------
@ -402,6 +412,9 @@ void SceneObject::setTransform( const MatrixF& mat )
#endif
PROFILE_SCOPE( SceneObject_setTransform );
// PATHSHAPE
PerformUpdatesForChildren(mat);
// PATHSHAPE END
// Update the transforms.
@ -876,6 +889,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 )
@ -915,6 +958,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() )
{
@ -1479,6 +1560,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
@ -1552,3 +1636,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){}

View file

@ -293,6 +293,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;
@ -819,6 +823,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.
@ -841,6 +866,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_

View file

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

View file

@ -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));
};
//--------------------------------------------------------------------------