mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-04-29 08:15:44 +00:00
Merge branch 'ExpandsComponents' of https://github.com/Areloch/Torque3D into development
This commit is contained in:
commit
b4a744a366
51 changed files with 4566 additions and 1710 deletions
|
|
@ -74,7 +74,7 @@ AnimationComponent::AnimationComponent() : Component()
|
||||||
mNetworked = true;
|
mNetworked = true;
|
||||||
|
|
||||||
mFriendlyName = "Animation(Component)";
|
mFriendlyName = "Animation(Component)";
|
||||||
mComponentType = "Render";
|
mComponentType = "Animation";
|
||||||
|
|
||||||
mDescription = getDescriptionText("Allows a rendered mesh to be animated");
|
mDescription = getDescriptionText("Allows a rendered mesh to be animated");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ public:
|
||||||
|
|
||||||
TSShape* getShape();
|
TSShape* getShape();
|
||||||
|
|
||||||
void targetShapeChanged(RenderComponentInterface* instanceInterface);
|
virtual void targetShapeChanged(RenderComponentInterface* instanceInterface);
|
||||||
|
|
||||||
virtual void processTick();
|
virtual void processTick();
|
||||||
virtual void advanceTime(F32 dt);
|
virtual void advanceTime(F32 dt);
|
||||||
|
|
|
||||||
|
|
@ -92,13 +92,13 @@ void SoundComponent::onComponentAdd()
|
||||||
{
|
{
|
||||||
Parent::onComponentAdd();
|
Parent::onComponentAdd();
|
||||||
|
|
||||||
Con::printf("We were added to an entity! SoundComponent reporting in for owner entity %i", mOwner->getId());
|
//Con::printf("We were added to an entity! SoundComponent reporting in for owner entity %i", mOwner->getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
//This is called when the component has been removed from an entity
|
//This is called when the component has been removed from an entity
|
||||||
void SoundComponent::onComponentRemove()
|
void SoundComponent::onComponentRemove()
|
||||||
{
|
{
|
||||||
Con::printf("We were removed from our entity! SoundComponent signing off for owner entity %i", mOwner->getId());
|
//Con::printf("We were removed from our entity! SoundComponent signing off for owner entity %i", mOwner->getId());
|
||||||
Parent::onComponentRemove();
|
Parent::onComponentRemove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,14 +113,14 @@ void SoundComponent::componentAddedToOwner(Component *comp)
|
||||||
playAudio(slotNum, mSoundFile[slotNum]);
|
playAudio(slotNum, mSoundFile[slotNum]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Con::printf("Our owner entity has a new component being added! SoundComponent welcomes component %i of type %s", comp->getId(), comp->getClassRep()->getNameSpace());
|
//Con::printf("Our owner entity has a new component being added! SoundComponent welcomes component %i of type %s", comp->getId(), comp->getClassRep()->getNameSpace());
|
||||||
}
|
}
|
||||||
|
|
||||||
//This is called any time a component is removed from an entity. Every component current owned by the entity is informed of the event.
|
//This is called any time a component is removed from an entity. Every component current owned by the entity is informed of the event.
|
||||||
//This allows cleanup and dependency management.
|
//This allows cleanup and dependency management.
|
||||||
void SoundComponent::componentRemovedFromOwner(Component *comp)
|
void SoundComponent::componentRemovedFromOwner(Component *comp)
|
||||||
{
|
{
|
||||||
Con::printf("Our owner entity has a removed a component! SoundComponent waves farewell to component %i of type %s", comp->getId(), comp->getClassRep()->getNameSpace());
|
//Con::printf("Our owner entity has a removed a component! SoundComponent waves farewell to component %i of type %s", comp->getId(), comp->getClassRep()->getNameSpace());
|
||||||
}
|
}
|
||||||
|
|
||||||
//Regular init persist fields function to set up static fields.
|
//Regular init persist fields function to set up static fields.
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -19,190 +19,188 @@
|
||||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#ifndef COLLISION_COMPONENT_H
|
#ifndef COLLISION_COMPONENT_H
|
||||||
#define COLLISION_COMPONENT_H
|
#define COLLISION_COMPONENT_H
|
||||||
|
|
||||||
#ifndef __RESOURCE_H__
|
#ifndef COMPONENT_H
|
||||||
#include "core/resource.h"
|
#include "T3D/components/component.h"
|
||||||
#endif
|
#endif
|
||||||
#ifndef _TSSHAPE_H_
|
|
||||||
#include "ts/tsShape.h"
|
#ifndef _CONVEX_H_
|
||||||
|
#include "collision/convex.h"
|
||||||
#endif
|
#endif
|
||||||
#ifndef _SCENERENDERSTATE_H_
|
#ifndef _COLLISION_H_
|
||||||
#include "scene/sceneRenderState.h"
|
#include "collision/collision.h"
|
||||||
#endif
|
#endif
|
||||||
#ifndef _MBOX_H_
|
#ifndef _EARLYOUTPOLYLIST_H_
|
||||||
#include "math/mBox.h"
|
#include "collision/earlyOutPolyList.h"
|
||||||
#endif
|
#endif
|
||||||
#ifndef ENTITY_H
|
#ifndef _SIM_H_
|
||||||
#include "T3D/entity.h"
|
#include "console/sim.h"
|
||||||
#endif
|
#endif
|
||||||
#ifndef CORE_INTERFACES_H
|
#ifndef _SCENECONTAINER_H_
|
||||||
#include "T3D/components/coreInterfaces.h"
|
#include "scene/sceneContainer.h"
|
||||||
#endif
|
|
||||||
#ifndef COLLISION_INTERFACES_H
|
|
||||||
#include "T3D/components/collision/collisionInterfaces.h"
|
|
||||||
#endif
|
|
||||||
#ifndef RENDER_COMPONENT_INTERFACE_H
|
|
||||||
#include "T3D/components/render/renderComponentInterface.h"
|
|
||||||
#endif
|
|
||||||
#ifndef PHYSICS_COMPONENT_INTERFACE_H
|
|
||||||
#include "T3D/components/physics/physicsComponentInterface.h"
|
|
||||||
#endif
|
#endif
|
||||||
#ifndef _T3D_PHYSICSCOMMON_H_
|
#ifndef _T3D_PHYSICSCOMMON_H_
|
||||||
#include "T3D/physics/physicsCommon.h"
|
#include "T3D/physics/physicsCommon.h"
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef PHYSICS_COMPONENT_H
|
||||||
|
#include "T3D/components/physics/physicsComponent.h"
|
||||||
|
#endif
|
||||||
#ifndef _T3D_PHYSICS_PHYSICSWORLD_H_
|
#ifndef _T3D_PHYSICS_PHYSICSWORLD_H_
|
||||||
#include "T3D/physics/physicsWorld.h"
|
#include "T3D/physics/physicsWorld.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class TSShapeInstance;
|
struct CollisionContactInfo
|
||||||
class SceneRenderState;
|
{
|
||||||
class CollisionComponent;
|
bool contacted, move;
|
||||||
class PhysicsBody;
|
SceneObject *contactObject;
|
||||||
class PhysicsWorld;
|
VectorF idealContactNormal;
|
||||||
|
VectorF contactNormal;
|
||||||
|
Point3F contactPoint;
|
||||||
|
F32 contactTime;
|
||||||
|
S32 contactTimer;
|
||||||
|
BaseMatInstance *contactMaterial;
|
||||||
|
|
||||||
class CollisionComponent : public Component,
|
Vector<SceneObject*> overlapObjects;
|
||||||
public CollisionInterface,
|
|
||||||
public CastRayInterface
|
void clear()
|
||||||
|
{
|
||||||
|
contacted=move=false;
|
||||||
|
contactObject = NULL;
|
||||||
|
contactNormal.set(0,0,0);
|
||||||
|
contactTime = 0.f;
|
||||||
|
contactTimer = 0;
|
||||||
|
idealContactNormal.set(0, 0, 1);
|
||||||
|
contactMaterial = NULL;
|
||||||
|
overlapObjects.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
CollisionContactInfo() { clear(); }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class CollisionComponent : public Component
|
||||||
{
|
{
|
||||||
typedef Component Parent;
|
typedef Component Parent;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum MeshType
|
// CollisionTimeout
|
||||||
|
// This struct lets us track our collisions and estimate when they've have timed out and we'll need to act on it.
|
||||||
|
struct CollisionTimeout
|
||||||
{
|
{
|
||||||
None = 0, ///< No mesh
|
CollisionTimeout* next;
|
||||||
Bounds = 1, ///< Bounding box of the shape
|
SceneObject* object;
|
||||||
CollisionMesh = 2, ///< Specifically designated collision meshes
|
U32 objectNumber;
|
||||||
VisibleMesh = 3 ///< Rendered mesh polygons
|
SimTime expireTime;
|
||||||
|
VectorF vector;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Signal< void( SceneObject* ) > onCollisionSignal;
|
||||||
|
Signal< void( SceneObject* ) > onContactSignal;
|
||||||
|
|
||||||
|
protected:
|
||||||
PhysicsWorld* mPhysicsWorld;
|
PhysicsWorld* mPhysicsWorld;
|
||||||
PhysicsBody* mPhysicsRep;
|
PhysicsBody* mPhysicsRep;
|
||||||
|
|
||||||
protected:
|
CollisionTimeout* mTimeoutList;
|
||||||
MeshType mCollisionType;
|
static CollisionTimeout* sFreeTimeoutList;
|
||||||
MeshType mDecalType;
|
|
||||||
MeshType mLOSType;
|
|
||||||
|
|
||||||
Vector<S32> mCollisionDetails;
|
CollisionList mCollisionList;
|
||||||
Vector<S32> mLOSDetails;
|
Vector<CollisionComponent*> mCollisionNotifyList;
|
||||||
|
|
||||||
StringTableEntry colisionMeshPrefix;
|
CollisionContactInfo mContactInfo;
|
||||||
|
|
||||||
RenderComponentInterface* mOwnerRenderInterface;
|
U32 CollisionMoveMask;
|
||||||
|
|
||||||
PhysicsComponentInterface* mOwnerPhysicsInterface;
|
bool mBlockColliding;
|
||||||
|
|
||||||
//only really relevent for the collision mesh type
|
bool mCollisionInited;
|
||||||
//if we note an animation component is added, we flag as being animated.
|
|
||||||
//This way, if we're using collision meshes, we can set it up to update their transforms
|
|
||||||
//as needed
|
|
||||||
bool mAnimated;
|
|
||||||
|
|
||||||
enum
|
void handleCollisionNotifyList();
|
||||||
{
|
|
||||||
ColliderMask = Parent::NextFreeMask,
|
void queueCollision( SceneObject *obj, const VectorF &vec);
|
||||||
};
|
|
||||||
|
/// checkEarlyOut
|
||||||
|
/// This function lets you trying and early out of any expensive collision checks by using simple extruded poly boxes representing our objects
|
||||||
|
/// If it returns true, we know we won't hit with the given parameters and can successfully early out. If it returns false, our test case collided
|
||||||
|
/// and we should do the full collision sim.
|
||||||
|
bool checkEarlyOut(Point3F start, VectorF velocity, F32 time, Box3F objectBox, Point3F objectScale,
|
||||||
|
Box3F collisionBox, U32 collisionMask, CollisionWorkingList &colWorkingList);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CollisionComponent();
|
CollisionComponent();
|
||||||
virtual ~CollisionComponent();
|
virtual ~CollisionComponent();
|
||||||
|
|
||||||
DECLARE_CONOBJECT(CollisionComponent);
|
DECLARE_CONOBJECT(CollisionComponent);
|
||||||
|
|
||||||
virtual U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream);
|
//Setup
|
||||||
virtual void unpackUpdate(NetConnection *con, BitStream *stream);
|
virtual void prepCollision() {};
|
||||||
|
|
||||||
virtual void componentAddedToOwner(Component *comp);
|
/// checkCollisions
|
||||||
virtual void componentRemovedFromOwner(Component *comp);
|
// This is our main function for checking if a collision is happening based on the start point, velocity and time
|
||||||
virtual void ownerTransformSet(MatrixF *mat);
|
// We do the bulk of the collision checking in here
|
||||||
void targetShapeChanged(RenderComponentInterface* instanceInterface);
|
//virtual bool checkCollisions( const F32 travelTime, Point3F *velocity, Point3F start )=0;
|
||||||
|
|
||||||
virtual void onComponentRemove();
|
CollisionList *getCollisionList() { return &mCollisionList; }
|
||||||
virtual void onComponentAdd();
|
|
||||||
|
|
||||||
virtual void checkDependencies();
|
void clearCollisionList() { mCollisionList.clear(); }
|
||||||
|
|
||||||
static void initPersistFields();
|
void clearCollisionNotifyList() { mCollisionNotifyList.clear(); }
|
||||||
|
|
||||||
void inspectPostApply();
|
Collision *getCollision(S32 col);
|
||||||
|
|
||||||
virtual void processTick();
|
CollisionContactInfo* getContactInfo() { return &mContactInfo; }
|
||||||
|
|
||||||
void prepCollision();
|
enum PublicConstants {
|
||||||
|
CollisionTimeoutValue = 250
|
||||||
|
};
|
||||||
|
|
||||||
PhysicsCollision* buildColShapes();
|
bool doesBlockColliding() { return mBlockColliding; }
|
||||||
|
|
||||||
void updatePhysics();
|
/// handleCollisionList
|
||||||
|
/// This basically takes in a CollisionList and calls handleCollision for each.
|
||||||
|
void handleCollisionList(CollisionList &collisionList, VectorF velocity);
|
||||||
|
|
||||||
virtual bool castRay(const Point3F &start, const Point3F &end, RayInfo* info);
|
/// handleCollision
|
||||||
|
/// This will take a collision and queue the collision info for the object so that in knows about the collision.
|
||||||
|
void handleCollision(Collision &col, VectorF velocity);
|
||||||
|
|
||||||
virtual bool buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F &box, const SphereF &sphere){ return false; }
|
virtual bool checkCollisions(const F32 travelTime, Point3F *velocity, Point3F start);
|
||||||
|
virtual bool updateCollisions(F32 time, VectorF vector, VectorF velocity);
|
||||||
|
virtual void updateWorkingCollisionSet(const U32 mask);
|
||||||
|
|
||||||
virtual PhysicsCollision* getCollisionData();
|
//
|
||||||
|
bool buildConvexOpcode(TSShapeInstance* sI, S32 dl, const Box3F &bounds, Convex *c, Convex *list);
|
||||||
|
bool buildMeshOpcode(TSMesh *mesh, const MatrixF &meshToObjectMat, const Box3F &bounds, Convex *convex, Convex *list);
|
||||||
|
|
||||||
//Utility functions, mostly for script
|
bool castRayOpcode(S32 dl, const Point3F & startPos, const Point3F & endPos, RayInfo *info);
|
||||||
Point3F getContactNormal() { return mContactInfo.contactNormal; }
|
bool castRayMeshOpcode(TSMesh *mesh, const Point3F &s, const Point3F &e, RayInfo *info, TSMaterialList *materials);
|
||||||
bool hasContact()
|
|
||||||
{
|
virtual PhysicsCollision* getCollisionData() {
|
||||||
if (mContactInfo.contactObject)
|
return nullptr;
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
S32 getCollisionCount()
|
|
||||||
{
|
|
||||||
return mCollisionList.getCount();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Point3F getCollisionNormal(S32 collisionIndex)
|
virtual PhysicsBody *getPhysicsRep()
|
||||||
{
|
{
|
||||||
if (collisionIndex < 0 || mCollisionList.getCount() < collisionIndex)
|
return mPhysicsRep;
|
||||||
return Point3F::Zero;
|
|
||||||
|
|
||||||
return mCollisionList[collisionIndex].normal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
F32 getCollisionAngle(S32 collisionIndex, Point3F upVector)
|
void buildConvex(const Box3F& box, Convex* convex) {}
|
||||||
{
|
bool buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F &box, const SphereF &sphere) { return false; }
|
||||||
if (collisionIndex < 0 || mCollisionList.getCount() < collisionIndex)
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
return mRadToDeg(mAcos(mDot(mCollisionList[collisionIndex].normal, upVector)));
|
//
|
||||||
}
|
Point3F getContactNormal();
|
||||||
|
bool hasContact();
|
||||||
|
S32 getCollisionCount();
|
||||||
|
Point3F getCollisionNormal(S32 collisionIndex);
|
||||||
|
F32 getCollisionAngle(S32 collisionIndex, Point3F upVector);
|
||||||
|
S32 getBestCollision(Point3F upVector);
|
||||||
|
F32 getBestCollisionAngle(VectorF upVector);
|
||||||
|
|
||||||
S32 getBestCollision(Point3F upVector)
|
Signal< void(PhysicsCollision* collision) > onCollisionChanged;
|
||||||
{
|
|
||||||
S32 bestCollision = -1;
|
|
||||||
|
|
||||||
F32 bestAngle = 360.f;
|
|
||||||
S32 count = mCollisionList.getCount();
|
|
||||||
for (U32 i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
F32 angle = mRadToDeg(mAcos(mDot(mCollisionList[i].normal, upVector)));
|
|
||||||
|
|
||||||
if (angle < bestAngle)
|
|
||||||
{
|
|
||||||
bestCollision = i;
|
|
||||||
bestAngle = angle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bestCollision;
|
|
||||||
}
|
|
||||||
|
|
||||||
F32 getBestCollisionAngle(VectorF upVector)
|
|
||||||
{
|
|
||||||
S32 bestCol = getBestCollision(upVector);
|
|
||||||
|
|
||||||
if (bestCol == -1)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return getCollisionAngle(bestCol, upVector);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef CollisionComponent::MeshType CollisionMeshMeshType;
|
#endif
|
||||||
DefineEnumType(CollisionMeshMeshType);
|
|
||||||
|
|
||||||
#endif // COLLISION_COMPONENT_H
|
|
||||||
|
|
@ -1,258 +0,0 @@
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Copyright (c) 2012 GarageGames, LLC
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to
|
|
||||||
// deal in the Software without restriction, including without limitation the
|
|
||||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
||||||
// sell copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
||||||
// IN THE SOFTWARE.
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#include "T3D/components/collision/collisionInterfaces.h"
|
|
||||||
#include "scene/sceneObject.h"
|
|
||||||
#include "T3D/entity.h"
|
|
||||||
#include "console/engineAPI.h"
|
|
||||||
#include "T3D/trigger.h"
|
|
||||||
#include "materials/baseMatInstance.h"
|
|
||||||
|
|
||||||
void CollisionInterface::handleCollisionList( CollisionList &collisionList, VectorF velocity )
|
|
||||||
{
|
|
||||||
Collision bestCol;
|
|
||||||
|
|
||||||
mCollisionList = collisionList;
|
|
||||||
|
|
||||||
for (U32 i=0; i < collisionList.getCount(); ++i)
|
|
||||||
{
|
|
||||||
Collision& colCheck = collisionList[i];
|
|
||||||
|
|
||||||
if (colCheck.object)
|
|
||||||
{
|
|
||||||
if (colCheck.object->getTypeMask() & PlayerObjectType)
|
|
||||||
{
|
|
||||||
handleCollision( colCheck, velocity );
|
|
||||||
}
|
|
||||||
else if (colCheck.object->getTypeMask() & TriggerObjectType)
|
|
||||||
{
|
|
||||||
// We've hit it's bounding box, that's close enough for triggers
|
|
||||||
Trigger* pTrigger = static_cast<Trigger*>(colCheck.object);
|
|
||||||
|
|
||||||
Component *comp = dynamic_cast<Component*>(this);
|
|
||||||
pTrigger->potentialEnterObject(comp->getOwner());
|
|
||||||
}
|
|
||||||
else if (colCheck.object->getTypeMask() & DynamicShapeObjectType)
|
|
||||||
{
|
|
||||||
Con::printf("HIT A GENERICALLY DYNAMIC OBJECT");
|
|
||||||
handleCollision(colCheck, velocity);
|
|
||||||
}
|
|
||||||
else if(colCheck.object->getTypeMask() & EntityObjectType)
|
|
||||||
{
|
|
||||||
Entity* ent = dynamic_cast<Entity*>(colCheck.object);
|
|
||||||
if (ent)
|
|
||||||
{
|
|
||||||
CollisionInterface *colObjectInterface = ent->getComponent<CollisionInterface>();
|
|
||||||
if (colObjectInterface)
|
|
||||||
{
|
|
||||||
//convert us to our component
|
|
||||||
Component *thisComp = dynamic_cast<Component*>(this);
|
|
||||||
if (thisComp)
|
|
||||||
{
|
|
||||||
colObjectInterface->onCollisionSignal.trigger(thisComp->getOwner());
|
|
||||||
|
|
||||||
//TODO: properly do this
|
|
||||||
Collision oppositeCol = colCheck;
|
|
||||||
oppositeCol.object = thisComp->getOwner();
|
|
||||||
|
|
||||||
colObjectInterface->handleCollision(oppositeCol, velocity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
handleCollision(colCheck, velocity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CollisionInterface::handleCollision( Collision &col, VectorF velocity )
|
|
||||||
{
|
|
||||||
if (col.object && (mContactInfo.contactObject == NULL ||
|
|
||||||
col.object->getId() != mContactInfo.contactObject->getId()))
|
|
||||||
{
|
|
||||||
queueCollision(col.object, velocity - col.object->getVelocity());
|
|
||||||
|
|
||||||
//do the callbacks to script for this collision
|
|
||||||
Component *comp = dynamic_cast<Component*>(this);
|
|
||||||
if (comp->isMethod("onCollision"))
|
|
||||||
{
|
|
||||||
S32 matId = col.material != NULL ? col.material->getMaterial()->getId() : 0;
|
|
||||||
Con::executef(comp, "onCollision", col.object, col.normal, col.point, matId, velocity);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (comp->getOwner()->isMethod("onCollisionEvent"))
|
|
||||||
{
|
|
||||||
S32 matId = col.material != NULL ? col.material->getMaterial()->getId() : 0;
|
|
||||||
Con::executef(comp->getOwner(), "onCollisionEvent", col.object, col.normal, col.point, matId, velocity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CollisionInterface::handleCollisionNotifyList()
|
|
||||||
{
|
|
||||||
//special handling for any collision components we should notify that a collision happened.
|
|
||||||
for (U32 i = 0; i < mCollisionNotifyList.size(); ++i)
|
|
||||||
{
|
|
||||||
//convert us to our component
|
|
||||||
Component *thisComp = dynamic_cast<Component*>(this);
|
|
||||||
if (thisComp)
|
|
||||||
{
|
|
||||||
mCollisionNotifyList[i]->onCollisionSignal.trigger(thisComp->getOwner());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mCollisionNotifyList.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
Chunker<CollisionInterface::CollisionTimeout> sCollisionTimeoutChunker;
|
|
||||||
CollisionInterface::CollisionTimeout* CollisionInterface::sFreeTimeoutList = 0;
|
|
||||||
|
|
||||||
void CollisionInterface::queueCollision( SceneObject *obj, const VectorF &vec)
|
|
||||||
{
|
|
||||||
// Add object to list of collisions.
|
|
||||||
SimTime time = Sim::getCurrentTime();
|
|
||||||
S32 num = obj->getId();
|
|
||||||
|
|
||||||
CollisionTimeout** adr = &mTimeoutList;
|
|
||||||
CollisionTimeout* ptr = mTimeoutList;
|
|
||||||
while (ptr)
|
|
||||||
{
|
|
||||||
if (ptr->objectNumber == num)
|
|
||||||
{
|
|
||||||
if (ptr->expireTime < time)
|
|
||||||
{
|
|
||||||
ptr->expireTime = time + CollisionTimeoutValue;
|
|
||||||
ptr->object = obj;
|
|
||||||
ptr->vector = vec;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Recover expired entries
|
|
||||||
if (ptr->expireTime < time)
|
|
||||||
{
|
|
||||||
CollisionTimeout* cur = ptr;
|
|
||||||
*adr = ptr->next;
|
|
||||||
ptr = ptr->next;
|
|
||||||
cur->next = sFreeTimeoutList;
|
|
||||||
sFreeTimeoutList = cur;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
adr = &ptr->next;
|
|
||||||
ptr = ptr->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// New entry for the object
|
|
||||||
if (sFreeTimeoutList != NULL)
|
|
||||||
{
|
|
||||||
ptr = sFreeTimeoutList;
|
|
||||||
sFreeTimeoutList = ptr->next;
|
|
||||||
ptr->next = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ptr = sCollisionTimeoutChunker.alloc();
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr->object = obj;
|
|
||||||
ptr->objectNumber = obj->getId();
|
|
||||||
ptr->vector = vec;
|
|
||||||
ptr->expireTime = time + CollisionTimeoutValue;
|
|
||||||
ptr->next = mTimeoutList;
|
|
||||||
|
|
||||||
mTimeoutList = ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CollisionInterface::checkEarlyOut(Point3F start, VectorF velocity, F32 time, Box3F objectBox, Point3F objectScale,
|
|
||||||
Box3F collisionBox, U32 collisionMask, CollisionWorkingList &colWorkingList)
|
|
||||||
{
|
|
||||||
Point3F end = start + velocity * time;
|
|
||||||
Point3F distance = end - start;
|
|
||||||
|
|
||||||
Box3F scaledBox = objectBox;
|
|
||||||
scaledBox.minExtents.convolve(objectScale);
|
|
||||||
scaledBox.maxExtents.convolve(objectScale);
|
|
||||||
|
|
||||||
if (mFabs(distance.x) < objectBox.len_x() &&
|
|
||||||
mFabs(distance.y) < objectBox.len_y() &&
|
|
||||||
mFabs(distance.z) < objectBox.len_z())
|
|
||||||
{
|
|
||||||
// We can potentially early out of this. If there are no polys in the clipped polylist at our
|
|
||||||
// end position, then we can bail, and just set start = end;
|
|
||||||
Box3F wBox = scaledBox;
|
|
||||||
wBox.minExtents += end;
|
|
||||||
wBox.maxExtents += end;
|
|
||||||
|
|
||||||
static EarlyOutPolyList eaPolyList;
|
|
||||||
eaPolyList.clear();
|
|
||||||
eaPolyList.mNormal.set(0.0f, 0.0f, 0.0f);
|
|
||||||
eaPolyList.mPlaneList.clear();
|
|
||||||
eaPolyList.mPlaneList.setSize(6);
|
|
||||||
eaPolyList.mPlaneList[0].set(wBox.minExtents,VectorF(-1.0f, 0.0f, 0.0f));
|
|
||||||
eaPolyList.mPlaneList[1].set(wBox.maxExtents,VectorF(0.0f, 1.0f, 0.0f));
|
|
||||||
eaPolyList.mPlaneList[2].set(wBox.maxExtents,VectorF(1.0f, 0.0f, 0.0f));
|
|
||||||
eaPolyList.mPlaneList[3].set(wBox.minExtents,VectorF(0.0f, -1.0f, 0.0f));
|
|
||||||
eaPolyList.mPlaneList[4].set(wBox.minExtents,VectorF(0.0f, 0.0f, -1.0f));
|
|
||||||
eaPolyList.mPlaneList[5].set(wBox.maxExtents,VectorF(0.0f, 0.0f, 1.0f));
|
|
||||||
|
|
||||||
// Build list from convex states here...
|
|
||||||
CollisionWorkingList& rList = colWorkingList;
|
|
||||||
CollisionWorkingList* pList = rList.wLink.mNext;
|
|
||||||
while (pList != &rList)
|
|
||||||
{
|
|
||||||
Convex* pConvex = pList->mConvex;
|
|
||||||
|
|
||||||
if (pConvex->getObject()->getTypeMask() & collisionMask)
|
|
||||||
{
|
|
||||||
Box3F convexBox = pConvex->getBoundingBox();
|
|
||||||
|
|
||||||
if (wBox.isOverlapped(convexBox))
|
|
||||||
{
|
|
||||||
// No need to separate out the physical zones here, we want those
|
|
||||||
// to cause a fallthrough as well...
|
|
||||||
pConvex->getPolyList(&eaPolyList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pList = pList->wLink.mNext;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eaPolyList.isEmpty())
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Collision* CollisionInterface::getCollision(S32 col)
|
|
||||||
{
|
|
||||||
if(col < mCollisionList.getCount() && col >= 0)
|
|
||||||
return &mCollisionList[col];
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
@ -1,167 +0,0 @@
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Copyright (c) 2012 GarageGames, LLC
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to
|
|
||||||
// deal in the Software without restriction, including without limitation the
|
|
||||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
||||||
// sell copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
||||||
// IN THE SOFTWARE.
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#ifndef COLLISION_INTERFACES_H
|
|
||||||
#define COLLISION_INTERFACES_H
|
|
||||||
|
|
||||||
#ifndef _CONVEX_H_
|
|
||||||
#include "collision/convex.h"
|
|
||||||
#endif
|
|
||||||
#ifndef _COLLISION_H_
|
|
||||||
#include "collision/collision.h"
|
|
||||||
#endif
|
|
||||||
#ifndef _EARLYOUTPOLYLIST_H_
|
|
||||||
#include "collision/earlyOutPolyList.h"
|
|
||||||
#endif
|
|
||||||
#ifndef _SIM_H_
|
|
||||||
#include "console/sim.h"
|
|
||||||
#endif
|
|
||||||
#ifndef _SCENECONTAINER_H_
|
|
||||||
#include "scene/sceneContainer.h"
|
|
||||||
#endif
|
|
||||||
#ifndef _T3D_PHYSICSCOMMON_H_
|
|
||||||
#include "T3D/physics/physicsCommon.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct ContactInfo
|
|
||||||
{
|
|
||||||
bool contacted, move;
|
|
||||||
SceneObject *contactObject;
|
|
||||||
VectorF idealContactNormal;
|
|
||||||
VectorF contactNormal;
|
|
||||||
Point3F contactPoint;
|
|
||||||
F32 contactTime;
|
|
||||||
S32 contactTimer;
|
|
||||||
BaseMatInstance *contactMaterial;
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
contacted=move=false;
|
|
||||||
contactObject = NULL;
|
|
||||||
contactNormal.set(0,0,0);
|
|
||||||
contactTime = 0.f;
|
|
||||||
contactTimer = 0;
|
|
||||||
idealContactNormal.set(0, 0, 1);
|
|
||||||
contactMaterial = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ContactInfo() { clear(); }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class CollisionInterface// : public Interface<CollisionInterface>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// CollisionTimeout
|
|
||||||
// This struct lets us track our collisions and estimate when they've have timed out and we'll need to act on it.
|
|
||||||
struct CollisionTimeout
|
|
||||||
{
|
|
||||||
CollisionTimeout* next;
|
|
||||||
SceneObject* object;
|
|
||||||
U32 objectNumber;
|
|
||||||
SimTime expireTime;
|
|
||||||
VectorF vector;
|
|
||||||
};
|
|
||||||
|
|
||||||
Signal< void( SceneObject* ) > onCollisionSignal;
|
|
||||||
Signal< void( SceneObject* ) > onContactSignal;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
CollisionTimeout* mTimeoutList;
|
|
||||||
static CollisionTimeout* sFreeTimeoutList;
|
|
||||||
|
|
||||||
CollisionList mCollisionList;
|
|
||||||
Vector<CollisionInterface*> mCollisionNotifyList;
|
|
||||||
|
|
||||||
ContactInfo mContactInfo;
|
|
||||||
|
|
||||||
Box3F mWorkingQueryBox;
|
|
||||||
|
|
||||||
U32 CollisionMoveMask;
|
|
||||||
|
|
||||||
Convex *mConvexList;
|
|
||||||
|
|
||||||
bool mBlockColliding;
|
|
||||||
|
|
||||||
void handleCollisionNotifyList();
|
|
||||||
|
|
||||||
void queueCollision( SceneObject *obj, const VectorF &vec);
|
|
||||||
|
|
||||||
/// checkEarlyOut
|
|
||||||
/// This function lets you trying and early out of any expensive collision checks by using simple extruded poly boxes representing our objects
|
|
||||||
/// If it returns true, we know we won't hit with the given parameters and can successfully early out. If it returns false, our test case collided
|
|
||||||
/// and we should do the full collision sim.
|
|
||||||
bool checkEarlyOut(Point3F start, VectorF velocity, F32 time, Box3F objectBox, Point3F objectScale,
|
|
||||||
Box3F collisionBox, U32 collisionMask, CollisionWorkingList &colWorkingList);
|
|
||||||
|
|
||||||
public:
|
|
||||||
/// checkCollisions
|
|
||||||
// This is our main function for checking if a collision is happening based on the start point, velocity and time
|
|
||||||
// We do the bulk of the collision checking in here
|
|
||||||
//virtual bool checkCollisions( const F32 travelTime, Point3F *velocity, Point3F start )=0;
|
|
||||||
|
|
||||||
CollisionList *getCollisionList() { return &mCollisionList; }
|
|
||||||
|
|
||||||
void clearCollisionList() { mCollisionList.clear(); }
|
|
||||||
|
|
||||||
void clearCollisionNotifyList() { mCollisionNotifyList.clear(); }
|
|
||||||
|
|
||||||
Collision *getCollision(S32 col);
|
|
||||||
|
|
||||||
ContactInfo* getContactInfo() { return &mContactInfo; }
|
|
||||||
|
|
||||||
Convex *getConvexList() { return mConvexList; }
|
|
||||||
|
|
||||||
virtual bool buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F &box, const SphereF &sphere) = 0;
|
|
||||||
|
|
||||||
enum PublicConstants {
|
|
||||||
CollisionTimeoutValue = 250
|
|
||||||
};
|
|
||||||
|
|
||||||
bool doesBlockColliding() { return mBlockColliding; }
|
|
||||||
|
|
||||||
/// handleCollisionList
|
|
||||||
/// This basically takes in a CollisionList and calls handleCollision for each.
|
|
||||||
void handleCollisionList(CollisionList &collisionList, VectorF velocity);
|
|
||||||
|
|
||||||
/// handleCollision
|
|
||||||
/// This will take a collision and queue the collision info for the object so that in knows about the collision.
|
|
||||||
void handleCollision(Collision &col, VectorF velocity);
|
|
||||||
|
|
||||||
virtual PhysicsCollision* getCollisionData() = 0;
|
|
||||||
|
|
||||||
Signal< void(PhysicsCollision* collision) > onCollisionChanged;
|
|
||||||
};
|
|
||||||
|
|
||||||
class BuildConvexInterface //: public Interface<CollisionInterface>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual void buildConvex(const Box3F& box, Convex* convex)=0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class BuildPolyListInterface// : public Interface<CollisionInterface>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual bool buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F &box, const SphereF &sphere) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -480,7 +480,7 @@ void CollisionTrigger::processTick(const Move* move)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mTickCommand.isEmpty())
|
if (!mTickCommand.isEmpty() && mObjects.size() != 0)
|
||||||
Con::evaluate(mTickCommand.c_str());
|
Con::evaluate(mTickCommand.c_str());
|
||||||
|
|
||||||
//if (mObjects.size() != 0)
|
//if (mObjects.size() != 0)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,122 @@
|
||||||
|
#include "T3D/components/collision/raycastColliderComponent.h"
|
||||||
|
#include "T3D/physics/physicsPlugin.h"
|
||||||
|
|
||||||
|
IMPLEMENT_CO_DATABLOCK_V1(RaycastColliderComponent);
|
||||||
|
|
||||||
|
RaycastColliderComponent::RaycastColliderComponent() :
|
||||||
|
mUseVelocity(false),
|
||||||
|
mOwnerPhysicsComponent(nullptr),
|
||||||
|
mRayDirection(VectorF::Zero),
|
||||||
|
mRayLength(1),
|
||||||
|
mPhysicsWorld(nullptr),
|
||||||
|
mOldPosition(Point3F::Zero),
|
||||||
|
mMask(-1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RaycastColliderComponent::~RaycastColliderComponent()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RaycastColliderComponent::onAdd()
|
||||||
|
{
|
||||||
|
if (!Parent::onAdd())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (PHYSICSMGR)
|
||||||
|
mPhysicsWorld = PHYSICSMGR->getWorld(isServerObject() ? "server" : "client");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void RaycastColliderComponent::onRemove()
|
||||||
|
{
|
||||||
|
Parent::onRemove();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RaycastColliderComponent::initPersistFields()
|
||||||
|
{
|
||||||
|
Parent::initPersistFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RaycastColliderComponent::onComponentAdd()
|
||||||
|
{
|
||||||
|
PhysicsComponent* physComp = mOwner->getComponent<PhysicsComponent>();
|
||||||
|
|
||||||
|
if (physComp)
|
||||||
|
{
|
||||||
|
mOwnerPhysicsComponent = physComp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RaycastColliderComponent::onComponentRemove()
|
||||||
|
{
|
||||||
|
mOwnerPhysicsComponent = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RaycastColliderComponent::componentAddedToOwner(Component *comp)
|
||||||
|
{
|
||||||
|
Parent::componentAddedToOwner(comp);
|
||||||
|
|
||||||
|
PhysicsComponent* physComp = dynamic_cast<PhysicsComponent*>(comp);
|
||||||
|
if (physComp)
|
||||||
|
{
|
||||||
|
mOwnerPhysicsComponent = physComp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RaycastColliderComponent::componentRemovedFromOwner(Component *comp)
|
||||||
|
{
|
||||||
|
Parent::componentRemovedFromOwner(comp);
|
||||||
|
|
||||||
|
if (mOwnerPhysicsComponent != nullptr && mOwnerPhysicsComponent->getId() == comp->getId())
|
||||||
|
{
|
||||||
|
mOwnerPhysicsComponent = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RaycastColliderComponent::processTick()
|
||||||
|
{
|
||||||
|
Parent::processTick();
|
||||||
|
|
||||||
|
// Raycast the abstract PhysicsWorld if a PhysicsPlugin exists.
|
||||||
|
bool hit = false;
|
||||||
|
|
||||||
|
Point3F start = mOldPosition;
|
||||||
|
Point3F end;
|
||||||
|
|
||||||
|
if (mUseVelocity)
|
||||||
|
{
|
||||||
|
//our end is the new position
|
||||||
|
end = mOwner->getPosition();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
end = start + (mRayDirection * mRayLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
RayInfo rInfo;
|
||||||
|
|
||||||
|
if (mPhysicsWorld)
|
||||||
|
hit = mPhysicsWorld->castRay(start, end, &rInfo, Point3F::Zero);
|
||||||
|
else
|
||||||
|
hit = mOwner->getContainer()->castRay(start, end, mMask, &rInfo);
|
||||||
|
|
||||||
|
if (hit)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mUseVelocity)
|
||||||
|
mOldPosition = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RaycastColliderComponent::interpolateTick(F32 dt)
|
||||||
|
{
|
||||||
|
Parent::interpolateTick(dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RaycastColliderComponent::advanceTime(F32 dt)
|
||||||
|
{
|
||||||
|
Parent::advanceTime(dt);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "T3D/components/collision/collisionComponent.h"
|
||||||
|
#include "T3D/components/physics/physicsComponent.h"
|
||||||
|
#include "T3D/physics/physicsWorld.h"
|
||||||
|
|
||||||
|
class RaycastColliderComponent : public CollisionComponent
|
||||||
|
{
|
||||||
|
typedef CollisionComponent Parent;
|
||||||
|
|
||||||
|
//If we're velocity based, we need a physics component on our owner to calculate the vel
|
||||||
|
bool mUseVelocity;
|
||||||
|
PhysicsComponent* mOwnerPhysicsComponent;
|
||||||
|
|
||||||
|
//If we're not using velocity, we'll just have a set direction and length we check against
|
||||||
|
VectorF mRayDirection;
|
||||||
|
F32 mRayLength;
|
||||||
|
|
||||||
|
PhysicsWorld *mPhysicsWorld;
|
||||||
|
|
||||||
|
Point3F mOldPosition;
|
||||||
|
|
||||||
|
U32 mMask;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DECLARE_CONOBJECT(RaycastColliderComponent);
|
||||||
|
|
||||||
|
RaycastColliderComponent();
|
||||||
|
~RaycastColliderComponent();
|
||||||
|
|
||||||
|
virtual bool onAdd();
|
||||||
|
virtual void onRemove();
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
virtual void onComponentAdd();
|
||||||
|
virtual void onComponentRemove();
|
||||||
|
|
||||||
|
//This is called when a different component is added to our owner entity
|
||||||
|
virtual void componentAddedToOwner(Component *comp);
|
||||||
|
//This is called when a different component is removed from our owner entity
|
||||||
|
virtual void componentRemovedFromOwner(Component *comp);
|
||||||
|
|
||||||
|
virtual void processTick();
|
||||||
|
virtual void interpolateTick(F32 dt);
|
||||||
|
virtual void advanceTime(F32 dt);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,607 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2012 GarageGames, LLC
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "T3D/components/collision/shapeCollisionComponent.h"
|
||||||
|
#include "T3D/components/collision/shapeCollisionComponent_ScriptBinding.h"
|
||||||
|
#include "T3D/components/physics/physicsComponent.h"
|
||||||
|
#include "console/consoleTypes.h"
|
||||||
|
#include "core/util/safeDelete.h"
|
||||||
|
#include "core/resourceManager.h"
|
||||||
|
#include "console/consoleTypes.h"
|
||||||
|
#include "console/consoleObject.h"
|
||||||
|
#include "core/stream/bitStream.h"
|
||||||
|
#include "scene/sceneRenderState.h"
|
||||||
|
#include "gfx/gfxTransformSaver.h"
|
||||||
|
#include "gfx/gfxDrawUtil.h"
|
||||||
|
#include "console/engineAPI.h"
|
||||||
|
#include "T3D/physics/physicsPlugin.h"
|
||||||
|
#include "T3D/physics/physicsBody.h"
|
||||||
|
#include "T3D/physics/physicsCollision.h"
|
||||||
|
#include "T3D/gameBase/gameConnection.h"
|
||||||
|
#include "collision/extrudedPolyList.h"
|
||||||
|
#include "math/mathIO.h"
|
||||||
|
#include "gfx/sim/debugDraw.h"
|
||||||
|
#include "collision/concretePolyList.h"
|
||||||
|
|
||||||
|
#include "T3D/trigger.h"
|
||||||
|
#include "opcode/Opcode.h"
|
||||||
|
#include "opcode/Ice/IceAABB.h"
|
||||||
|
#include "opcode/Ice/IcePoint.h"
|
||||||
|
#include "opcode/OPC_AABBTree.h"
|
||||||
|
#include "opcode/OPC_AABBCollider.h"
|
||||||
|
|
||||||
|
#include "math/mathUtils.h"
|
||||||
|
#include "materials/baseMatInstance.h"
|
||||||
|
#include "collision/vertexPolyList.h"
|
||||||
|
|
||||||
|
extern bool gEditingMission;
|
||||||
|
|
||||||
|
static bool sRenderColliders = false;
|
||||||
|
|
||||||
|
//Docs
|
||||||
|
ConsoleDocClass(ShapeCollisionComponent,
|
||||||
|
"@brief The Box Collider component uses a box or rectangular convex shape for collisions.\n\n"
|
||||||
|
|
||||||
|
"Colliders are individualized components that are similarly based off the CollisionInterface core.\n"
|
||||||
|
"They are basically the entire functionality of how Torque handles collisions compacted into a single component.\n"
|
||||||
|
"A collider will both collide against and be collided with, other entities.\n"
|
||||||
|
"Individual colliders will offer different shapes. This box collider will generate a box/rectangle convex, \n"
|
||||||
|
"while the mesh collider will take the owner Entity's rendered shape and do polysoup collision on it, etc.\n\n"
|
||||||
|
|
||||||
|
"The general flow of operations for how collisions happen is thus:\n"
|
||||||
|
" -When the component is added(or updated) prepCollision() is called.\n"
|
||||||
|
" This will set up our initial convex shape for usage later.\n\n"
|
||||||
|
|
||||||
|
" -When we update via processTick(), we first test if our entity owner is mobile.\n"
|
||||||
|
" If our owner isn't mobile(as in, they have no components that provide it a velocity to move)\n"
|
||||||
|
" then we skip doing our active collision checks. Collisions are checked by the things moving, as\n"
|
||||||
|
" opposed to being reactionary. If we're moving, we call updateWorkingCollisionSet().\n"
|
||||||
|
" updateWorkingCollisionSet() estimates our bounding space for our current ticket based on our position and velocity.\n"
|
||||||
|
" If our bounding space has changed since the last tick, we proceed to call updateWorkingList() on our convex.\n"
|
||||||
|
" This notifies any object in the bounding space that they may be collided with, so they will call buildConvex().\n"
|
||||||
|
" buildConvex() will set up our ConvexList with our collision convex info.\n\n"
|
||||||
|
|
||||||
|
" -When the component that is actually causing our movement, such as SimplePhysicsBehavior, updates, it will check collisions.\n"
|
||||||
|
" It will call checkCollisions() on us. checkCollisions() will first build a bounding shape for our convex, and test\n"
|
||||||
|
" if we can early out because we won't hit anything based on our starting point, velocity, and tick time.\n"
|
||||||
|
" If we don't early out, we proceed to call updateCollisions(). This builds an ExtrudePolyList, which is then extruded\n"
|
||||||
|
" based on our velocity. We then test our extruded polies on our working list of objects we build\n"
|
||||||
|
" up earlier via updateWorkingCollisionSet. Any collisions that happen here will be added to our mCollisionList.\n"
|
||||||
|
" Finally, we call handleCollisionList() on our collisionList, which then queues out the colliison notice\n"
|
||||||
|
" to the object(s) we collided with so they can do callbacks and the like. We also report back on if we did collide\n"
|
||||||
|
" to the physics component via our bool return in checkCollisions() so it can make the physics react accordingly.\n\n"
|
||||||
|
|
||||||
|
"One interesting point to note is the usage of mBlockColliding.\n"
|
||||||
|
"This is set so that it dictates the return on checkCollisions(). If set to false, it will ensure checkCollisions()\n"
|
||||||
|
"will return false, regardless if we actually collided. This is useful, because even if checkCollisions() returns false,\n"
|
||||||
|
"we still handle the collisions so the callbacks happen. This enables us to apply a collider to an object that doesn't block\n"
|
||||||
|
"objects, but does have callbacks, so it can act as a trigger, allowing for arbitrarily shaped triggers, as any collider can\n"
|
||||||
|
"act as a trigger volume(including MeshCollider).\n\n"
|
||||||
|
|
||||||
|
"@tsexample\n"
|
||||||
|
"new ShapeCollisionComponentInstance()\n"
|
||||||
|
"{\n"
|
||||||
|
" template = ShapeCollisionComponentTemplate;\n"
|
||||||
|
" colliderSize = \"1 1 2\";\n"
|
||||||
|
" blockColldingObject = \"1\";\n"
|
||||||
|
"};\n"
|
||||||
|
"@endtsexample\n"
|
||||||
|
|
||||||
|
"@see SimplePhysicsBehavior\n"
|
||||||
|
"@ingroup Collision\n"
|
||||||
|
"@ingroup Components\n"
|
||||||
|
);
|
||||||
|
//Docs
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
ImplementEnumType(CollisionMeshMeshType,
|
||||||
|
"Type of mesh data available in a shape.\n"
|
||||||
|
"@ingroup gameObjects")
|
||||||
|
{ ShapeCollisionComponent::None, "None", "No mesh data." },
|
||||||
|
{ ShapeCollisionComponent::Bounds, "Bounds", "Bounding box of the shape." },
|
||||||
|
{ ShapeCollisionComponent::CollisionMesh, "Collision Mesh", "Specifically desingated \"collision\" meshes." },
|
||||||
|
{ ShapeCollisionComponent::VisibleMesh, "Visible Mesh", "Rendered mesh polygons." },
|
||||||
|
EndImplementEnumType;
|
||||||
|
|
||||||
|
//
|
||||||
|
ShapeCollisionComponent::ShapeCollisionComponent() : CollisionComponent()
|
||||||
|
{
|
||||||
|
mFriendlyName = "Shape Collision Component";
|
||||||
|
|
||||||
|
mFriendlyName = "Shape Collision";
|
||||||
|
mComponentType = "Collision";
|
||||||
|
|
||||||
|
mDescription = getDescriptionText("A stub component class that physics components should inherit from.");
|
||||||
|
|
||||||
|
mOwnerRenderInterface = NULL;
|
||||||
|
mOwnerPhysicsComp = NULL;
|
||||||
|
|
||||||
|
mBlockColliding = true;
|
||||||
|
|
||||||
|
mCollisionType = CollisionMesh;
|
||||||
|
mLOSType = CollisionMesh;
|
||||||
|
mDecalType = CollisionMesh;
|
||||||
|
|
||||||
|
colisionMeshPrefix = StringTable->insert("Collision");
|
||||||
|
|
||||||
|
CollisionMoveMask = (TerrainObjectType | PlayerObjectType |
|
||||||
|
StaticShapeObjectType | VehicleObjectType |
|
||||||
|
VehicleBlockerObjectType | DynamicShapeObjectType | StaticObjectType | EntityObjectType | TriggerObjectType);
|
||||||
|
|
||||||
|
mAnimated = false;
|
||||||
|
|
||||||
|
mCollisionInited = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShapeCollisionComponent::~ShapeCollisionComponent()
|
||||||
|
{
|
||||||
|
for (S32 i = 0; i < mFields.size(); ++i)
|
||||||
|
{
|
||||||
|
ComponentField &field = mFields[i];
|
||||||
|
SAFE_DELETE_ARRAY(field.mFieldDescription);
|
||||||
|
}
|
||||||
|
|
||||||
|
SAFE_DELETE_ARRAY(mDescription);
|
||||||
|
}
|
||||||
|
|
||||||
|
IMPLEMENT_CONOBJECT(ShapeCollisionComponent);
|
||||||
|
|
||||||
|
void ShapeCollisionComponent::onComponentAdd()
|
||||||
|
{
|
||||||
|
Parent::onComponentAdd();
|
||||||
|
|
||||||
|
RenderComponentInterface *renderInterface = mOwner->getComponent<RenderComponentInterface>();
|
||||||
|
if (renderInterface)
|
||||||
|
{
|
||||||
|
renderInterface->onShapeInstanceChanged.notify(this, &ShapeCollisionComponent::targetShapeChanged);
|
||||||
|
mOwnerRenderInterface = renderInterface;
|
||||||
|
}
|
||||||
|
|
||||||
|
//physicsInterface
|
||||||
|
PhysicsComponent *physicsComp = mOwner->getComponent<PhysicsComponent>();
|
||||||
|
if (physicsComp)
|
||||||
|
{
|
||||||
|
mOwnerPhysicsComp = physicsComp;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (PHYSICSMGR)
|
||||||
|
{
|
||||||
|
mPhysicsRep = PHYSICSMGR->createBody();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prepCollision();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShapeCollisionComponent::onComponentRemove()
|
||||||
|
{
|
||||||
|
SAFE_DELETE(mPhysicsRep);
|
||||||
|
|
||||||
|
mOwnerPhysicsComp = nullptr;
|
||||||
|
|
||||||
|
mCollisionInited = false;
|
||||||
|
|
||||||
|
Parent::onComponentRemove();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShapeCollisionComponent::componentAddedToOwner(Component *comp)
|
||||||
|
{
|
||||||
|
if (comp->getId() == getId())
|
||||||
|
return;
|
||||||
|
|
||||||
|
//test if this is a shape component!
|
||||||
|
RenderComponentInterface *renderInterface = dynamic_cast<RenderComponentInterface*>(comp);
|
||||||
|
if (renderInterface)
|
||||||
|
{
|
||||||
|
renderInterface->onShapeInstanceChanged.notify(this, &ShapeCollisionComponent::targetShapeChanged);
|
||||||
|
mOwnerRenderInterface = renderInterface;
|
||||||
|
prepCollision();
|
||||||
|
}
|
||||||
|
|
||||||
|
PhysicsComponent *physicsComp = dynamic_cast<PhysicsComponent*>(comp);
|
||||||
|
if (physicsComp)
|
||||||
|
{
|
||||||
|
if (mPhysicsRep)
|
||||||
|
SAFE_DELETE(mPhysicsRep);
|
||||||
|
|
||||||
|
mOwnerPhysicsComp = physicsComp;
|
||||||
|
|
||||||
|
prepCollision();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShapeCollisionComponent::componentRemovedFromOwner(Component *comp)
|
||||||
|
{
|
||||||
|
if (comp->getId() == getId()) //?????????
|
||||||
|
return;
|
||||||
|
|
||||||
|
//test if this is a shape component!
|
||||||
|
RenderComponentInterface *renderInterface = dynamic_cast<RenderComponentInterface*>(comp);
|
||||||
|
if (renderInterface)
|
||||||
|
{
|
||||||
|
renderInterface->onShapeInstanceChanged.remove(this, &ShapeCollisionComponent::targetShapeChanged);
|
||||||
|
mOwnerRenderInterface = NULL;
|
||||||
|
prepCollision();
|
||||||
|
}
|
||||||
|
|
||||||
|
//physicsInterface
|
||||||
|
PhysicsComponent *physicsComp = dynamic_cast<PhysicsComponent*>(comp);
|
||||||
|
if (physicsComp)
|
||||||
|
{
|
||||||
|
mPhysicsRep = PHYSICSMGR->createBody();
|
||||||
|
|
||||||
|
mCollisionInited = false;
|
||||||
|
|
||||||
|
mOwnerPhysicsComp = nullptr;
|
||||||
|
|
||||||
|
prepCollision();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShapeCollisionComponent::checkDependencies()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShapeCollisionComponent::initPersistFields()
|
||||||
|
{
|
||||||
|
Parent::initPersistFields();
|
||||||
|
|
||||||
|
addGroup("Collision");
|
||||||
|
|
||||||
|
addField("CollisionType", TypeCollisionMeshMeshType, Offset(mCollisionType, ShapeCollisionComponent),
|
||||||
|
"The type of mesh data to use for collision queries.");
|
||||||
|
|
||||||
|
addField("LineOfSightType", TypeCollisionMeshMeshType, Offset(mLOSType, ShapeCollisionComponent),
|
||||||
|
"The type of mesh data to use for collision queries.");
|
||||||
|
|
||||||
|
addField("DecalType", TypeCollisionMeshMeshType, Offset(mDecalType, ShapeCollisionComponent),
|
||||||
|
"The type of mesh data to use for collision queries.");
|
||||||
|
|
||||||
|
addField("CollisionMeshPrefix", TypeString, Offset(colisionMeshPrefix, ShapeCollisionComponent),
|
||||||
|
"The type of mesh data to use for collision queries.");
|
||||||
|
|
||||||
|
addField("BlockCollisions", TypeBool, Offset(mBlockColliding, ShapeCollisionComponent), "");
|
||||||
|
|
||||||
|
endGroup("Collision");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShapeCollisionComponent::inspectPostApply()
|
||||||
|
{
|
||||||
|
// Apply any transformations set in the editor
|
||||||
|
Parent::inspectPostApply();
|
||||||
|
|
||||||
|
if (isServerObject())
|
||||||
|
{
|
||||||
|
setMaskBits(ColliderMask);
|
||||||
|
prepCollision();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
U32 ShapeCollisionComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
|
||||||
|
{
|
||||||
|
U32 retMask = Parent::packUpdate(con, mask, stream);
|
||||||
|
|
||||||
|
if (stream->writeFlag(mask & (ColliderMask | InitialUpdateMask)))
|
||||||
|
{
|
||||||
|
stream->write((U32)mCollisionType);
|
||||||
|
stream->writeString(colisionMeshPrefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
return retMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShapeCollisionComponent::unpackUpdate(NetConnection *con, BitStream *stream)
|
||||||
|
{
|
||||||
|
Parent::unpackUpdate(con, stream);
|
||||||
|
|
||||||
|
if (stream->readFlag()) // UpdateMask
|
||||||
|
{
|
||||||
|
U32 collisionType = CollisionMesh;
|
||||||
|
|
||||||
|
stream->read(&collisionType);
|
||||||
|
|
||||||
|
// Handle it if we have changed CollisionType's
|
||||||
|
if ((MeshType)collisionType != mCollisionType)
|
||||||
|
{
|
||||||
|
mCollisionType = (MeshType)collisionType;
|
||||||
|
|
||||||
|
prepCollision();
|
||||||
|
}
|
||||||
|
|
||||||
|
char readBuffer[1024];
|
||||||
|
|
||||||
|
stream->readString(readBuffer);
|
||||||
|
colisionMeshPrefix = StringTable->insert(readBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShapeCollisionComponent::ownerTransformSet(MatrixF *mat)
|
||||||
|
{
|
||||||
|
/*bool isSrv = isServerObject();
|
||||||
|
if (mPhysicsRep && mCollisionInited)
|
||||||
|
mPhysicsRep->setTransform(mOwner->getTransform());*/
|
||||||
|
}
|
||||||
|
|
||||||
|
//Setup
|
||||||
|
void ShapeCollisionComponent::targetShapeChanged(RenderComponentInterface* instanceInterface)
|
||||||
|
{
|
||||||
|
prepCollision();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShapeCollisionComponent::prepCollision()
|
||||||
|
{
|
||||||
|
if (!mOwner)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Let the client know that the collision was updated
|
||||||
|
setMaskBits(ColliderMask);
|
||||||
|
|
||||||
|
mOwner->disableCollision();
|
||||||
|
|
||||||
|
if (mCollisionType == None)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//Physics API
|
||||||
|
PhysicsCollision *colShape = NULL;
|
||||||
|
|
||||||
|
if (mCollisionType == Bounds)
|
||||||
|
{
|
||||||
|
MatrixF offset(true);
|
||||||
|
|
||||||
|
if (mOwnerRenderInterface && mOwnerRenderInterface->getShape())
|
||||||
|
offset.setPosition(mOwnerRenderInterface->getShape()->center);
|
||||||
|
|
||||||
|
colShape = PHYSICSMGR->createCollision();
|
||||||
|
colShape->addBox(mOwner->getObjBox().getExtents() * 0.5f * mOwner->getScale(), offset);
|
||||||
|
}
|
||||||
|
else if (mCollisionType == CollisionMesh || (mCollisionType == VisibleMesh /*&& !mOwner->getComponent<AnimatedMesh>()*/))
|
||||||
|
{
|
||||||
|
colShape = buildColShapes();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (colShape)
|
||||||
|
{
|
||||||
|
mPhysicsWorld = PHYSICSMGR->getWorld(isServerObject() ? "server" : "client");
|
||||||
|
|
||||||
|
if (mPhysicsRep)
|
||||||
|
{
|
||||||
|
if (mBlockColliding)
|
||||||
|
mPhysicsRep->init(colShape, 0, 0, mOwner, mPhysicsWorld);
|
||||||
|
else
|
||||||
|
mPhysicsRep->init(colShape, 0, PhysicsBody::BF_TRIGGER, mOwner, mPhysicsWorld);
|
||||||
|
|
||||||
|
mPhysicsRep->setTransform(mOwner->getTransform());
|
||||||
|
|
||||||
|
mCollisionInited = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mOwner->enableCollision();
|
||||||
|
|
||||||
|
onCollisionChanged.trigger(colShape);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Update
|
||||||
|
void ShapeCollisionComponent::processTick()
|
||||||
|
{
|
||||||
|
if (!isActive())
|
||||||
|
return;
|
||||||
|
|
||||||
|
//callback if we have a persisting contact
|
||||||
|
if (mContactInfo.contactObject)
|
||||||
|
{
|
||||||
|
if (mContactInfo.contactTimer > 0)
|
||||||
|
{
|
||||||
|
if (isMethod("updateContact"))
|
||||||
|
Con::executef(this, "updateContact");
|
||||||
|
|
||||||
|
if (mOwner->isMethod("updateContact"))
|
||||||
|
Con::executef(mOwner, "updateContact");
|
||||||
|
}
|
||||||
|
|
||||||
|
++mContactInfo.contactTimer;
|
||||||
|
}
|
||||||
|
else if (mContactInfo.contactTimer != 0)
|
||||||
|
mContactInfo.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShapeCollisionComponent::updatePhysics()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
PhysicsCollision* ShapeCollisionComponent::getCollisionData()
|
||||||
|
{
|
||||||
|
if ((!PHYSICSMGR || mCollisionType == None) || mOwnerRenderInterface == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
PhysicsCollision *colShape = NULL;
|
||||||
|
if (mCollisionType == Bounds)
|
||||||
|
{
|
||||||
|
MatrixF offset(true);
|
||||||
|
offset.setPosition(mOwnerRenderInterface->getShape()->center);
|
||||||
|
colShape = PHYSICSMGR->createCollision();
|
||||||
|
colShape->addBox(mOwner->getObjBox().getExtents() * 0.5f * mOwner->getScale(), offset);
|
||||||
|
}
|
||||||
|
else if (mCollisionType == CollisionMesh || (mCollisionType == VisibleMesh/* && !mOwner->getComponent<AnimatedMesh>()*/))
|
||||||
|
{
|
||||||
|
colShape = buildColShapes();
|
||||||
|
//colShape = mOwnerShapeInstance->getShape()->buildColShape(mCollisionType == VisibleMesh, mOwner->getScale());
|
||||||
|
}
|
||||||
|
/*else if (mCollisionType == VisibleMesh && !mOwner->getComponent<AnimatedMesh>())
|
||||||
|
{
|
||||||
|
//We don't have support for visible mesh collisions with animated meshes currently in the physics abstraction layer
|
||||||
|
//so we don't generate anything if we're set to use a visible mesh but have an animated mesh component.
|
||||||
|
colShape = mOwnerShapeInstance->getShape()->buildColShape(mCollisionType == VisibleMesh, mOwner->getScale());
|
||||||
|
}*/
|
||||||
|
else if (mCollisionType == VisibleMesh/* && mOwner->getComponent<AnimatedMesh>()*/)
|
||||||
|
{
|
||||||
|
Con::printf("ShapeCollisionComponent::updatePhysics: Cannot use visible mesh collisions with an animated mesh!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return colShape;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShapeCollisionComponent::castRay(const Point3F &start, const Point3F &end, RayInfo* info)
|
||||||
|
{
|
||||||
|
if (!mCollisionType == None)
|
||||||
|
{
|
||||||
|
if (mPhysicsWorld)
|
||||||
|
{
|
||||||
|
return mPhysicsWorld->castRay(start, end, info, Point3F::Zero);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PhysicsCollision* ShapeCollisionComponent::buildColShapes()
|
||||||
|
{
|
||||||
|
PROFILE_SCOPE(ShapeCollisionComponent_buildColShapes);
|
||||||
|
|
||||||
|
PhysicsCollision *colShape = NULL;
|
||||||
|
U32 surfaceKey = 0;
|
||||||
|
|
||||||
|
TSShape* shape = mOwnerRenderInterface->getShape();
|
||||||
|
|
||||||
|
if (shape == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (mCollisionType == VisibleMesh)
|
||||||
|
{
|
||||||
|
// Here we build triangle collision meshes from the
|
||||||
|
// visible detail levels.
|
||||||
|
|
||||||
|
// A negative subshape on the detail means we don't have geometry.
|
||||||
|
const TSShape::Detail &detail = shape->details[0];
|
||||||
|
if (detail.subShapeNum < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// We don't try to optimize the triangles we're given
|
||||||
|
// and assume the art was created properly for collision.
|
||||||
|
ConcretePolyList polyList;
|
||||||
|
polyList.setTransform(&MatrixF::Identity, mOwner->getScale());
|
||||||
|
|
||||||
|
// Create the collision meshes.
|
||||||
|
S32 start = shape->subShapeFirstObject[detail.subShapeNum];
|
||||||
|
S32 end = start + shape->subShapeNumObjects[detail.subShapeNum];
|
||||||
|
for (S32 o = start; o < end; o++)
|
||||||
|
{
|
||||||
|
const TSShape::Object &object = shape->objects[o];
|
||||||
|
if (detail.objectDetailNum >= object.numMeshes)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// No mesh or no verts.... nothing to do.
|
||||||
|
TSMesh *mesh = shape->meshes[object.startMeshIndex + detail.objectDetailNum];
|
||||||
|
if (!mesh || mesh->mNumVerts == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Gather the mesh triangles.
|
||||||
|
polyList.clear();
|
||||||
|
mesh->buildPolyList(0, &polyList, surfaceKey, NULL);
|
||||||
|
|
||||||
|
// Create the collision shape if we haven't already.
|
||||||
|
if (!colShape)
|
||||||
|
colShape = PHYSICSMGR->createCollision();
|
||||||
|
|
||||||
|
// Get the object space mesh transform.
|
||||||
|
MatrixF localXfm;
|
||||||
|
shape->getNodeWorldTransform(object.nodeIndex, &localXfm);
|
||||||
|
|
||||||
|
colShape->addTriangleMesh(polyList.mVertexList.address(),
|
||||||
|
polyList.mVertexList.size(),
|
||||||
|
polyList.mIndexList.address(),
|
||||||
|
polyList.mIndexList.size() / 3,
|
||||||
|
localXfm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return what we built... if anything.
|
||||||
|
return colShape;
|
||||||
|
}
|
||||||
|
else if (mCollisionType == CollisionMesh)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Scan out the collision hulls...
|
||||||
|
//
|
||||||
|
// TODO: We need to support LOS collision for physics.
|
||||||
|
//
|
||||||
|
for (U32 i = 0; i < shape->details.size(); i++)
|
||||||
|
{
|
||||||
|
const TSShape::Detail &detail = shape->details[i];
|
||||||
|
const String &name = shape->names[detail.nameIndex];
|
||||||
|
|
||||||
|
// Is this a valid collision detail.
|
||||||
|
if (!dStrStartsWith(name, colisionMeshPrefix) || detail.subShapeNum < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Now go thru the meshes for this detail.
|
||||||
|
S32 start = shape->subShapeFirstObject[detail.subShapeNum];
|
||||||
|
S32 end = start + shape->subShapeNumObjects[detail.subShapeNum];
|
||||||
|
if (start >= end)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (S32 o = start; o < end; o++)
|
||||||
|
{
|
||||||
|
const TSShape::Object &object = shape->objects[o];
|
||||||
|
const String &meshName = shape->names[object.nameIndex];
|
||||||
|
|
||||||
|
if (object.numMeshes <= detail.objectDetailNum)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// No mesh, a flat bounds, or no verts.... nothing to do.
|
||||||
|
TSMesh *mesh = shape->meshes[object.startMeshIndex + detail.objectDetailNum];
|
||||||
|
if (!mesh || mesh->getBounds().isEmpty() || mesh->mNumVerts == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// We need the default mesh transform.
|
||||||
|
MatrixF localXfm;
|
||||||
|
shape->getNodeWorldTransform(object.nodeIndex, &localXfm);
|
||||||
|
|
||||||
|
// We have some sort of collision shape... so allocate it.
|
||||||
|
if (!colShape)
|
||||||
|
colShape = PHYSICSMGR->createCollision();
|
||||||
|
|
||||||
|
// Any other mesh name we assume as a generic convex hull.
|
||||||
|
//
|
||||||
|
// Collect the verts using the vertex polylist which will
|
||||||
|
// filter out duplicates. This is importaint as the convex
|
||||||
|
// generators can sometimes fail with duplicate verts.
|
||||||
|
//
|
||||||
|
VertexPolyList polyList;
|
||||||
|
MatrixF meshMat(localXfm);
|
||||||
|
|
||||||
|
Point3F t = meshMat.getPosition();
|
||||||
|
t.convolve(mOwner->getScale());
|
||||||
|
meshMat.setPosition(t);
|
||||||
|
|
||||||
|
polyList.setTransform(&MatrixF::Identity, mOwner->getScale());
|
||||||
|
mesh->buildPolyList(0, &polyList, surfaceKey, NULL);
|
||||||
|
colShape->addConvex(polyList.getVertexList().address(),
|
||||||
|
polyList.getVertexList().size(),
|
||||||
|
meshMat);
|
||||||
|
} // objects
|
||||||
|
} // details
|
||||||
|
}
|
||||||
|
|
||||||
|
return colShape;
|
||||||
|
}
|
||||||
137
Engine/source/T3D/components/collision/shapeCollisionComponent.h
Normal file
137
Engine/source/T3D/components/collision/shapeCollisionComponent.h
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2012 GarageGames, LLC
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
#pragma once
|
||||||
|
#ifndef SHAPE_COLLISION_COMPONENT_H
|
||||||
|
#define SHAPE_COLLISION_COMPONENT_H
|
||||||
|
|
||||||
|
#ifndef __RESOURCE_H__
|
||||||
|
#include "core/resource.h"
|
||||||
|
#endif
|
||||||
|
#ifndef _TSSHAPE_H_
|
||||||
|
#include "ts/tsShape.h"
|
||||||
|
#endif
|
||||||
|
#ifndef _SCENERENDERSTATE_H_
|
||||||
|
#include "scene/sceneRenderState.h"
|
||||||
|
#endif
|
||||||
|
#ifndef _MBOX_H_
|
||||||
|
#include "math/mBox.h"
|
||||||
|
#endif
|
||||||
|
#ifndef ENTITY_H
|
||||||
|
#include "T3D/entity.h"
|
||||||
|
#endif
|
||||||
|
#ifndef CORE_INTERFACES_H
|
||||||
|
#include "T3D/components/coreInterfaces.h"
|
||||||
|
#endif
|
||||||
|
#ifndef COLLISION_COMPONENT_H
|
||||||
|
#include "T3D/components/collision/collisionComponent.h"
|
||||||
|
#endif
|
||||||
|
#ifndef RENDER_COMPONENT_INTERFACE_H
|
||||||
|
#include "T3D/components/render/renderComponentInterface.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class TSShapeInstance;
|
||||||
|
class SceneRenderState;
|
||||||
|
class ShapeCollisionComponent;
|
||||||
|
class PhysicsBody;
|
||||||
|
class PhysicsWorld;
|
||||||
|
|
||||||
|
class ShapeCollisionComponent : public CollisionComponent
|
||||||
|
{
|
||||||
|
typedef Component Parent;
|
||||||
|
public:
|
||||||
|
enum MeshType
|
||||||
|
{
|
||||||
|
None = 0, ///< No mesh
|
||||||
|
Bounds = 1, ///< Bounding box of the shape
|
||||||
|
CollisionMesh = 2, ///< Specifically designated collision meshes
|
||||||
|
VisibleMesh = 3 ///< Rendered mesh polygons
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
MeshType mCollisionType;
|
||||||
|
MeshType mDecalType;
|
||||||
|
MeshType mLOSType;
|
||||||
|
|
||||||
|
Vector<S32> mCollisionDetails;
|
||||||
|
Vector<S32> mLOSDetails;
|
||||||
|
|
||||||
|
StringTableEntry colisionMeshPrefix;
|
||||||
|
|
||||||
|
RenderComponentInterface* mOwnerRenderInterface;
|
||||||
|
|
||||||
|
PhysicsComponent* mOwnerPhysicsComp;
|
||||||
|
|
||||||
|
//only really relevent for the collision mesh type
|
||||||
|
//if we note an animation component is added, we flag as being animated.
|
||||||
|
//This way, if we're using collision meshes, we can set it up to update their transforms
|
||||||
|
//as needed
|
||||||
|
bool mAnimated;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
ColliderMask = Parent::NextFreeMask,
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
ShapeCollisionComponent();
|
||||||
|
virtual ~ShapeCollisionComponent();
|
||||||
|
DECLARE_CONOBJECT(ShapeCollisionComponent);
|
||||||
|
|
||||||
|
virtual U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream);
|
||||||
|
virtual void unpackUpdate(NetConnection *con, BitStream *stream);
|
||||||
|
|
||||||
|
virtual void componentAddedToOwner(Component *comp);
|
||||||
|
virtual void componentRemovedFromOwner(Component *comp);
|
||||||
|
virtual void ownerTransformSet(MatrixF *mat);
|
||||||
|
void targetShapeChanged(RenderComponentInterface* instanceInterface);
|
||||||
|
|
||||||
|
virtual void onComponentRemove();
|
||||||
|
virtual void onComponentAdd();
|
||||||
|
|
||||||
|
virtual void checkDependencies();
|
||||||
|
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
void inspectPostApply();
|
||||||
|
|
||||||
|
//Setup
|
||||||
|
virtual void prepCollision();
|
||||||
|
|
||||||
|
//Updates
|
||||||
|
virtual void processTick();
|
||||||
|
|
||||||
|
PhysicsCollision* buildColShapes();
|
||||||
|
|
||||||
|
void updatePhysics();
|
||||||
|
|
||||||
|
virtual bool castRay(const Point3F &start, const Point3F &end, RayInfo* info);
|
||||||
|
|
||||||
|
virtual bool buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F &box, const SphereF &sphere){ return false; }
|
||||||
|
|
||||||
|
virtual PhysicsCollision* getCollisionData();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef ShapeCollisionComponent::MeshType CollisionMeshMeshType;
|
||||||
|
DefineEnumType(CollisionMeshMeshType);
|
||||||
|
|
||||||
|
#endif // COLLISION_COMPONENT_H
|
||||||
|
|
@ -0,0 +1,172 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2012 GarageGames, LLC
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "console/engineAPI.h"
|
||||||
|
#include "T3D/components/collision/shapeCollisionComponent.h"
|
||||||
|
#include "materials/baseMatInstance.h"
|
||||||
|
|
||||||
|
DefineEngineMethod(CollisionComponent, getNumberOfContacts, S32, (), ,
|
||||||
|
"Gets the number of contacts this collider has hit.\n"
|
||||||
|
"@return The number of static fields defined on the object.")
|
||||||
|
{
|
||||||
|
return object->getCollisionList()->getCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(CollisionComponent, getBestContact, S32, (), ,
|
||||||
|
"Gets the number of contacts this collider has hit.\n"
|
||||||
|
"@return The number of static fields defined on the object.")
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(CollisionComponent, getContactNormal, Point3F, (), ,
|
||||||
|
"Gets the number of contacts this collider has hit.\n"
|
||||||
|
"@return The number of static fields defined on the object.")
|
||||||
|
{
|
||||||
|
if (object->getContactInfo())
|
||||||
|
{
|
||||||
|
if (object->getContactInfo()->contactObject)
|
||||||
|
{
|
||||||
|
return object->getContactInfo()->contactNormal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Point3F::Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(CollisionComponent, getContactMaterial, S32, (), ,
|
||||||
|
"Gets the number of contacts this collider has hit.\n"
|
||||||
|
"@return The number of static fields defined on the object.")
|
||||||
|
{
|
||||||
|
if (object->getContactInfo())
|
||||||
|
{
|
||||||
|
if (object->getContactInfo()->contactObject)
|
||||||
|
{
|
||||||
|
if (object->getContactInfo()->contactMaterial != NULL)
|
||||||
|
return object->getContactInfo()->contactMaterial->getMaterial()->getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(CollisionComponent, getContactObject, S32, (), ,
|
||||||
|
"Gets the number of contacts this collider has hit.\n"
|
||||||
|
"@return The number of static fields defined on the object.")
|
||||||
|
{
|
||||||
|
if (object->getContactInfo())
|
||||||
|
{
|
||||||
|
return object->getContactInfo()->contactObject != NULL ? object->getContactInfo()->contactObject->getId() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(CollisionComponent, getContactPoint, Point3F, (), ,
|
||||||
|
"Gets the number of contacts this collider has hit.\n"
|
||||||
|
"@return The number of static fields defined on the object.")
|
||||||
|
{
|
||||||
|
if (object->getContactInfo())
|
||||||
|
{
|
||||||
|
if (object->getContactInfo()->contactObject)
|
||||||
|
{
|
||||||
|
return object->getContactInfo()->contactPoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Point3F::Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(CollisionComponent, getContactTime, S32, (), ,
|
||||||
|
"Gets the number of contacts this collider has hit.\n"
|
||||||
|
"@return The number of static fields defined on the object.")
|
||||||
|
{
|
||||||
|
if (object->getContactInfo())
|
||||||
|
{
|
||||||
|
if (object->getContactInfo()->contactObject)
|
||||||
|
{
|
||||||
|
return object->getContactInfo()->contactTimer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(ShapeCollisionComponent, hasContact, bool, (), ,
|
||||||
|
"@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n"
|
||||||
|
|
||||||
|
"@param pos impulse world position\n"
|
||||||
|
"@param vel impulse velocity (impulse force F = m * v)\n"
|
||||||
|
"@return Always true\n"
|
||||||
|
|
||||||
|
"@note Not all objects that derrive from GameBase have this defined.\n")
|
||||||
|
{
|
||||||
|
return object->hasContact();
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(ShapeCollisionComponent, getCollisionCount, S32, (), ,
|
||||||
|
"@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n"
|
||||||
|
|
||||||
|
"@param pos impulse world position\n"
|
||||||
|
"@param vel impulse velocity (impulse force F = m * v)\n"
|
||||||
|
"@return Always true\n"
|
||||||
|
|
||||||
|
"@note Not all objects that derrive from GameBase have this defined.\n")
|
||||||
|
{
|
||||||
|
return object->getCollisionCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(ShapeCollisionComponent, getCollisionNormal, Point3F, (S32 collisionIndex), ,
|
||||||
|
"@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n"
|
||||||
|
|
||||||
|
"@param pos impulse world position\n"
|
||||||
|
"@param vel impulse velocity (impulse force F = m * v)\n"
|
||||||
|
"@return Always true\n"
|
||||||
|
|
||||||
|
"@note Not all objects that derrive from GameBase have this defined.\n")
|
||||||
|
{
|
||||||
|
return object->getCollisionNormal(collisionIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(ShapeCollisionComponent, getCollisionAngle, F32, (S32 collisionIndex, VectorF upVector), ,
|
||||||
|
"@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n"
|
||||||
|
|
||||||
|
"@param pos impulse world position\n"
|
||||||
|
"@param vel impulse velocity (impulse force F = m * v)\n"
|
||||||
|
"@return Always true\n"
|
||||||
|
|
||||||
|
"@note Not all objects that derrive from GameBase have this defined.\n")
|
||||||
|
{
|
||||||
|
return object->getCollisionAngle(collisionIndex, upVector);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(ShapeCollisionComponent, getBestCollisionAngle, F32, (VectorF upVector), ,
|
||||||
|
"@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n"
|
||||||
|
|
||||||
|
"@param pos impulse world position\n"
|
||||||
|
"@param vel impulse velocity (impulse force F = m * v)\n"
|
||||||
|
"@return Always true\n"
|
||||||
|
|
||||||
|
"@note Not all objects that derrive from GameBase have this defined.\n")
|
||||||
|
{
|
||||||
|
return object->getBestCollisionAngle(upVector);
|
||||||
|
}
|
||||||
216
Engine/source/T3D/components/collision/simpleHitboxComponent.cpp
Normal file
216
Engine/source/T3D/components/collision/simpleHitboxComponent.cpp
Normal file
|
|
@ -0,0 +1,216 @@
|
||||||
|
#include "simpleHitboxComponent.h"
|
||||||
|
|
||||||
|
IMPLEMENT_CO_NETOBJECT_V1(SimpleHitboxComponent);
|
||||||
|
|
||||||
|
SimpleHitboxComponent::SimpleHitboxComponent() :
|
||||||
|
// location of head, torso, legs
|
||||||
|
mBoxHeadPercentage(0.85f),
|
||||||
|
mBoxTorsoPercentage(0.55f),
|
||||||
|
mBoxLeftPercentage(0),
|
||||||
|
mBoxRightPercentage(1),
|
||||||
|
mBoxBackPercentage(0),
|
||||||
|
mBoxFrontPercentage(1),
|
||||||
|
mIsProne(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleHitboxComponent::~SimpleHitboxComponent()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleHitboxComponent::initPersistFields()
|
||||||
|
{
|
||||||
|
addGroup("Hitbox");
|
||||||
|
addField("headPercentage", TypeF32, Offset(mBoxHeadPercentage, SimpleHitboxComponent), "");
|
||||||
|
addField("torsoPercentage", TypeF32, Offset(mBoxTorsoPercentage, SimpleHitboxComponent), "");
|
||||||
|
addField("leftPercentage", TypeF32, Offset(mBoxLeftPercentage, SimpleHitboxComponent), "");
|
||||||
|
addField("rightPercentage", TypeF32, Offset(mBoxRightPercentage, SimpleHitboxComponent), "");
|
||||||
|
addField("backPercentage", TypeF32, Offset(mBoxBackPercentage, SimpleHitboxComponent), "");
|
||||||
|
addField("frontPercentage", TypeF32, Offset(mBoxFrontPercentage, SimpleHitboxComponent), "");
|
||||||
|
|
||||||
|
addField("isProne", TypeF32, Offset(mIsProne, SimpleHitboxComponent), "");
|
||||||
|
endGroup("Hitbox");
|
||||||
|
|
||||||
|
Parent::initPersistFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleHitboxComponent::onComponentAdd()
|
||||||
|
{
|
||||||
|
Parent::onComponentAdd();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleHitboxComponent::componentAddedToOwner(Component *comp)
|
||||||
|
{
|
||||||
|
Parent::componentAddedToOwner(comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleHitboxComponent::componentRemovedFromOwner(Component *comp)
|
||||||
|
{
|
||||||
|
Parent::componentRemovedFromOwner(comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleHitboxComponent::processTick()
|
||||||
|
{
|
||||||
|
Parent::processTick();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleHitboxComponent::interpolateTick(F32 dt)
|
||||||
|
{
|
||||||
|
Parent::interpolateTick(dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleHitboxComponent::advanceTime(F32 dt)
|
||||||
|
{
|
||||||
|
Parent::advanceTime(dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleHitboxComponent::getDamageLocation(const Point3F& in_rPos, const char *&out_rpVert, const char *&out_rpQuad)
|
||||||
|
{
|
||||||
|
Point3F newPoint;
|
||||||
|
mOwner->getWorldToObj().mulP(in_rPos, &newPoint);
|
||||||
|
|
||||||
|
Point3F boxSize = mOwner->getObjBox().getExtents();
|
||||||
|
|
||||||
|
F32 boxHeight = boxSize.z;
|
||||||
|
F32 pointHeight = newPoint.z;
|
||||||
|
|
||||||
|
if (mIsProne)
|
||||||
|
pointHeight = newPoint.y; //this assumes we're y-forward
|
||||||
|
|
||||||
|
F32 zTorso = mBoxTorsoPercentage;
|
||||||
|
F32 zHead = mBoxHeadPercentage;
|
||||||
|
|
||||||
|
zTorso *= boxHeight;
|
||||||
|
zHead *= boxHeight;
|
||||||
|
|
||||||
|
if (pointHeight <= zTorso)
|
||||||
|
out_rpVert = "legs";
|
||||||
|
else if (pointHeight <= zHead)
|
||||||
|
out_rpVert = "torso";
|
||||||
|
else
|
||||||
|
out_rpVert = "head";
|
||||||
|
|
||||||
|
if (dStrcmp(out_rpVert, "head") != 0)
|
||||||
|
{
|
||||||
|
if (newPoint.y >= 0.0f)
|
||||||
|
{
|
||||||
|
if (newPoint.x <= 0.0f)
|
||||||
|
out_rpQuad = "front_left";
|
||||||
|
else
|
||||||
|
out_rpQuad = "front_right";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (newPoint.x <= 0.0f)
|
||||||
|
out_rpQuad = "back_left";
|
||||||
|
else
|
||||||
|
out_rpQuad = "back_right";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
F32 backToFront = boxSize.x;
|
||||||
|
F32 leftToRight = boxSize.y;
|
||||||
|
|
||||||
|
F32 backPoint = backToFront * mBoxBackPercentage;
|
||||||
|
F32 frontPoint = backToFront * mBoxFrontPercentage;
|
||||||
|
F32 leftPoint = leftToRight * mBoxLeftPercentage;
|
||||||
|
F32 rightPoint = leftToRight * mBoxRightPercentage;
|
||||||
|
|
||||||
|
S32 index = 0;
|
||||||
|
if (newPoint.y < backPoint)
|
||||||
|
index += 0;
|
||||||
|
else if (newPoint.y >= frontPoint)
|
||||||
|
index += 3;
|
||||||
|
else
|
||||||
|
index += 6;
|
||||||
|
|
||||||
|
if (newPoint.x < leftPoint)
|
||||||
|
index += 0;
|
||||||
|
else if (newPoint.x >= rightPoint)
|
||||||
|
index += 1;
|
||||||
|
else
|
||||||
|
index += 2;
|
||||||
|
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0: out_rpQuad = "left_back"; break;
|
||||||
|
case 1: out_rpQuad = "middle_back"; break;
|
||||||
|
case 2: out_rpQuad = "right_back"; break;
|
||||||
|
case 3: out_rpQuad = "left_middle"; break;
|
||||||
|
case 4: out_rpQuad = "middle_middle"; break;
|
||||||
|
case 5: out_rpQuad = "right_middle"; break;
|
||||||
|
case 6: out_rpQuad = "left_front"; break;
|
||||||
|
case 7: out_rpQuad = "middle_front"; break;
|
||||||
|
case 8: out_rpQuad = "right_front"; break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
AssertFatal(0, "Bad non-tant index");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(SimpleHitboxComponent, getDamageLocation, const char*, (Point3F pos), ,
|
||||||
|
"@brief Get the named damage location and modifier for a given world position.\n\n"
|
||||||
|
|
||||||
|
"the Player object can simulate different hit locations based on a pre-defined set "
|
||||||
|
"of PlayerData defined percentages. These hit percentages divide up the Player's "
|
||||||
|
"bounding box into different regions. The diagram below demonstrates how the various "
|
||||||
|
"PlayerData properties split up the bounding volume:\n\n"
|
||||||
|
|
||||||
|
"<img src=\"images/player_damageloc.png\">\n\n"
|
||||||
|
|
||||||
|
"While you may pass in any world position and getDamageLocation() will provide a best-fit "
|
||||||
|
"location, you should be aware that this can produce some interesting results. For example, "
|
||||||
|
"any position that is above PlayerData::boxHeadPercentage will be considered a 'head' hit, even "
|
||||||
|
"if the world position is high in the sky. Therefore it may be wise to keep the passed in point "
|
||||||
|
"to somewhere on the surface of, or within, the Player's bounding volume.\n\n"
|
||||||
|
|
||||||
|
"@note This method will not return an accurate location when the player is "
|
||||||
|
"prone or swimming.\n\n"
|
||||||
|
|
||||||
|
"@param pos A world position for which to retrieve a body region on this player.\n"
|
||||||
|
|
||||||
|
"@return a string containing two words (space separated strings), where the "
|
||||||
|
"first is a location and the second is a modifier.\n\n"
|
||||||
|
|
||||||
|
"Posible locations:<ul>"
|
||||||
|
"<li>head</li>"
|
||||||
|
"<li>torso</li>"
|
||||||
|
"<li>legs</li></ul>\n"
|
||||||
|
|
||||||
|
"Head modifiers:<ul>"
|
||||||
|
"<li>left_back</li>"
|
||||||
|
"<li>middle_back</li>"
|
||||||
|
"<li>right_back</li>"
|
||||||
|
"<li>left_middle</li>"
|
||||||
|
"<li>middle_middle</li>"
|
||||||
|
"<li>right_middle</li>"
|
||||||
|
"<li>left_front</li>"
|
||||||
|
"<li>middle_front</li>"
|
||||||
|
"<li>right_front</li></ul>\n"
|
||||||
|
|
||||||
|
"Legs/Torso modifiers:<ul>"
|
||||||
|
"<li>front_left</li>"
|
||||||
|
"<li>front_right</li>"
|
||||||
|
"<li>back_left</li>"
|
||||||
|
"<li>back_right</li></ul>\n"
|
||||||
|
|
||||||
|
"@see PlayerData::boxHeadPercentage\n"
|
||||||
|
"@see PlayerData::boxHeadFrontPercentage\n"
|
||||||
|
"@see PlayerData::boxHeadBackPercentage\n"
|
||||||
|
"@see PlayerData::boxHeadLeftPercentage\n"
|
||||||
|
"@see PlayerData::boxHeadRightPercentage\n"
|
||||||
|
"@see PlayerData::boxTorsoPercentage\n"
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const char *buffer1;
|
||||||
|
const char *buffer2;
|
||||||
|
|
||||||
|
object->getDamageLocation(pos, buffer1, buffer2);
|
||||||
|
|
||||||
|
static const U32 bufSize = 128;
|
||||||
|
char *buff = Con::getReturnBuffer(bufSize);
|
||||||
|
dSprintf(buff, bufSize, "%s %s", buffer1, buffer2);
|
||||||
|
return buff;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "T3D/components/component.h"
|
||||||
|
|
||||||
|
class SimpleHitboxComponent : public Component
|
||||||
|
{
|
||||||
|
typedef Component Parent;
|
||||||
|
|
||||||
|
// location of head, torso, legs
|
||||||
|
F32 mBoxHeadPercentage;
|
||||||
|
F32 mBoxTorsoPercentage;
|
||||||
|
|
||||||
|
// damage locations
|
||||||
|
F32 mBoxLeftPercentage;
|
||||||
|
F32 mBoxRightPercentage;
|
||||||
|
F32 mBoxBackPercentage;
|
||||||
|
F32 mBoxFrontPercentage;
|
||||||
|
|
||||||
|
// Is our hitbox horizontal, usually due to being prone, swimming, etc
|
||||||
|
bool mIsProne;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SimpleHitboxComponent();
|
||||||
|
~SimpleHitboxComponent();
|
||||||
|
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
virtual void onComponentAdd();
|
||||||
|
virtual void componentAddedToOwner(Component *comp);
|
||||||
|
virtual void componentRemovedFromOwner(Component *comp);
|
||||||
|
|
||||||
|
virtual void processTick();
|
||||||
|
virtual void interpolateTick(F32 dt);
|
||||||
|
virtual void advanceTime(F32 dt);
|
||||||
|
|
||||||
|
void getDamageLocation(const Point3F& in_rPos, const char *&out_rpVert, const char *&out_rpQuad);
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(SimpleHitboxComponent);
|
||||||
|
};
|
||||||
|
|
@ -456,7 +456,7 @@ void Component::checkComponentFieldModified(const char* slotName, const char* ne
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
void Component::addComponentField(const char *fieldName, const char *desc, const char *type, const char *defaultValue /* = NULL */, const char *userData /* = NULL */, /*const char* dependency /* = NULL *//*,*/ bool hidden /* = false */)
|
void Component::addComponentField(const char *fieldName, const char *desc, const char *type, const char *defaultValue /* = NULL */, const char *userData /* = NULL */, /*const char* dependency /* = NULL *//*,*/ bool hidden /* = false */, const char* customLabel /* = ""*/)
|
||||||
{
|
{
|
||||||
StringTableEntry stFieldName = StringTable->insert(fieldName);
|
StringTableEntry stFieldName = StringTable->insert(fieldName);
|
||||||
|
|
||||||
|
|
@ -467,6 +467,12 @@ void Component::addComponentField(const char *fieldName, const char *desc, const
|
||||||
}
|
}
|
||||||
|
|
||||||
ComponentField field;
|
ComponentField field;
|
||||||
|
|
||||||
|
if (customLabel != "")
|
||||||
|
field.mFieldLabel = customLabel;
|
||||||
|
else
|
||||||
|
field.mFieldLabel = stFieldName;
|
||||||
|
|
||||||
field.mFieldName = stFieldName;
|
field.mFieldName = stFieldName;
|
||||||
|
|
||||||
//find the field type
|
//find the field type
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#ifndef COMPONENT_H
|
#ifndef COMPONENT_H
|
||||||
#define COMPONENT_H
|
#define COMPONENT_H
|
||||||
|
|
||||||
|
|
@ -44,6 +46,7 @@ class Namespace;
|
||||||
|
|
||||||
struct ComponentField
|
struct ComponentField
|
||||||
{
|
{
|
||||||
|
StringTableEntry mFieldLabel;
|
||||||
StringTableEntry mFieldName;
|
StringTableEntry mFieldName;
|
||||||
StringTableEntry mFieldDescription;
|
StringTableEntry mFieldDescription;
|
||||||
|
|
||||||
|
|
@ -145,7 +148,7 @@ public:
|
||||||
/// @param type The Type of field that this is, example 'Text' or 'Bool'
|
/// @param type The Type of field that this is, example 'Text' or 'Bool'
|
||||||
/// @param defaultValue The Default value of this field
|
/// @param defaultValue The Default value of this field
|
||||||
/// @param userData An extra optional field that can be used for user data
|
/// @param userData An extra optional field that can be used for user data
|
||||||
void addComponentField(const char *fieldName, const char *desc, const char *type, const char *defaultValue = NULL, const char *userData = NULL, bool hidden = false);
|
void addComponentField(const char *fieldName, const char *desc, const char *type, const char *defaultValue = NULL, const char *userData = NULL, bool hidden = false, const char* customLabel = "");
|
||||||
|
|
||||||
/// Returns the number of ComponentField's on this template
|
/// Returns the number of ComponentField's on this template
|
||||||
inline S32 getComponentFieldCount() { return mFields.size(); };
|
inline S32 getComponentFieldCount() { return mFields.size(); };
|
||||||
|
|
|
||||||
149
Engine/source/T3D/components/game/controlObjectComponent.cpp
Normal file
149
Engine/source/T3D/components/game/controlObjectComponent.cpp
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2012 GarageGames, LLC
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "T3D/components/game/controlObjectComponent.h"
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor/Destructor
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
ControlObjectComponent::ControlObjectComponent() : Component(),
|
||||||
|
mOwnerConnection(nullptr),
|
||||||
|
mOwnerConnectionId(0)
|
||||||
|
{
|
||||||
|
mFriendlyName = "Control Object";
|
||||||
|
mComponentType = "Game";
|
||||||
|
|
||||||
|
mDescription = getDescriptionText("Allows owner entity to be controlled by a client.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlObjectComponent::~ControlObjectComponent()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
IMPLEMENT_CO_NETOBJECT_V1(ControlObjectComponent);
|
||||||
|
|
||||||
|
bool ControlObjectComponent::onAdd()
|
||||||
|
{
|
||||||
|
if (!Parent::onAdd())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlObjectComponent::onRemove()
|
||||||
|
{
|
||||||
|
Parent::onRemove();
|
||||||
|
}
|
||||||
|
|
||||||
|
//This is mostly a catch for situations where the behavior is re-added to the object and the like and we may need to force an update to the behavior
|
||||||
|
void ControlObjectComponent::onComponentAdd()
|
||||||
|
{
|
||||||
|
Parent::onComponentAdd();
|
||||||
|
|
||||||
|
if (mOwnerConnection && mOwnerConnection->getControlObject() == nullptr)
|
||||||
|
{
|
||||||
|
mOwnerConnection->setControlObject(mOwner);
|
||||||
|
mOwnerConnectionId = mOwnerConnection->getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlObjectComponent::onComponentRemove()
|
||||||
|
{
|
||||||
|
Parent::onComponentRemove();
|
||||||
|
|
||||||
|
if (mOwnerConnection)
|
||||||
|
{
|
||||||
|
mOwnerConnection->setControlObject(nullptr);
|
||||||
|
mOwnerConnectionId = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlObjectComponent::initPersistFields()
|
||||||
|
{
|
||||||
|
Parent::initPersistFields();
|
||||||
|
|
||||||
|
addField("clientOwner", TypeS32, Offset(mOwnerConnectionId, ControlObjectComponent), "Client connection ID");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlObjectComponent::setConnectionControlObject(GameConnection* conn)
|
||||||
|
{
|
||||||
|
if (conn)
|
||||||
|
{
|
||||||
|
if (conn->getControlObject() == nullptr)
|
||||||
|
{
|
||||||
|
conn->setControlObject(mOwner);
|
||||||
|
mOwnerConnectionId = conn->getId();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Inform the old control object it's no longer in control?
|
||||||
|
conn->setControlObject(mOwner);
|
||||||
|
mOwnerConnectionId = conn->getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlObjectComponent::onClientConnect(GameConnection* conn)
|
||||||
|
{
|
||||||
|
if (conn && conn->getControlObject() == nullptr)
|
||||||
|
{
|
||||||
|
conn->setControlObject(mOwner);
|
||||||
|
mOwnerConnectionId = conn->getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlObjectComponent::onClientDisconnect(GameConnection* conn)
|
||||||
|
{
|
||||||
|
if (conn && conn->getControlObject() == mOwner)
|
||||||
|
{
|
||||||
|
conn->setControlObject(nullptr);
|
||||||
|
mOwnerConnectionId = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(ControlObjectComponent, onClientConnect, void, (GameConnection* conn), (nullAsType<GameConnection*>()),
|
||||||
|
"Triggers a signal call to all components for a certain function.")
|
||||||
|
{
|
||||||
|
if (conn == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
object->onClientConnect(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(ControlObjectComponent, onClientDisconnect, void, (GameConnection* conn), (nullAsType<GameConnection*>()),
|
||||||
|
"Triggers a signal call to all components for a certain function.")
|
||||||
|
{
|
||||||
|
if (conn == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
object->onClientDisconnect(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(ControlObjectComponent, setConnectionControlObject, void, (GameConnection* conn), (nullAsType<GameConnection*>()),
|
||||||
|
"Triggers a signal call to all components for a certain function.")
|
||||||
|
{
|
||||||
|
if (conn == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
object->setConnectionControlObject(conn);
|
||||||
|
}
|
||||||
30
Engine/source/T3D/components/game/controlObjectComponent.h
Normal file
30
Engine/source/T3D/components/game/controlObjectComponent.h
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "T3D/components/component.h"
|
||||||
|
|
||||||
|
#include "T3D/gameBase/gameConnection.h"
|
||||||
|
|
||||||
|
class ControlObjectComponent : public Component
|
||||||
|
{
|
||||||
|
typedef Component Parent;
|
||||||
|
|
||||||
|
GameConnection* mOwnerConnection;
|
||||||
|
S32 mOwnerConnectionId;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ControlObjectComponent();
|
||||||
|
~ControlObjectComponent();
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(ControlObjectComponent);
|
||||||
|
|
||||||
|
virtual bool onAdd();
|
||||||
|
virtual void onRemove();
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
virtual void onComponentAdd();
|
||||||
|
virtual void onComponentRemove();
|
||||||
|
|
||||||
|
void onClientConnect(GameConnection* conn);
|
||||||
|
void onClientDisconnect(GameConnection* conn);
|
||||||
|
void setConnectionControlObject(GameConnection* conn);
|
||||||
|
};
|
||||||
359
Engine/source/T3D/components/game/followPathComponent.cpp
Normal file
359
Engine/source/T3D/components/game/followPathComponent.cpp
Normal file
|
|
@ -0,0 +1,359 @@
|
||||||
|
#include "T3D/components/game/followPathComponent.h"
|
||||||
|
|
||||||
|
IMPLEMENT_CO_DATABLOCK_V1(FollowPathComponent);
|
||||||
|
|
||||||
|
IMPLEMENT_CALLBACK(FollowPathComponent, onNode, void, (S32 node), (node),
|
||||||
|
"A script callback that indicates the path camera has arrived at a specific node in its path. Server side only.\n"
|
||||||
|
"@param Node Unique ID assigned to this node.\n");
|
||||||
|
|
||||||
|
FollowPathComponent::FollowPathComponent()
|
||||||
|
{
|
||||||
|
delta.time = 0;
|
||||||
|
delta.timeVec = 0;
|
||||||
|
|
||||||
|
//mDataBlock = 0;
|
||||||
|
mState = Forward;
|
||||||
|
mNodeBase = 0;
|
||||||
|
mNodeCount = 0;
|
||||||
|
mPosition = 0;
|
||||||
|
mTarget = 0;
|
||||||
|
mTargetSet = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FollowPathComponent::~FollowPathComponent()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FollowPathComponent::onAdd()
|
||||||
|
{
|
||||||
|
if (!Parent::onAdd())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/*// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
mObjBox.maxExtents = mObjScale;
|
||||||
|
mObjBox.minExtents = mObjScale;
|
||||||
|
mObjBox.minExtents.neg();
|
||||||
|
resetWorldBox();*/
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void FollowPathComponent::onRemove()
|
||||||
|
{
|
||||||
|
Parent::onRemove();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FollowPathComponent::initPersistFields()
|
||||||
|
{
|
||||||
|
Parent::initPersistFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FollowPathComponent::componentAddedToOwner(Component *comp)
|
||||||
|
{
|
||||||
|
Parent::componentAddedToOwner(comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FollowPathComponent::componentRemovedFromOwner(Component *comp)
|
||||||
|
{
|
||||||
|
Parent::componentRemovedFromOwner(comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FollowPathComponent::processTick()
|
||||||
|
{
|
||||||
|
Parent::processTick();
|
||||||
|
|
||||||
|
// Move to new time
|
||||||
|
advancePosition(TickMs);
|
||||||
|
|
||||||
|
// Set new position
|
||||||
|
MatrixF mat;
|
||||||
|
interpolateMat(mPosition, &mat);
|
||||||
|
mOwner->setTransform(mat);
|
||||||
|
|
||||||
|
mOwner->updateContainer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FollowPathComponent::interpolateTick(F32 dt)
|
||||||
|
{
|
||||||
|
Parent::interpolateTick(dt);
|
||||||
|
|
||||||
|
MatrixF mat;
|
||||||
|
interpolateMat(delta.time + (delta.timeVec * dt), &mat);
|
||||||
|
mOwner->setRenderTransform(mat);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FollowPathComponent::interpolateMat(F32 pos, MatrixF* mat)
|
||||||
|
{
|
||||||
|
/*CameraSpline::Knot knot;
|
||||||
|
mSpline.value(pos - mNodeBase, &knot);
|
||||||
|
knot.mRotation.setMatrix(mat);
|
||||||
|
mat->setPosition(knot.mPosition);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void FollowPathComponent::advanceTime(F32 dt)
|
||||||
|
{
|
||||||
|
Parent::advanceTime(dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FollowPathComponent::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 FollowPathComponent::getCameraTransform(F32* pos, MatrixF* mat)
|
||||||
|
{
|
||||||
|
// Overide the ShapeBase method to skip all the first/third person support.
|
||||||
|
getRenderEyeTransform(mat);
|
||||||
|
|
||||||
|
// Apply Camera FX.
|
||||||
|
mat->mul(gCamFXMgr.getTrans());
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void FollowPathComponent::setPosition(F32 pos)
|
||||||
|
{
|
||||||
|
mPosition = mClampF(pos, (F32)mNodeBase, (F32)(mNodeBase + mNodeCount - 1));
|
||||||
|
MatrixF mat;
|
||||||
|
interpolateMat(mPosition, &mat);
|
||||||
|
mOwner->setTransform(mat);
|
||||||
|
setMaskBits(PositionMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FollowPathComponent::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 FollowPathComponent::setState(State s)
|
||||||
|
{
|
||||||
|
mState = s;
|
||||||
|
setMaskBits(StateMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void FollowPathComponent::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 FollowPathComponent::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 = (F32)mNodeBase;
|
||||||
|
setMaskBits(PositionMask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FollowPathComponent::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 > F32(mNodeBase + (NodeWindow - 1)))
|
||||||
|
{
|
||||||
|
mPosition = F32(mNodeBase + (NodeWindow - 1));
|
||||||
|
setMaskBits(PositionMask);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
void FollowPathComponent::popFront()
|
||||||
|
{
|
||||||
|
/*if (mNodeCount < 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Remove the first node. Node base and position are unaffected.
|
||||||
|
mNodeCount--;
|
||||||
|
delete mSpline.remove(mSpline.getKnot(0));
|
||||||
|
|
||||||
|
if (mPosition > 0)
|
||||||
|
mPosition--;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void FollowPathComponent::onNode(S32 node)
|
||||||
|
{
|
||||||
|
//if (!isGhost())
|
||||||
|
// onNode_callback(node);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*U32 FollowPathComponent::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 FollowPathComponent::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;
|
||||||
|
|
||||||
|
}*/
|
||||||
82
Engine/source/T3D/components/game/followPathComponent.h
Normal file
82
Engine/source/T3D/components/game/followPathComponent.h
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "T3D/components/component.h"
|
||||||
|
|
||||||
|
class FollowPathComponent : public Component
|
||||||
|
{
|
||||||
|
typedef Component Parent;
|
||||||
|
|
||||||
|
enum State {
|
||||||
|
Forward,
|
||||||
|
Backward,
|
||||||
|
Stop,
|
||||||
|
StateBits = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MaskBits {
|
||||||
|
WindowMask = Parent::NextFreeMask,
|
||||||
|
PositionMask = Parent::NextFreeMask + 1,
|
||||||
|
TargetMask = Parent::NextFreeMask + 2,
|
||||||
|
StateMask = Parent::NextFreeMask + 3,
|
||||||
|
NextFreeMask = Parent::NextFreeMask << 1
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StateDelta {
|
||||||
|
F32 time;
|
||||||
|
F32 timeVec;
|
||||||
|
};
|
||||||
|
StateDelta delta;
|
||||||
|
|
||||||
|
enum Constants {
|
||||||
|
NodeWindow = 128 // Maximum number of active nodes
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
//PathCameraData* 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(FollowPathComponent);
|
||||||
|
|
||||||
|
FollowPathComponent();
|
||||||
|
~FollowPathComponent();
|
||||||
|
|
||||||
|
virtual bool onAdd();
|
||||||
|
virtual void onRemove();
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
//This is called when a different component is added to our owner entity
|
||||||
|
virtual void componentAddedToOwner(Component *comp);
|
||||||
|
//This is called when a different component is removed from our owner entity
|
||||||
|
virtual void componentRemovedFromOwner(Component *comp);
|
||||||
|
|
||||||
|
virtual void processTick();
|
||||||
|
virtual void interpolateTick(F32 dt);
|
||||||
|
virtual void advanceTime(F32 dt);
|
||||||
|
|
||||||
|
//
|
||||||
|
//void onEditorEnable();
|
||||||
|
//void onEditorDisable();
|
||||||
|
|
||||||
|
void onNode(S32 node);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
DECLARE_CALLBACK(void, onNode, (S32 node));
|
||||||
|
};
|
||||||
171
Engine/source/T3D/components/game/interactComponent.cpp
Normal file
171
Engine/source/T3D/components/game/interactComponent.cpp
Normal file
|
|
@ -0,0 +1,171 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2012 GarageGames, LLC
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "T3D/components/game/interactComponent.h"
|
||||||
|
#include "scene/sceneContainer.h"
|
||||||
|
#include "T3D/components/game/interactableComponent.h"
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor/Destructor
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
InteractComponent::InteractComponent() : Component(),
|
||||||
|
mUseRaycastInteract(true),
|
||||||
|
mUseRenderedRaycast(false),
|
||||||
|
mUseRadiusInteract(true),
|
||||||
|
mInteractRadius(1.5),
|
||||||
|
mInteractRayDist(1.5),
|
||||||
|
mUseNaturalReach(false)
|
||||||
|
{
|
||||||
|
mFriendlyName = "Interact";
|
||||||
|
mComponentType = "Game";
|
||||||
|
|
||||||
|
mDescription = getDescriptionText("Allows owner entity interact.");
|
||||||
|
}
|
||||||
|
|
||||||
|
InteractComponent::~InteractComponent()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
IMPLEMENT_CO_NETOBJECT_V1(InteractComponent);
|
||||||
|
|
||||||
|
bool InteractComponent::onAdd()
|
||||||
|
{
|
||||||
|
if (!Parent::onAdd())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InteractComponent::onRemove()
|
||||||
|
{
|
||||||
|
Parent::onRemove();
|
||||||
|
}
|
||||||
|
|
||||||
|
//This is mostly a catch for situations where the behavior is re-added to the object and the like and we may need to force an update to the behavior
|
||||||
|
void InteractComponent::onComponentAdd()
|
||||||
|
{
|
||||||
|
Parent::onComponentAdd();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InteractComponent::onComponentRemove()
|
||||||
|
{
|
||||||
|
Parent::onComponentRemove();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InteractComponent::initPersistFields()
|
||||||
|
{
|
||||||
|
Parent::initPersistFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InteractComponent::processTick()
|
||||||
|
{
|
||||||
|
if (isClientObject())
|
||||||
|
return; //this shouldn't happen
|
||||||
|
|
||||||
|
//First, if we're doing rays, try that as if we get a hit, we can always assume that's the "correct" option
|
||||||
|
if (mUseRaycastInteract)
|
||||||
|
{
|
||||||
|
mOwner->disableCollision();
|
||||||
|
|
||||||
|
Point3F start = mOwner->getPosition();
|
||||||
|
Point3F end = mOwner->getTransform().getForwardVector() * mInteractRayDist + start;
|
||||||
|
|
||||||
|
RayInfo rinfo;
|
||||||
|
S32 ret = 0;
|
||||||
|
|
||||||
|
if (mUseRenderedRaycast)
|
||||||
|
{
|
||||||
|
rinfo.generateTexCoord = true;
|
||||||
|
if (gServerContainer.castRayRendered(mOwner->getPosition(), end, EntityObjectType, &rinfo) == true)
|
||||||
|
ret = rinfo.object->getId();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (gServerContainer.castRay(mOwner->getPosition(), end, EntityObjectType, &rinfo) == true)
|
||||||
|
ret = rinfo.object->getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
mOwner->enableCollision();
|
||||||
|
|
||||||
|
Entity* hitEntity = static_cast<Entity*>(rinfo.object);
|
||||||
|
|
||||||
|
if (hitEntity)
|
||||||
|
{
|
||||||
|
//call on that badboy!
|
||||||
|
InteractableComponent* iComp = hitEntity->getComponent<InteractableComponent>();
|
||||||
|
|
||||||
|
if (iComp)
|
||||||
|
{
|
||||||
|
iComp->interact(this, rinfo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//If not using rays or no hit, then do the radius search if we have it
|
||||||
|
if (mUseRadiusInteract)
|
||||||
|
{
|
||||||
|
gServerContainer.initRadiusSearch(mOwner->getPosition(), mInteractRadius, EntityObjectType);
|
||||||
|
|
||||||
|
F32 lastBestDist = 9999;
|
||||||
|
F32 lastBestWeight = 0;
|
||||||
|
Entity* bestFitEntity = nullptr;
|
||||||
|
|
||||||
|
Entity* e = static_cast<Entity*>(gServerContainer.containerSearchNextObject());
|
||||||
|
|
||||||
|
while (e != nullptr)
|
||||||
|
{
|
||||||
|
InteractableComponent* iComp = e->getComponent<InteractableComponent>();
|
||||||
|
|
||||||
|
if (iComp != nullptr)
|
||||||
|
{
|
||||||
|
F32 weight = iComp->getWeight();
|
||||||
|
VectorF distVec = e->getPosition() - mOwner->getPosition();
|
||||||
|
F32 dist = distVec.len();
|
||||||
|
|
||||||
|
//If the weight is better, always pick it
|
||||||
|
if (weight > lastBestWeight)
|
||||||
|
{
|
||||||
|
lastBestDist = dist;
|
||||||
|
lastBestWeight = weight;
|
||||||
|
bestFitEntity = e;
|
||||||
|
}
|
||||||
|
//Otherwise, if the weight is matched and the distance is closer, pick that
|
||||||
|
else if (weight >= lastBestWeight && lastBestDist < dist)
|
||||||
|
{
|
||||||
|
lastBestWeight = weight;
|
||||||
|
bestFitEntity = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
e = static_cast<Entity*>(gServerContainer.containerSearchNextObject()); //loop 'round
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bestFitEntity)
|
||||||
|
{
|
||||||
|
//call on that badboy!
|
||||||
|
InteractableComponent* iComp = bestFitEntity->getComponent<InteractableComponent>();
|
||||||
|
|
||||||
|
iComp->interact(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
34
Engine/source/T3D/components/game/interactComponent.h
Normal file
34
Engine/source/T3D/components/game/interactComponent.h
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "T3D/components/component.h"
|
||||||
|
|
||||||
|
|
||||||
|
class InteractComponent : public Component
|
||||||
|
{
|
||||||
|
typedef Component Parent;
|
||||||
|
|
||||||
|
bool mUseRaycastInteract;
|
||||||
|
bool mUseRenderedRaycast;
|
||||||
|
bool mUseRadiusInteract;
|
||||||
|
|
||||||
|
F32 mInteractRadius;
|
||||||
|
F32 mInteractRayDist;
|
||||||
|
|
||||||
|
//Adjusts the length of the ray based on the idea of further reach if you look down because of crouching
|
||||||
|
bool mUseNaturalReach;
|
||||||
|
|
||||||
|
public:
|
||||||
|
InteractComponent();
|
||||||
|
~InteractComponent();
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(InteractComponent);
|
||||||
|
|
||||||
|
virtual bool onAdd();
|
||||||
|
virtual void onRemove();
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
virtual void onComponentAdd();
|
||||||
|
virtual void onComponentRemove();
|
||||||
|
|
||||||
|
virtual void processTick();
|
||||||
|
};
|
||||||
94
Engine/source/T3D/components/game/interactableComponent.cpp
Normal file
94
Engine/source/T3D/components/game/interactableComponent.cpp
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2012 GarageGames, LLC
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "T3D/components/game/InteractableComponent.h"
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor/Destructor
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
InteractableComponent::InteractableComponent() : Component(),
|
||||||
|
mInteractableWeight(1)
|
||||||
|
{
|
||||||
|
mFriendlyName = "Interactable";
|
||||||
|
mComponentType = "Game";
|
||||||
|
|
||||||
|
mDescription = getDescriptionText("Allows owner entity to be interacted with.");
|
||||||
|
}
|
||||||
|
|
||||||
|
InteractableComponent::~InteractableComponent()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
IMPLEMENT_CO_NETOBJECT_V1(InteractableComponent);
|
||||||
|
|
||||||
|
bool InteractableComponent::onAdd()
|
||||||
|
{
|
||||||
|
if (!Parent::onAdd())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InteractableComponent::onRemove()
|
||||||
|
{
|
||||||
|
Parent::onRemove();
|
||||||
|
}
|
||||||
|
|
||||||
|
//This is mostly a catch for situations where the behavior is re-added to the object and the like and we may need to force an update to the behavior
|
||||||
|
void InteractableComponent::onComponentAdd()
|
||||||
|
{
|
||||||
|
Parent::onComponentAdd();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InteractableComponent::onComponentRemove()
|
||||||
|
{
|
||||||
|
Parent::onComponentRemove();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InteractableComponent::initPersistFields()
|
||||||
|
{
|
||||||
|
Parent::initPersistFields();
|
||||||
|
|
||||||
|
addField("interactableWeight", TypeF32, Offset(mInteractableWeight, InteractableComponent), "Controls importance values when using radius mode for interaction");
|
||||||
|
}
|
||||||
|
|
||||||
|
void InteractableComponent::interact(InteractComponent* interactor)
|
||||||
|
{
|
||||||
|
if (interactor != nullptr)
|
||||||
|
{
|
||||||
|
mOwner->notifyComponents("onInteract", interactor->getIdString());
|
||||||
|
|
||||||
|
if(isMethod("onInteract"))
|
||||||
|
Con::executef(this, "onInteract", interactor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InteractableComponent::interact(InteractComponent* interactor, RayInfo rayInfo)
|
||||||
|
{
|
||||||
|
if (interactor != nullptr)
|
||||||
|
{
|
||||||
|
mOwner->notifyComponents("onInteract", interactor->getIdString());
|
||||||
|
|
||||||
|
if (isMethod("onInteract"))
|
||||||
|
Con::executef(this, "onInteract", interactor);
|
||||||
|
}
|
||||||
|
}
|
||||||
30
Engine/source/T3D/components/game/interactableComponent.h
Normal file
30
Engine/source/T3D/components/game/interactableComponent.h
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "T3D/components/component.h"
|
||||||
|
#include "T3D/components/game/interactComponent.h"
|
||||||
|
|
||||||
|
class InteractableComponent : public Component
|
||||||
|
{
|
||||||
|
typedef Component Parent;
|
||||||
|
|
||||||
|
//Controls importance values when using radius mode for interaction
|
||||||
|
F32 mInteractableWeight;
|
||||||
|
|
||||||
|
public:
|
||||||
|
InteractableComponent();
|
||||||
|
~InteractableComponent();
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(InteractableComponent);
|
||||||
|
|
||||||
|
virtual bool onAdd();
|
||||||
|
virtual void onRemove();
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
virtual void onComponentAdd();
|
||||||
|
virtual void onComponentRemove();
|
||||||
|
|
||||||
|
void interact(InteractComponent* interactor);
|
||||||
|
void interact(InteractComponent* interactor, RayInfo rayInfo);
|
||||||
|
|
||||||
|
F32 getWeight() { return mInteractableWeight; }
|
||||||
|
};
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
#include "console/engineAPI.h"
|
#include "console/engineAPI.h"
|
||||||
#include "sim/netConnection.h"
|
#include "sim/netConnection.h"
|
||||||
#include "T3D/gameBase/gameConnection.h"
|
#include "T3D/gameBase/gameConnection.h"
|
||||||
#include "T3D/components/coreInterfaces.h"
|
//#include "T3D/components/coreInterfaces.h"
|
||||||
#include "math/mathUtils.h"
|
#include "math/mathUtils.h"
|
||||||
#include "collision/concretePolyList.h"
|
#include "collision/concretePolyList.h"
|
||||||
#include "collision/clippedPolyList.h"
|
#include "collision/clippedPolyList.h"
|
||||||
|
|
@ -94,21 +94,21 @@ void TriggerComponent::onComponentAdd()
|
||||||
{
|
{
|
||||||
Parent::onComponentAdd();
|
Parent::onComponentAdd();
|
||||||
|
|
||||||
CollisionInterface *colInt = mOwner->getComponent<CollisionInterface>();
|
CollisionComponent *colComp = mOwner->getComponent<CollisionComponent>();
|
||||||
|
|
||||||
if(colInt)
|
if(colComp)
|
||||||
{
|
{
|
||||||
colInt->onCollisionSignal.notify(this, &TriggerComponent::potentialEnterObject);
|
colComp->onCollisionSignal.notify(this, &TriggerComponent::potentialEnterObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TriggerComponent::onComponentRemove()
|
void TriggerComponent::onComponentRemove()
|
||||||
{
|
{
|
||||||
CollisionInterface *colInt = mOwner->getComponent<CollisionInterface>();
|
CollisionComponent *colComp = mOwner->getComponent<CollisionComponent>();
|
||||||
|
|
||||||
if(colInt)
|
if(colComp)
|
||||||
{
|
{
|
||||||
colInt->onCollisionSignal.remove(this, &TriggerComponent::potentialEnterObject);
|
colComp->onCollisionSignal.remove(this, &TriggerComponent::potentialEnterObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
Parent::onComponentRemove();
|
Parent::onComponentRemove();
|
||||||
|
|
@ -119,11 +119,11 @@ void TriggerComponent::componentAddedToOwner(Component *comp)
|
||||||
if (comp->getId() == getId())
|
if (comp->getId() == getId())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CollisionInterface *colInt = mOwner->getComponent<CollisionInterface>();
|
CollisionComponent *colComp = mOwner->getComponent<CollisionComponent>();
|
||||||
|
|
||||||
if (colInt)
|
if (colComp)
|
||||||
{
|
{
|
||||||
colInt->onCollisionSignal.notify(this, &TriggerComponent::potentialEnterObject);
|
colComp->onCollisionSignal.notify(this, &TriggerComponent::potentialEnterObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -132,11 +132,11 @@ void TriggerComponent::componentRemovedFromOwner(Component *comp)
|
||||||
if (comp->getId() == getId()) //?????????
|
if (comp->getId() == getId()) //?????????
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CollisionInterface *colInt = mOwner->getComponent<CollisionInterface>();
|
CollisionComponent *colComp = mOwner->getComponent<CollisionComponent>();
|
||||||
|
|
||||||
if (colInt)
|
if (colComp)
|
||||||
{
|
{
|
||||||
colInt->onCollisionSignal.remove(this, &TriggerComponent::potentialEnterObject);
|
colComp->onCollisionSignal.remove(this, &TriggerComponent::potentialEnterObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -217,19 +217,19 @@ bool TriggerComponent::testObject(SceneObject* enter)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
//check if the entity has a collision shape
|
//check if the entity has a collision shape
|
||||||
CollisionInterface *cI = enterEntity->getComponent<CollisionInterface>();
|
CollisionComponent *colComp = enterEntity->getComponent<CollisionComponent>();
|
||||||
if (cI)
|
if (colComp)
|
||||||
{
|
{
|
||||||
cI->buildPolyList(PLC_Collision, &mClippedList, mOwner->getWorldBox(), sphere);
|
colComp->buildPolyList(PLC_Collision, &mClippedList, mOwner->getWorldBox(), sphere);
|
||||||
|
|
||||||
if (!mClippedList.isEmpty())
|
if (!mClippedList.isEmpty())
|
||||||
{
|
{
|
||||||
//well, it's clipped with, or inside, our bounds
|
//well, it's clipped with, or inside, our bounds
|
||||||
//now to test the clipped list against our own collision mesh
|
//now to test the clipped list against our own collision mesh
|
||||||
CollisionInterface *myCI = mOwner->getComponent<CollisionInterface>();
|
CollisionComponent *myColComp = mOwner->getComponent<CollisionComponent>();
|
||||||
|
|
||||||
//wait, how would we NOT have this?
|
//wait, how would we NOT have this?
|
||||||
if (myCI)
|
if (myColComp)
|
||||||
{
|
{
|
||||||
//anywho, build our list and then we'll check intersections
|
//anywho, build our list and then we'll check intersections
|
||||||
ClippedPolyList myList;
|
ClippedPolyList myList;
|
||||||
|
|
@ -238,7 +238,7 @@ bool TriggerComponent::testObject(SceneObject* enter)
|
||||||
myList.setTransform(&ownerTransform, mOwner->getScale());
|
myList.setTransform(&ownerTransform, mOwner->getScale());
|
||||||
myList.setObject(mOwner);
|
myList.setObject(mOwner);
|
||||||
|
|
||||||
myCI->buildPolyList(PLC_Collision, &myList, enterBox, sphere);
|
myColComp->buildPolyList(PLC_Collision, &myList, enterBox, sphere);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -354,4 +354,4 @@ DefineEngineMethod( TriggerComponent, visualizeFrustums, void,
|
||||||
"@return true if successful, false if failed (objB is not valid)" )
|
"@return true if successful, false if failed (objB is not valid)" )
|
||||||
{
|
{
|
||||||
object->visualizeFrustums(renderTime);
|
object->visualizeFrustums(renderTime);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@
|
||||||
#include "T3D/entity.h"
|
#include "T3D/entity.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef _COLLISION_INTERFACES_H_
|
#ifndef COLLISION_COMPONENT_H
|
||||||
#include "T3D/components/collision/collisionInterfaces.h"
|
#include "T3D/components/collision/collisionComponent.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
#include "T3D/components/physics/physicsBehavior.h"
|
#include "T3D/components/physics/physicsComponent.h"
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "console/consoleTypes.h"
|
#include "console/consoleTypes.h"
|
||||||
#include "core/util/safeDelete.h"
|
#include "core/util/safeDelete.h"
|
||||||
|
|
@ -37,6 +37,8 @@
|
||||||
#include "T3D/containerQuery.h"
|
#include "T3D/containerQuery.h"
|
||||||
#include "math/mathIO.h"
|
#include "math/mathIO.h"
|
||||||
|
|
||||||
|
#include "T3D/physics/physicsPlugin.h"
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// Constructor/Destructor
|
// Constructor/Destructor
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
@ -47,6 +49,11 @@ PhysicsComponent::PhysicsComponent() : Component()
|
||||||
addComponentField("drag", "The drag coefficient that constantly affects the object", "float", "0.7", "");
|
addComponentField("drag", "The drag coefficient that constantly affects the object", "float", "0.7", "");
|
||||||
addComponentField("mass", "The mass of the object", "float", "1", "");
|
addComponentField("mass", "The mass of the object", "float", "1", "");
|
||||||
|
|
||||||
|
mFriendlyName = "Physics Component";
|
||||||
|
mComponentType = "Physics";
|
||||||
|
|
||||||
|
mDescription = getDescriptionText("A stub component class that physics components should inherit from.");
|
||||||
|
|
||||||
mStatic = false;
|
mStatic = false;
|
||||||
mAtRest = false;
|
mAtRest = false;
|
||||||
mAtRestCounter = 0;
|
mAtRestCounter = 0;
|
||||||
|
|
@ -80,7 +87,7 @@ PhysicsComponent::~PhysicsComponent()
|
||||||
SAFE_DELETE_ARRAY(mDescription);
|
SAFE_DELETE_ARRAY(mDescription);
|
||||||
}
|
}
|
||||||
|
|
||||||
IMPLEMENT_CO_NETOBJECT_V1(PhysicsComponent);
|
IMPLEMENT_CONOBJECT(PhysicsComponent);
|
||||||
|
|
||||||
void PhysicsComponent::onComponentAdd()
|
void PhysicsComponent::onComponentAdd()
|
||||||
{
|
{
|
||||||
|
|
@ -92,6 +99,11 @@ void PhysicsComponent::onComponentAdd()
|
||||||
mDelta.posVec = Point3F(0,0,0);
|
mDelta.posVec = Point3F(0,0,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PhysicsComponent::onComponentRemove()
|
||||||
|
{
|
||||||
|
Parent::onComponentRemove();
|
||||||
|
}
|
||||||
|
|
||||||
void PhysicsComponent::initPersistFields()
|
void PhysicsComponent::initPersistFields()
|
||||||
{
|
{
|
||||||
Parent::initPersistFields();
|
Parent::initPersistFields();
|
||||||
|
|
@ -101,6 +113,7 @@ void PhysicsComponent::initPersistFields()
|
||||||
addField("isStatic", TypeBool, Offset(mStatic, PhysicsComponent));
|
addField("isStatic", TypeBool, Offset(mStatic, PhysicsComponent));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Networking
|
||||||
U32 PhysicsComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
|
U32 PhysicsComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
|
||||||
{
|
{
|
||||||
U32 retMask = Parent::packUpdate(con, mask, stream);
|
U32 retMask = Parent::packUpdate(con, mask, stream);
|
||||||
|
|
@ -123,7 +136,6 @@ U32 PhysicsComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream
|
||||||
}
|
}
|
||||||
return retMask;
|
return retMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsComponent::unpackUpdate(NetConnection *con, BitStream *stream)
|
void PhysicsComponent::unpackUpdate(NetConnection *con, BitStream *stream)
|
||||||
{
|
{
|
||||||
Parent::unpackUpdate(con, stream);
|
Parent::unpackUpdate(con, stream);
|
||||||
|
|
@ -146,7 +158,35 @@ void PhysicsComponent::unpackUpdate(NetConnection *con, BitStream *stream)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//Setup
|
||||||
|
void PhysicsComponent::prepCollision()
|
||||||
|
{
|
||||||
|
if (!mOwner)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mConvexList != NULL)
|
||||||
|
mConvexList->nukeList();
|
||||||
|
|
||||||
|
mOwner->enableCollision();
|
||||||
|
_updatePhysics();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsComponent::_updatePhysics()
|
||||||
|
{
|
||||||
|
SAFE_DELETE( mPhysicsRep );
|
||||||
|
|
||||||
|
if ( !PHYSICSMGR )
|
||||||
|
return;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsComponent::buildConvex(const Box3F& box, Convex* convex)
|
||||||
|
{
|
||||||
|
convex = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Updates
|
||||||
void PhysicsComponent::interpolateTick(F32 dt)
|
void PhysicsComponent::interpolateTick(F32 dt)
|
||||||
{
|
{
|
||||||
Point3F pos = mDelta.pos + mDelta.posVec * dt;
|
Point3F pos = mDelta.pos + mDelta.posVec * dt;
|
||||||
|
|
@ -155,10 +195,19 @@ void PhysicsComponent::interpolateTick(F32 dt)
|
||||||
setRenderPosition(pos,dt);
|
setRenderPosition(pos,dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
void PhysicsComponent::updatePos(const F32 travelTime)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsComponent::updateForces()
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void PhysicsComponent::updateContainer()
|
void PhysicsComponent::updateContainer()
|
||||||
{
|
{
|
||||||
PROFILE_SCOPE( PhysicsBehaviorInstance_updateContainer );
|
PROFILE_SCOPE(PhysicsBehaviorInstance_updateContainer);
|
||||||
|
|
||||||
// Update container drag and buoyancy properties
|
// Update container drag and buoyancy properties
|
||||||
|
|
||||||
|
|
@ -168,11 +217,11 @@ void PhysicsComponent::updateContainer()
|
||||||
//mGravityMod = 1.0;
|
//mGravityMod = 1.0;
|
||||||
//mAppliedForce.set(0,0,0);
|
//mAppliedForce.set(0,0,0);
|
||||||
|
|
||||||
ContainerQueryInfo info;
|
mLastContainerInfo = ContainerQueryInfo();
|
||||||
info.box = mOwner->getWorldBox();
|
mLastContainerInfo.box = mOwner->getWorldBox();
|
||||||
info.mass = mMass;
|
mLastContainerInfo.mass = mMass;
|
||||||
|
|
||||||
mOwner->getContainer()->findObjects(info.box, WaterObjectType|PhysicalZoneObjectType,findRouter,&info);
|
mOwner->getContainer()->findObjects(mLastContainerInfo.box, WaterObjectType | PhysicalZoneObjectType, findRouter, &mLastContainerInfo);
|
||||||
|
|
||||||
//mWaterCoverage = info.waterCoverage;
|
//mWaterCoverage = info.waterCoverage;
|
||||||
//mLiquidType = info.liquidType;
|
//mLiquidType = info.liquidType;
|
||||||
|
|
@ -182,71 +231,37 @@ void PhysicsComponent::updateContainer()
|
||||||
// This value might be useful as a datablock value,
|
// This value might be useful as a datablock value,
|
||||||
// This is what allows the player to stand in shallow water (below this coverage)
|
// This is what allows the player to stand in shallow water (below this coverage)
|
||||||
// without jiggling from buoyancy
|
// without jiggling from buoyancy
|
||||||
if (info.waterCoverage >= 0.25f)
|
if (mLastContainerInfo.waterCoverage >= 0.25f)
|
||||||
{
|
{
|
||||||
// water viscosity is used as drag for in water.
|
// water viscosity is used as drag for in water.
|
||||||
// ShapeBaseData drag is used for drag outside of water.
|
// ShapeBaseData drag is used for drag outside of water.
|
||||||
// Combine these two components to calculate this ShapeBase object's
|
// Combine these two components to calculate this ShapeBase object's
|
||||||
// current drag.
|
// current drag.
|
||||||
mDrag = ( info.waterCoverage * info.waterViscosity ) +
|
mDrag = (mLastContainerInfo.waterCoverage * mLastContainerInfo.waterViscosity) +
|
||||||
( 1.0f - info.waterCoverage ) * mDrag;
|
(1.0f - mLastContainerInfo.waterCoverage) * mDrag;
|
||||||
//mBuoyancy = (info.waterDensity / mDataBlock->density) * info.waterCoverage;
|
//mBuoyancy = (info.waterDensity / mDataBlock->density) * info.waterCoverage;
|
||||||
}
|
}
|
||||||
|
|
||||||
//mAppliedForce = info.appliedForce;
|
//mAppliedForce = info.appliedForce;
|
||||||
mGravityMod = info.gravityScale;
|
mGravityMod = mLastContainerInfo.gravityScale;
|
||||||
}
|
}
|
||||||
//
|
|
||||||
void PhysicsComponent::_updatePhysics()
|
//Events
|
||||||
|
void PhysicsComponent::updateVelocity(const F32 dt)
|
||||||
{
|
{
|
||||||
/*SAFE_DELETE( mOwner->mPhysicsRep );
|
|
||||||
|
|
||||||
if ( !PHYSICSMGR )
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (mDataBlock->simpleServerCollision)
|
|
||||||
{
|
|
||||||
// We only need the trigger on the server.
|
|
||||||
if ( isServerObject() )
|
|
||||||
{
|
|
||||||
PhysicsCollision *colShape = PHYSICSMGR->createCollision();
|
|
||||||
colShape->addBox( mObjBox.getExtents() * 0.5f, MatrixF::Identity );
|
|
||||||
|
|
||||||
PhysicsWorld *world = PHYSICSMGR->getWorld( isServerObject() ? "server" : "client" );
|
|
||||||
mPhysicsRep = PHYSICSMGR->createBody();
|
|
||||||
mPhysicsRep->init( colShape, 0, PhysicsBody::BF_TRIGGER | PhysicsBody::BF_KINEMATIC, this, world );
|
|
||||||
mPhysicsRep->setTransform( getTransform() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ( !mShapeInstance )
|
|
||||||
return;
|
|
||||||
|
|
||||||
PhysicsCollision* colShape = mShapeInstance->getShape()->buildColShape( false, getScale() );
|
|
||||||
|
|
||||||
if ( colShape )
|
|
||||||
{
|
|
||||||
PhysicsWorld *world = PHYSICSMGR->getWorld( isServerObject() ? "server" : "client" );
|
|
||||||
mPhysicsRep = PHYSICSMGR->createBody();
|
|
||||||
mPhysicsRep->init( colShape, 0, PhysicsBody::BF_KINEMATIC, this, world );
|
|
||||||
mPhysicsRep->setTransform( getTransform() );
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PhysicsBody *PhysicsComponent::getPhysicsRep()
|
void PhysicsComponent::applyImpulse(const Point3F&, const VectorF& vec)
|
||||||
{
|
{
|
||||||
/*if(mOwner)
|
// Items ignore angular velocity
|
||||||
{
|
VectorF vel;
|
||||||
Entity* ac = dynamic_cast<Entity*>(mOwner);
|
vel.x = vec.x / mMass;
|
||||||
if(ac)
|
vel.y = vec.y / mMass;
|
||||||
return ac->mPhysicsRep;
|
vel.z = vec.z / mMass;
|
||||||
}*/
|
setVelocity(mVelocity + vel);
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
//
|
|
||||||
|
//Setters
|
||||||
void PhysicsComponent::setTransform(const MatrixF& mat)
|
void PhysicsComponent::setTransform(const MatrixF& mat)
|
||||||
{
|
{
|
||||||
mOwner->setTransform(mat);
|
mOwner->setTransform(mat);
|
||||||
|
|
@ -257,8 +272,8 @@ void PhysicsComponent::setTransform(const MatrixF& mat)
|
||||||
mAtRestCounter = 0;
|
mAtRestCounter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( getPhysicsRep() )
|
if (getPhysicsRep())
|
||||||
getPhysicsRep()->setTransform( mOwner->getTransform() );
|
getPhysicsRep()->setTransform(mOwner->getTransform());
|
||||||
|
|
||||||
setMaskBits(UpdateMask);
|
setMaskBits(UpdateMask);
|
||||||
}
|
}
|
||||||
|
|
@ -272,16 +287,15 @@ void PhysicsComponent::setPosition(const Point3F& pos)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
mat.setColumn(3,pos);
|
mat.setColumn(3, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
mOwner->setTransform(mat);
|
mOwner->setTransform(mat);
|
||||||
|
|
||||||
if ( getPhysicsRep() )
|
if (getPhysicsRep())
|
||||||
getPhysicsRep()->setTransform( mat );
|
getPhysicsRep()->setTransform(mat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PhysicsComponent::setRenderPosition(const Point3F& pos, F32 dt)
|
void PhysicsComponent::setRenderPosition(const Point3F& pos, F32 dt)
|
||||||
{
|
{
|
||||||
MatrixF mat = mOwner->getRenderTransform();
|
MatrixF mat = mOwner->getRenderTransform();
|
||||||
|
|
@ -291,16 +305,12 @@ void PhysicsComponent::setRenderPosition(const Point3F& pos, F32 dt)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
mat.setColumn(3,pos);
|
mat.setColumn(3, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
mOwner->setRenderTransform(mat);
|
mOwner->setRenderTransform(mat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsComponent::updateVelocity(const F32 dt)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysicsComponent::setVelocity(const VectorF& vel)
|
void PhysicsComponent::setVelocity(const VectorF& vel)
|
||||||
{
|
{
|
||||||
mVelocity = vel;
|
mVelocity = vel;
|
||||||
|
|
@ -310,6 +320,18 @@ void PhysicsComponent::setVelocity(const VectorF& vel)
|
||||||
setMaskBits(VelocityMask);
|
setMaskBits(VelocityMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Getters
|
||||||
|
PhysicsBody *PhysicsComponent::getPhysicsRep()
|
||||||
|
{
|
||||||
|
/*if(mOwner)
|
||||||
|
{
|
||||||
|
Entity* ac = dynamic_cast<Entity*>(mOwner);
|
||||||
|
if(ac)
|
||||||
|
return ac->mPhysicsRep;
|
||||||
|
}*/
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void PhysicsComponent::getVelocity(const Point3F& r, Point3F* v)
|
void PhysicsComponent::getVelocity(const Point3F& r, Point3F* v)
|
||||||
{
|
{
|
||||||
*v = mVelocity;
|
*v = mVelocity;
|
||||||
|
|
@ -339,20 +361,6 @@ F32 PhysicsComponent::getZeroImpulse(const Point3F& r,const Point3F& normal)
|
||||||
return 1 / ((1/mMass) + mDot(c, normal));
|
return 1 / ((1/mMass) + mDot(c, normal));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsComponent::accumulateForce(F32 dt, Point3F force)
|
|
||||||
{
|
|
||||||
mVelocity += force * dt;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysicsComponent::applyImpulse(const Point3F&,const VectorF& vec)
|
|
||||||
{
|
|
||||||
// Items ignore angular velocity
|
|
||||||
VectorF vel;
|
|
||||||
vel.x = vec.x / mMass;
|
|
||||||
vel.y = vec.y / mMass;
|
|
||||||
vel.z = vec.z / mMass;
|
|
||||||
setVelocity(mVelocity + vel);
|
|
||||||
}
|
|
||||||
|
|
||||||
DefineEngineMethod( PhysicsComponent, applyImpulse, bool, ( Point3F pos, VectorF vel ),,
|
DefineEngineMethod( PhysicsComponent, applyImpulse, bool, ( Point3F pos, VectorF vel ),,
|
||||||
"@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n"
|
"@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n"
|
||||||
|
|
@ -2,9 +2,10 @@
|
||||||
// Torque Game Engine
|
// Torque Game Engine
|
||||||
// Copyright (C) GarageGames.com, Inc.
|
// Copyright (C) GarageGames.com, Inc.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
#pragma once
|
||||||
|
#ifndef PHYSICS_COMPONENT_H
|
||||||
|
#define PHYSICS_COMPONENT_H
|
||||||
|
|
||||||
#ifndef _PHYSICSBEHAVIOR_H_
|
|
||||||
#define _PHYSICSBEHAVIOR_H_
|
|
||||||
#include "T3D/components/component.h"
|
#include "T3D/components/component.h"
|
||||||
|
|
||||||
#ifndef __RESOURCE_H__
|
#ifndef __RESOURCE_H__
|
||||||
|
|
@ -59,13 +60,17 @@ protected:
|
||||||
VectorF mGravity;
|
VectorF mGravity;
|
||||||
VectorF mVelocity;
|
VectorF mVelocity;
|
||||||
F32 mDrag;
|
F32 mDrag;
|
||||||
F32 mMass;
|
F32 mMass;
|
||||||
|
|
||||||
F32 mGravityMod;
|
F32 mGravityMod;
|
||||||
|
|
||||||
S32 csmAtRestTimer;
|
S32 csmAtRestTimer;
|
||||||
F32 sAtRestVelocity; // Min speed after collisio
|
F32 sAtRestVelocity; // Min speed after collisio
|
||||||
|
|
||||||
|
PhysicsBody* mPhysicsRep;
|
||||||
|
PhysicsWorld* mPhysicsWorld;
|
||||||
|
|
||||||
|
Convex* mConvexList;
|
||||||
public:
|
public:
|
||||||
enum MaskBits {
|
enum MaskBits {
|
||||||
PositionMask = Parent::NextFreeMask << 0,
|
PositionMask = Parent::NextFreeMask << 0,
|
||||||
|
|
@ -79,7 +84,7 @@ public:
|
||||||
{
|
{
|
||||||
Move move; ///< Last move from server
|
Move move; ///< Last move from server
|
||||||
F32 dt; ///< Last interpolation time
|
F32 dt; ///< Last interpolation time
|
||||||
// Interpolation data
|
// Interpolation data
|
||||||
Point3F pos;
|
Point3F pos;
|
||||||
Point3F posVec;
|
Point3F posVec;
|
||||||
QuatF rot[2];
|
QuatF rot[2];
|
||||||
|
|
@ -91,8 +96,11 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
StateDelta mDelta;
|
StateDelta mDelta;
|
||||||
|
|
||||||
S32 mPredictionCount; ///< Number of ticks to predict
|
S32 mPredictionCount; ///< Number of ticks to predict
|
||||||
|
|
||||||
|
ContainerQueryInfo mLastContainerInfo;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PhysicsComponent();
|
PhysicsComponent();
|
||||||
virtual ~PhysicsComponent();
|
virtual ~PhysicsComponent();
|
||||||
|
|
@ -100,36 +108,49 @@ public:
|
||||||
|
|
||||||
static void initPersistFields();
|
static void initPersistFields();
|
||||||
|
|
||||||
virtual void interpolateTick(F32 dt);
|
//Components
|
||||||
virtual void updatePos(const U32 /*mask*/, const F32 dt){}
|
virtual void onComponentAdd();
|
||||||
virtual void _updatePhysics();
|
virtual void onComponentRemove();
|
||||||
virtual PhysicsBody *getPhysicsRep();
|
|
||||||
|
|
||||||
|
//Setup
|
||||||
|
void prepCollision();
|
||||||
|
virtual void _updatePhysics();
|
||||||
|
virtual void buildConvex(const Box3F& box, Convex* convex);
|
||||||
|
|
||||||
|
//Update
|
||||||
|
virtual void interpolateTick(F32 dt);
|
||||||
|
virtual void updatePos(const F32 dt);
|
||||||
|
|
||||||
|
virtual void updateForces();
|
||||||
|
void updateContainer();
|
||||||
|
|
||||||
|
//Physics Collision Conveinence Hooks
|
||||||
|
virtual bool updateCollision(F32 dt, Rigid& ns, CollisionList &cList) { return false; }
|
||||||
|
virtual bool resolveContacts(Rigid& ns, CollisionList& cList, F32 dt) { return false; }
|
||||||
|
virtual bool resolveCollision(const Point3F& p, const Point3F &normal) { return false; }
|
||||||
|
|
||||||
|
//Networking
|
||||||
virtual U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream);
|
virtual U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream);
|
||||||
virtual void unpackUpdate(NetConnection *con, BitStream *stream);
|
virtual void unpackUpdate(NetConnection *con, BitStream *stream);
|
||||||
|
|
||||||
virtual void onComponentAdd();
|
//Events
|
||||||
|
|
||||||
void updateContainer();
|
|
||||||
|
|
||||||
virtual void updateVelocity(const F32 dt);
|
virtual void updateVelocity(const F32 dt);
|
||||||
virtual Point3F getVelocity() { return mVelocity; }
|
|
||||||
virtual void getOriginVector(const Point3F &p, Point3F* r);
|
|
||||||
virtual void getVelocity(const Point3F& r, Point3F* v);
|
|
||||||
virtual void setVelocity(const VectorF& vel);
|
virtual void setVelocity(const VectorF& vel);
|
||||||
virtual void setTransform(const MatrixF& mat);
|
virtual void setTransform(const MatrixF& mat);
|
||||||
virtual void setPosition(const Point3F& pos);
|
virtual void setPosition(const Point3F& pos);
|
||||||
void setRenderPosition(const Point3F& pos, F32 dt);
|
void setRenderPosition(const Point3F& pos, F32 dt);
|
||||||
|
|
||||||
virtual void applyImpulse(const Point3F&, const VectorF& vec);
|
virtual void applyImpulse(const Point3F&, const VectorF& vec);
|
||||||
virtual F32 getZeroImpulse(const Point3F& r, const Point3F& normal);
|
|
||||||
virtual void accumulateForce(F32 dt, Point3F force);
|
|
||||||
|
|
||||||
//Rigid Body Collision Conveinence Hooks
|
//Gets
|
||||||
virtual bool updateCollision(F32 dt, Rigid& ns, CollisionList &cList) { return false; }
|
F32 getMass() { return mMass; }
|
||||||
virtual bool resolveContacts(Rigid& ns, CollisionList& cList, F32 dt) { return false; }
|
virtual PhysicsBody *getPhysicsRep();
|
||||||
//virtual bool resolveCollision(Rigid& ns, CollisionList& cList) { return false; }
|
virtual Point3F getVelocity() { return mVelocity; }
|
||||||
virtual bool resolveCollision(const Point3F& p, const Point3F &normal) { return false; }
|
virtual void getOriginVector(const Point3F &p, Point3F* r);
|
||||||
|
virtual void getVelocity(const Point3F& r, Point3F* v);
|
||||||
|
virtual F32 getZeroImpulse(const Point3F& r, const Point3F& normal);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _COMPONENT_H_
|
#endif // _COMPONENT_H_
|
||||||
|
|
@ -37,7 +37,6 @@
|
||||||
#include "collision/collision.h"
|
#include "collision/collision.h"
|
||||||
#include "T3D/physics/physicsPlayer.h"
|
#include "T3D/physics/physicsPlayer.h"
|
||||||
#include "T3D/physics/physicsPlugin.h"
|
#include "T3D/physics/physicsPlugin.h"
|
||||||
#include "T3D/components/collision/collisionInterfaces.h"
|
|
||||||
#include "T3D/trigger.h"
|
#include "T3D/trigger.h"
|
||||||
#include "T3D/components/collision/collisionTrigger.h"
|
#include "T3D/components/collision/collisionTrigger.h"
|
||||||
|
|
||||||
|
|
@ -58,13 +57,8 @@ IMPLEMENT_CALLBACK(PlayerControllerComponent, updateMove, void, (PlayerControlle
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// Constructor/Destructor
|
// Constructor/Destructor
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
PlayerControllerComponent::PlayerControllerComponent() : Component()
|
PlayerControllerComponent::PlayerControllerComponent() : PhysicsComponent()
|
||||||
{
|
{
|
||||||
addComponentField("isStatic", "If enabled, object will not simulate physics", "bool", "0", "");
|
|
||||||
addComponentField("gravity", "The direction of gravity affecting this object, as a vector", "vector", "0 0 -9", "");
|
|
||||||
addComponentField("drag", "The drag coefficient that constantly affects the object", "float", "0.7", "");
|
|
||||||
addComponentField("mass", "The mass of the object", "float", "1", "");
|
|
||||||
|
|
||||||
mBuoyancy = 0.f;
|
mBuoyancy = 0.f;
|
||||||
mFriction = 0.3f;
|
mFriction = 0.3f;
|
||||||
mElasticity = 0.4f;
|
mElasticity = 0.4f;
|
||||||
|
|
@ -122,7 +116,7 @@ PlayerControllerComponent::PlayerControllerComponent() : Component()
|
||||||
mPhysicsRep = nullptr;
|
mPhysicsRep = nullptr;
|
||||||
mPhysicsWorld = nullptr;
|
mPhysicsWorld = nullptr;
|
||||||
|
|
||||||
mOwnerCollisionInterface = nullptr;
|
mOwnerCollisionComp = nullptr;
|
||||||
mIntegrationCount = 0;
|
mIntegrationCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -160,6 +154,13 @@ void PlayerControllerComponent::onComponentAdd()
|
||||||
{
|
{
|
||||||
Parent::onComponentAdd();
|
Parent::onComponentAdd();
|
||||||
|
|
||||||
|
CollisionComponent *collisionComp = mOwner->getComponent<CollisionComponent>();
|
||||||
|
if (collisionComp)
|
||||||
|
{
|
||||||
|
collisionComp->onCollisionChanged.notify(this, &PlayerControllerComponent::updatePhysics);
|
||||||
|
mOwnerCollisionComp = collisionComp;
|
||||||
|
}
|
||||||
|
|
||||||
updatePhysics();
|
updatePhysics();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -168,12 +169,11 @@ void PlayerControllerComponent::componentAddedToOwner(Component *comp)
|
||||||
if (comp->getId() == getId())
|
if (comp->getId() == getId())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//test if this is a shape component!
|
CollisionComponent *collisionComp = dynamic_cast<CollisionComponent*>(comp);
|
||||||
CollisionInterface *collisionInterface = dynamic_cast<CollisionInterface*>(comp);
|
if (collisionComp)
|
||||||
if (collisionInterface)
|
|
||||||
{
|
{
|
||||||
collisionInterface->onCollisionChanged.notify(this, &PlayerControllerComponent::updatePhysics);
|
collisionComp->onCollisionChanged.notify(this, &PlayerControllerComponent::updatePhysics);
|
||||||
mOwnerCollisionInterface = collisionInterface;
|
mOwnerCollisionComp = collisionComp;
|
||||||
updatePhysics();
|
updatePhysics();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -183,12 +183,11 @@ void PlayerControllerComponent::componentRemovedFromOwner(Component *comp)
|
||||||
if (comp->getId() == getId()) //?????????
|
if (comp->getId() == getId()) //?????????
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//test if this is a shape component!
|
CollisionComponent *collisionComp = dynamic_cast<CollisionComponent*>(comp);
|
||||||
CollisionInterface *collisionInterface = dynamic_cast<CollisionInterface*>(comp);
|
if (collisionComp)
|
||||||
if (collisionInterface)
|
|
||||||
{
|
{
|
||||||
collisionInterface->onCollisionChanged.remove(this, &PlayerControllerComponent::updatePhysics);
|
collisionComp->onCollisionChanged.notify(this, &PlayerControllerComponent::updatePhysics);
|
||||||
mOwnerCollisionInterface = NULL;
|
mOwnerCollisionComp = nullptr;
|
||||||
updatePhysics();
|
updatePhysics();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -219,7 +218,7 @@ void PlayerControllerComponent::initPersistFields()
|
||||||
Parent::initPersistFields();
|
Parent::initPersistFields();
|
||||||
|
|
||||||
addField("inputVelocity", TypePoint3F, Offset(mInputVelocity, PlayerControllerComponent), "");
|
addField("inputVelocity", TypePoint3F, Offset(mInputVelocity, PlayerControllerComponent), "");
|
||||||
addField("useDirectMoveInput", TypePoint3F, Offset(mUseDirectMoveInput, PlayerControllerComponent), "");
|
addField("useDirectMoveInput", TypeBool, Offset(mUseDirectMoveInput, PlayerControllerComponent), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
U32 PlayerControllerComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
|
U32 PlayerControllerComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
|
||||||
|
|
@ -579,10 +578,10 @@ void PlayerControllerComponent::updatePos(const F32 travelTime)
|
||||||
haveCollisions = true;
|
haveCollisions = true;
|
||||||
|
|
||||||
//TODO: clean this up so the phys component doesn't have to tell the col interface to do this
|
//TODO: clean this up so the phys component doesn't have to tell the col interface to do this
|
||||||
CollisionInterface* colInterface = mOwner->getComponent<CollisionInterface>();
|
CollisionComponent* colComp = mOwner->getComponent<CollisionComponent>();
|
||||||
if (colInterface)
|
if (colComp)
|
||||||
{
|
{
|
||||||
colInterface->handleCollisionList(collisionList, mVelocity);
|
colComp->handleCollisionList(collisionList, mVelocity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -629,6 +628,8 @@ void PlayerControllerComponent::updatePos(const F32 travelTime)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateContainer();
|
||||||
|
|
||||||
MatrixF newMat;
|
MatrixF newMat;
|
||||||
newMat.setPosition(newPos);
|
newMat.setPosition(newPos);
|
||||||
|
|
@ -701,6 +702,9 @@ void PlayerControllerComponent::findContact(bool *run, bool *jump, VectorF *cont
|
||||||
|
|
||||||
if (mContactInfo.contacted)
|
if (mContactInfo.contacted)
|
||||||
mContactInfo.contactNormal = *contactNormal;
|
mContactInfo.contactNormal = *contactNormal;
|
||||||
|
|
||||||
|
mContactInfo.run = *run;
|
||||||
|
mContactInfo.jump = *jump;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerControllerComponent::applyImpulse(const Point3F &pos, const VectorF &vec)
|
void PlayerControllerComponent::applyImpulse(const Point3F &pos, const VectorF &vec)
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,8 @@
|
||||||
#ifndef PLAYER_CONTORLLER_COMPONENT_H
|
#ifndef PLAYER_CONTORLLER_COMPONENT_H
|
||||||
#define PLAYER_CONTORLLER_COMPONENT_H
|
#define PLAYER_CONTORLLER_COMPONENT_H
|
||||||
|
|
||||||
#ifndef PHYSICSBEHAVIOR_H
|
#ifndef PHYSICS_COMPONENT_H
|
||||||
#include "T3D/components/physics/physicsBehavior.h"
|
#include "T3D/components/physics/physicsComponent.h"
|
||||||
#endif
|
#endif
|
||||||
#ifndef __RESOURCE_H__
|
#ifndef __RESOURCE_H__
|
||||||
#include "core/resource.h"
|
#include "core/resource.h"
|
||||||
|
|
@ -53,25 +53,20 @@
|
||||||
#ifndef _T3D_PHYSICS_PHYSICSWORLD_H_
|
#ifndef _T3D_PHYSICS_PHYSICSWORLD_H_
|
||||||
#include "T3D/physics/physicsWorld.h"
|
#include "T3D/physics/physicsWorld.h"
|
||||||
#endif
|
#endif
|
||||||
#ifndef PHYSICS_COMPONENT_INTERFACE_H
|
#ifndef COLLISION_COMPONENT_H
|
||||||
#include "T3D/components/physics/physicsComponentInterface.h"
|
#include "T3D/components/collision/collisionComponent.h"
|
||||||
#endif
|
|
||||||
#ifndef COLLISION_INTERFACES_H
|
|
||||||
#include "T3D/components/collision/collisionInterfaces.h"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class SceneRenderState;
|
class SceneRenderState;
|
||||||
class PhysicsWorld;
|
class PhysicsWorld;
|
||||||
class PhysicsPlayer;
|
class PhysicsPlayer;
|
||||||
class SimplePhysicsBehaviorInstance;
|
class SimplePhysicsBehaviorInstance;
|
||||||
class CollisionInterface;
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
class PlayerControllerComponent : public Component,
|
class PlayerControllerComponent : public PhysicsComponent
|
||||||
public PhysicsComponentInterface
|
|
||||||
{
|
{
|
||||||
typedef Component Parent;
|
typedef Component Parent;
|
||||||
|
|
||||||
|
|
@ -101,7 +96,7 @@ class PlayerControllerComponent : public Component,
|
||||||
PhysicsPlayer *mPhysicsRep;
|
PhysicsPlayer *mPhysicsRep;
|
||||||
PhysicsWorld *mPhysicsWorld;
|
PhysicsWorld *mPhysicsWorld;
|
||||||
|
|
||||||
CollisionInterface* mOwnerCollisionInterface;
|
CollisionComponent* mOwnerCollisionComp;
|
||||||
|
|
||||||
struct ContactInfo
|
struct ContactInfo
|
||||||
{
|
{
|
||||||
|
|
@ -113,8 +108,9 @@ class PlayerControllerComponent : public Component,
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
contacted = jump = run = false;
|
contacted = jump = run = false;
|
||||||
contactObject = NULL;
|
contactObject = nullptr;
|
||||||
contactNormal.set(1, 1, 1);
|
contactNormal.set(0,0,0);
|
||||||
|
contactTime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ContactInfo() { clear(); }
|
ContactInfo() { clear(); }
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ bool RigidBodyComponent::smNoSmoothing = false;
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// Constructor/Destructor
|
// Constructor/Destructor
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
RigidBodyComponent::RigidBodyComponent() : Component()
|
RigidBodyComponent::RigidBodyComponent() : PhysicsComponent()
|
||||||
{
|
{
|
||||||
mMass = 20;
|
mMass = 20;
|
||||||
mDynamicFriction = 1;
|
mDynamicFriction = 1;
|
||||||
|
|
@ -353,11 +353,11 @@ void RigidBodyComponent::findContact()
|
||||||
|
|
||||||
mPhysicsRep->findContact(&contactObject, contactNormal, &overlapObjects);
|
mPhysicsRep->findContact(&contactObject, contactNormal, &overlapObjects);
|
||||||
|
|
||||||
if (!overlapObjects.empty())
|
/*if (!overlapObjects.empty())
|
||||||
{
|
{
|
||||||
//fire our signal that the physics sim said collisions happened
|
//fire our signal that the physics sim said collisions happened
|
||||||
onPhysicsCollision.trigger(*contactNormal, overlapObjects);
|
onPhysicsCollision.trigger(*contactNormal, overlapObjects);
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void RigidBodyComponent::_onPhysicsReset(PhysicsResetEvent reset)
|
void RigidBodyComponent::_onPhysicsReset(PhysicsResetEvent reset)
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,8 @@
|
||||||
#ifndef COLLISION_COMPONENT_H
|
#ifndef COLLISION_COMPONENT_H
|
||||||
#include "T3D/components/collision/collisionComponent.h"
|
#include "T3D/components/collision/collisionComponent.h"
|
||||||
#endif
|
#endif
|
||||||
#ifndef PHYSICS_COMPONENT_INTERFACE_H
|
#ifndef PHYSICS_COMPONENT_H
|
||||||
#include "T3D/components/physics/physicsComponentInterface.h"
|
#include "T3D/components/physics/physicsComponent.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class PhysicsBody;
|
class PhysicsBody;
|
||||||
|
|
@ -42,9 +42,9 @@ class PhysicsBody;
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
class RigidBodyComponent : public Component, public PhysicsComponentInterface
|
class RigidBodyComponent : public PhysicsComponent
|
||||||
{
|
{
|
||||||
typedef Component Parent;
|
typedef PhysicsComponent Parent;
|
||||||
|
|
||||||
enum SimType
|
enum SimType
|
||||||
{
|
{
|
||||||
|
|
|
||||||
391
Engine/source/T3D/components/physics/simplePhysicsComponent.cpp
Normal file
391
Engine/source/T3D/components/physics/simplePhysicsComponent.cpp
Normal file
|
|
@ -0,0 +1,391 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Torque Game Engine
|
||||||
|
// Copyright (C) GarageGames.com, Inc.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "T3D/components/physics/simplePhysicsComponent.h"
|
||||||
|
#include "T3D/components/collision/collisionComponent.h"
|
||||||
|
#include "platform/platform.h"
|
||||||
|
#include "console/consoleTypes.h"
|
||||||
|
#include "core/util/safeDelete.h"
|
||||||
|
#include "core/resourceManager.h"
|
||||||
|
#include "core/stream/fileStream.h"
|
||||||
|
#include "console/consoleTypes.h"
|
||||||
|
#include "console/consoleObject.h"
|
||||||
|
#include "ts/tsShapeInstance.h"
|
||||||
|
#include "core/stream/bitStream.h"
|
||||||
|
#include "gfx/gfxTransformSaver.h"
|
||||||
|
#include "console/engineAPI.h"
|
||||||
|
#include "lighting/lightQuery.h"
|
||||||
|
#include "T3D/gameBase/gameConnection.h"
|
||||||
|
#include "collision/collision.h"
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Callbacks
|
||||||
|
IMPLEMENT_CALLBACK( SimplePhysicsComponent, updateMove, void, ( SimplePhysicsComponent* obj ), ( obj ),
|
||||||
|
"Called when the player updates it's movement, only called if object is set to callback in script(doUpdateMove).\n"
|
||||||
|
"@param obj the Player object\n" );
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor/Destructor
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
SimplePhysicsComponent::SimplePhysicsComponent() : PhysicsComponent()
|
||||||
|
{
|
||||||
|
mBuoyancy = 0.f;
|
||||||
|
mFriction = 0.3f;
|
||||||
|
mElasticity = 0.4f;
|
||||||
|
mMaxVelocity = 3000.f;
|
||||||
|
mSticky = false;
|
||||||
|
|
||||||
|
mDrag = 0.5;
|
||||||
|
|
||||||
|
mVelocity = Point3F::Zero;
|
||||||
|
|
||||||
|
moveSpeed = Point3F(1, 1, 1);
|
||||||
|
|
||||||
|
mFriendlyName = "Simple Physics";
|
||||||
|
mComponentType = "Physics";
|
||||||
|
|
||||||
|
mDescription = getDescriptionText("Simple physics Component that allows gravity and impulses.");
|
||||||
|
}
|
||||||
|
|
||||||
|
SimplePhysicsComponent::~SimplePhysicsComponent()
|
||||||
|
{
|
||||||
|
for(S32 i = 0;i < mFields.size();++i)
|
||||||
|
{
|
||||||
|
ComponentField &field = mFields[i];
|
||||||
|
SAFE_DELETE_ARRAY(field.mFieldDescription);
|
||||||
|
}
|
||||||
|
|
||||||
|
SAFE_DELETE_ARRAY(mDescription);
|
||||||
|
}
|
||||||
|
|
||||||
|
IMPLEMENT_CONOBJECT(SimplePhysicsComponent);
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool SimplePhysicsComponent::onAdd()
|
||||||
|
{
|
||||||
|
if(! Parent::onAdd())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimplePhysicsComponent::onRemove()
|
||||||
|
{
|
||||||
|
Parent::onRemove();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimplePhysicsComponent::initPersistFields()
|
||||||
|
{
|
||||||
|
Parent::initPersistFields();
|
||||||
|
|
||||||
|
addField( "moveSpeed", TypePoint3F, Offset(moveSpeed, SimplePhysicsComponent), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
U32 SimplePhysicsComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
|
||||||
|
{
|
||||||
|
U32 retMask = Parent::packUpdate(con, mask, stream);
|
||||||
|
return retMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimplePhysicsComponent::unpackUpdate(NetConnection *con, BitStream *stream)
|
||||||
|
{
|
||||||
|
Parent::unpackUpdate(con, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
void SimplePhysicsComponent::processTick()
|
||||||
|
{
|
||||||
|
Parent::processTick();
|
||||||
|
|
||||||
|
if (!isServerObject() || !isActive())
|
||||||
|
return;
|
||||||
|
|
||||||
|
//
|
||||||
|
//if (mCollisionObject && !--mCollisionTimeout)
|
||||||
|
// mCollisionObject = 0;
|
||||||
|
|
||||||
|
// Warp to catch up to server
|
||||||
|
if (mDelta.warpCount < mDelta.warpTicks)
|
||||||
|
{
|
||||||
|
mDelta.warpCount++;
|
||||||
|
|
||||||
|
// Set new pos.
|
||||||
|
mOwner->getTransform().getColumn(3,&mDelta.pos);
|
||||||
|
mDelta.pos += mDelta.warpOffset;
|
||||||
|
//mDelta.rot[0] = mDelta.rot[1];
|
||||||
|
//mDelta.rot[1].interpolate(mDelta.warpRot[0],mDelta.warpRot[1],F32(mDelta.warpCount)/mDelta.warpTicks);
|
||||||
|
MatrixF trans;
|
||||||
|
mDelta.rot[1].setMatrix(&trans);
|
||||||
|
trans.setPosition(mDelta.pos);
|
||||||
|
setTransform(trans);
|
||||||
|
|
||||||
|
// Pos backstepping
|
||||||
|
mDelta.posVec.x = -mDelta.warpOffset.x;
|
||||||
|
mDelta.posVec.y = -mDelta.warpOffset.y;
|
||||||
|
mDelta.posVec.z = -mDelta.warpOffset.z;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Save current rigid state interpolation
|
||||||
|
mDelta.posVec = mOwner->getPosition();
|
||||||
|
//mDelta.rot[0] = mOwner->getTransform();
|
||||||
|
|
||||||
|
updateForces();
|
||||||
|
updatePos(TickSec);
|
||||||
|
|
||||||
|
// Wrap up interpolation info
|
||||||
|
mDelta.pos = mOwner->getPosition();
|
||||||
|
mDelta.posVec -= mOwner->getPosition();
|
||||||
|
//mDelta.rot[1] = mRigid.angPosition;
|
||||||
|
|
||||||
|
// Update container database
|
||||||
|
setTransform(mOwner->getTransform());
|
||||||
|
setMaskBits(UpdateMask);
|
||||||
|
updateContainer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimplePhysicsComponent::interpolateTick(F32 dt)
|
||||||
|
{
|
||||||
|
// Client side interpolation
|
||||||
|
Point3F pos = mDelta.pos + mDelta.posVec * dt;
|
||||||
|
MatrixF mat = mOwner->getRenderTransform();
|
||||||
|
mat.setColumn(3,pos);
|
||||||
|
mOwner->setRenderTransform(mat);
|
||||||
|
mDelta.dt = dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimplePhysicsComponent::updatePos(const F32 travelTime)
|
||||||
|
{
|
||||||
|
mOwner->getTransform().getColumn(3,&mDelta.posVec);
|
||||||
|
|
||||||
|
// When mounted to another object, only Z rotation used.
|
||||||
|
if (mOwner->isMounted()) {
|
||||||
|
mVelocity = mOwner->getObjectMount()->getVelocity();
|
||||||
|
setPosition(Point3F(0.0f, 0.0f, 0.0f));
|
||||||
|
setMaskBits(UpdateMask);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Point3F newPos;
|
||||||
|
|
||||||
|
if ( mVelocity.isZero() )
|
||||||
|
newPos = mDelta.posVec;
|
||||||
|
else
|
||||||
|
newPos = _move( travelTime );
|
||||||
|
//}
|
||||||
|
|
||||||
|
// Set new position
|
||||||
|
// If on the client, calc delta for backstepping
|
||||||
|
if (isClientObject())
|
||||||
|
{
|
||||||
|
mDelta.pos = newPos;
|
||||||
|
mDelta.posVec = mDelta.posVec - mDelta.pos;
|
||||||
|
mDelta.dt = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
setPosition( newPos );
|
||||||
|
setMaskBits( UpdateMask );
|
||||||
|
updateContainer();
|
||||||
|
|
||||||
|
/*if (!isGhost())
|
||||||
|
{
|
||||||
|
// Do mission area callbacks on the server as well
|
||||||
|
checkMissionArea();
|
||||||
|
}*/
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Point3F SimplePhysicsComponent::_move( const F32 travelTime )
|
||||||
|
{
|
||||||
|
// Try and move to new pos
|
||||||
|
F32 totalMotion = 0.0f;
|
||||||
|
|
||||||
|
Point3F start;
|
||||||
|
Point3F initialPosition;
|
||||||
|
mOwner->getTransform().getColumn(3,&start);
|
||||||
|
initialPosition = start;
|
||||||
|
|
||||||
|
VectorF firstNormal(0.0f, 0.0f, 0.0f);
|
||||||
|
//F32 maxStep = mDataBlock->maxStepHeight;
|
||||||
|
F32 time = travelTime;
|
||||||
|
U32 count = 0;
|
||||||
|
S32 sMoveRetryCount = 5;
|
||||||
|
|
||||||
|
CollisionComponent* colComp = mOwner->getComponent<CollisionComponent>();
|
||||||
|
|
||||||
|
if(!colComp)
|
||||||
|
return start + mVelocity * time;
|
||||||
|
|
||||||
|
colComp->clearCollisionList();
|
||||||
|
|
||||||
|
for (; count < sMoveRetryCount; count++)
|
||||||
|
{
|
||||||
|
F32 speed = mVelocity.len();
|
||||||
|
if (!speed)
|
||||||
|
break;
|
||||||
|
|
||||||
|
Point3F end = start + mVelocity * time;
|
||||||
|
Point3F distance = end - start;
|
||||||
|
|
||||||
|
bool collided = colComp->checkCollisions(time, &mVelocity, start);
|
||||||
|
|
||||||
|
if (colComp->getCollisionList()->getCount() != 0 && colComp->getCollisionList()->getTime() < 1.0f)
|
||||||
|
{
|
||||||
|
// Set to collision point
|
||||||
|
F32 velLen = mVelocity.len();
|
||||||
|
|
||||||
|
F32 dt = time * getMin(colComp->getCollisionList()->getTime(), 1.0f);
|
||||||
|
start += mVelocity * dt;
|
||||||
|
time -= dt;
|
||||||
|
|
||||||
|
totalMotion += velLen * dt;
|
||||||
|
|
||||||
|
// Back off...
|
||||||
|
if ( velLen > 0.f )
|
||||||
|
{
|
||||||
|
F32 newT = getMin(0.01f / velLen, dt);
|
||||||
|
start -= mVelocity * newT;
|
||||||
|
totalMotion -= velLen * newT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pick the surface most parallel to the face that was hit.
|
||||||
|
U32 colCount = colComp->getCollisionList()->getCount();
|
||||||
|
|
||||||
|
const Collision *collision = colComp->getCollision(0);
|
||||||
|
const Collision *cp = collision + 1;
|
||||||
|
const Collision *ep = collision + colComp->getCollisionList()->getCount();
|
||||||
|
for (; cp != ep; cp++)
|
||||||
|
{
|
||||||
|
U32 colCountLoop = colComp->getCollisionList()->getCount();
|
||||||
|
|
||||||
|
//TODO: Move this somewhere else
|
||||||
|
if(Entity* colEnt = dynamic_cast<Entity*>(collision->object))
|
||||||
|
{
|
||||||
|
if(CollisionComponent *collidingEntityColComp = colEnt->getComponent<CollisionComponent>())
|
||||||
|
{
|
||||||
|
if(!collidingEntityColComp->doesBlockColliding())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cp->faceDot > collision->faceDot)
|
||||||
|
collision = cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
//check the last/first one just incase
|
||||||
|
if(Entity* colEnt = dynamic_cast<Entity*>(collision->object))
|
||||||
|
{
|
||||||
|
if(CollisionComponent *collidingEntityColComp = colEnt->getComponent<CollisionComponent>())
|
||||||
|
{
|
||||||
|
if(!collidingEntityColComp->doesBlockColliding())
|
||||||
|
{
|
||||||
|
//if our ideal surface doesn't stop us, just move along
|
||||||
|
return start + mVelocity * time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//F32 bd = _doCollisionImpact( collision, wasFalling );
|
||||||
|
F32 bd = -mDot( mVelocity, collision->normal);
|
||||||
|
|
||||||
|
// Subtract out velocity
|
||||||
|
F32 sNormalElasticity = 0.01f;
|
||||||
|
VectorF dv = collision->normal * (bd + sNormalElasticity);
|
||||||
|
mVelocity += dv;
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
firstNormal = collision->normal;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (count == 1)
|
||||||
|
{
|
||||||
|
// Re-orient velocity along the crease.
|
||||||
|
if (mDot(dv,firstNormal) < 0.0f &&
|
||||||
|
mDot(collision->normal,firstNormal) < 0.0f)
|
||||||
|
{
|
||||||
|
VectorF nv;
|
||||||
|
mCross(collision->normal,firstNormal,&nv);
|
||||||
|
F32 nvl = nv.len();
|
||||||
|
if (nvl)
|
||||||
|
{
|
||||||
|
if (mDot(nv,mVelocity) < 0.0f)
|
||||||
|
nvl = -nvl;
|
||||||
|
nv *= mVelocity.len() / nvl;
|
||||||
|
mVelocity = nv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
totalMotion += (end - start).len();
|
||||||
|
start = end;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
U32 colCountThree = colComp->getCollisionList()->getCount();
|
||||||
|
|
||||||
|
if (colCountThree != 0)
|
||||||
|
bool derp = true;
|
||||||
|
|
||||||
|
if (count == sMoveRetryCount)
|
||||||
|
{
|
||||||
|
// Failed to move
|
||||||
|
start = initialPosition;
|
||||||
|
mVelocity.set(0.0f, 0.0f, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimplePhysicsComponent::updateForces()
|
||||||
|
{
|
||||||
|
// Acceleration due to gravity
|
||||||
|
mVelocity += (mGravity * mGravityMod) * TickMs;
|
||||||
|
F32 len = mVelocity.len();
|
||||||
|
|
||||||
|
if (mMaxVelocity > 0 && mAbs(len) > mMaxVelocity)
|
||||||
|
{
|
||||||
|
Point3F excess = mVelocity * (1.0 - (mMaxVelocity / len));
|
||||||
|
excess *= 0.1f;
|
||||||
|
mVelocity -= excess;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Container buoyancy & drag
|
||||||
|
if(mOwner->getContainerInfo().waterCoverage > 0.65f)
|
||||||
|
mVelocity -= mBuoyancy * (mGravity * mGravityMod) * TickMs;
|
||||||
|
|
||||||
|
mVelocity -= mVelocity * mDrag * TickMs;
|
||||||
|
|
||||||
|
if( mVelocity.isZero() )
|
||||||
|
mVelocity = Point3F::Zero;
|
||||||
|
else
|
||||||
|
setMaskBits(VelocityMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
void SimplePhysicsComponent::setVelocity(const VectorF& vel)
|
||||||
|
{
|
||||||
|
Parent::setVelocity(vel);
|
||||||
|
|
||||||
|
// Clamp against the maximum velocity.
|
||||||
|
if ( mMaxVelocity > 0 )
|
||||||
|
{
|
||||||
|
F32 len = mVelocity.magnitudeSafe();
|
||||||
|
if ( len > mMaxVelocity )
|
||||||
|
{
|
||||||
|
Point3F excess = mVelocity * ( 1.0f - (mMaxVelocity / len ) );
|
||||||
|
mVelocity -= excess;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Torque Game Engine
|
||||||
|
// Copyright (C) GarageGames.com, Inc.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef SIMPLE_PHYSICS_COMPONENT_H
|
||||||
|
#define SIMPLE_PHYSICS_COMPONENT_H
|
||||||
|
|
||||||
|
#ifndef PHYSICS_COMPONENT_H
|
||||||
|
#include "T3D/components/physics/physicsComponent.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __RESOURCE_H__
|
||||||
|
#include "core/resource.h"
|
||||||
|
#endif
|
||||||
|
#ifndef _TSSHAPE_H_
|
||||||
|
#include "ts/tsShape.h"
|
||||||
|
#endif
|
||||||
|
#ifndef _SCENERENDERSTATE_H_
|
||||||
|
#include "scene/sceneRenderState.h"
|
||||||
|
#endif
|
||||||
|
#ifndef _MBOX_H_
|
||||||
|
#include "math/mBox.h"
|
||||||
|
#endif
|
||||||
|
#ifndef _ENTITY_H_
|
||||||
|
#include "T3D/Entity.h"
|
||||||
|
#endif
|
||||||
|
#ifndef _CONVEX_H_
|
||||||
|
#include "collision/convex.h"
|
||||||
|
#endif
|
||||||
|
#ifndef _BOXCONVEX_H_
|
||||||
|
#include "collision/boxConvex.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class SceneRenderState;
|
||||||
|
class PhysicsBody;
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
///
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
class SimplePhysicsComponent : public PhysicsComponent
|
||||||
|
{
|
||||||
|
typedef PhysicsComponent Parent;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
F32 mBuoyancy;
|
||||||
|
F32 mFriction;
|
||||||
|
F32 mElasticity;
|
||||||
|
F32 mMaxVelocity;
|
||||||
|
bool mSticky;
|
||||||
|
|
||||||
|
U32 mIntegrationCount;
|
||||||
|
|
||||||
|
Point3F moveSpeed;
|
||||||
|
|
||||||
|
Point3F mStickyCollisionPos;
|
||||||
|
Point3F mStickyCollisionNormal;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SimplePhysicsComponent();
|
||||||
|
virtual ~SimplePhysicsComponent();
|
||||||
|
DECLARE_CONOBJECT(SimplePhysicsComponent);
|
||||||
|
|
||||||
|
virtual bool onAdd();
|
||||||
|
virtual void onRemove();
|
||||||
|
static void initPersistFields();
|
||||||
|
|
||||||
|
virtual U32 packUpdate(NetConnection *con, U32 mask, BitStream *stream);
|
||||||
|
virtual void unpackUpdate(NetConnection *con, BitStream *stream);
|
||||||
|
|
||||||
|
virtual void processTick();
|
||||||
|
virtual void interpolateTick(F32 dt);
|
||||||
|
virtual void updatePos(const F32 dt);
|
||||||
|
void updateForces();
|
||||||
|
|
||||||
|
void updateMove(const Move* move);
|
||||||
|
Point3F _move(const F32 travelTime);
|
||||||
|
|
||||||
|
//virtual void onComponentRemove();
|
||||||
|
|
||||||
|
virtual VectorF getVelocity() { return mVelocity; }
|
||||||
|
virtual void setVelocity(const VectorF& vel);
|
||||||
|
|
||||||
|
//
|
||||||
|
DECLARE_CALLBACK(void, updateMove, (SimplePhysicsComponent* obj));
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _COMPONENT_H_
|
||||||
|
|
@ -45,21 +45,10 @@
|
||||||
#include "core/strings/findMatch.h"
|
#include "core/strings/findMatch.h"
|
||||||
#include "T3D/components/render/meshComponent_ScriptBinding.h"
|
#include "T3D/components/render/meshComponent_ScriptBinding.h"
|
||||||
|
|
||||||
ImplementEnumType(BatchingMode,
|
|
||||||
"Type of mesh data available in a shape.\n"
|
|
||||||
"@ingroup gameObjects")
|
|
||||||
{
|
|
||||||
MeshComponent::Individual, "Individual", "This mesh is rendered indivudally, wthout batching or instancing."
|
|
||||||
},
|
|
||||||
{ MeshComponent::StaticBatch, "Static Batching", "Statically batches this mesh together with others to reduce drawcalls." },
|
|
||||||
//{ MeshComponent::DynamicBatch, "Dynamic Batching", "Dynamical batches this mesh together with others to reduce drawcalls each frame." },
|
|
||||||
// { MeshComponent::Instanced, "Instanced", "This mesh is rendered as an instance, reducing draw overhead with others that share the same mesh and material." },
|
|
||||||
EndImplementEnumType;
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// Constructor/Destructor
|
// Constructor/Destructor
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
MeshComponent::MeshComponent() : Component(), mShape(nullptr), mRenderMode(Individual)
|
MeshComponent::MeshComponent() : Component(), mShape(nullptr)
|
||||||
{
|
{
|
||||||
mFriendlyName = "Mesh Component";
|
mFriendlyName = "Mesh Component";
|
||||||
mComponentType = "Render";
|
mComponentType = "Render";
|
||||||
|
|
@ -75,8 +64,6 @@ MeshComponent::MeshComponent() : Component(), mShape(nullptr), mRenderMode(Indiv
|
||||||
mMeshAssetId = StringTable->EmptyString();
|
mMeshAssetId = StringTable->EmptyString();
|
||||||
|
|
||||||
mInterfaceData = new MeshRenderSystemInterface();
|
mInterfaceData = new MeshRenderSystemInterface();
|
||||||
|
|
||||||
mRenderMode = Individual;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshComponent::~MeshComponent()
|
MeshComponent::~MeshComponent()
|
||||||
|
|
@ -134,14 +121,9 @@ void MeshComponent::initPersistFields()
|
||||||
{
|
{
|
||||||
Parent::initPersistFields();
|
Parent::initPersistFields();
|
||||||
|
|
||||||
addGroup("Rendering");
|
|
||||||
addField("BatchingMode", TypeBatchingMode, Offset(mRenderMode, MeshComponent),
|
|
||||||
"The mode of batching this shape should be rendered with.");
|
|
||||||
endGroup("Rendering");
|
|
||||||
|
|
||||||
//create a hook to our internal variables
|
//create a hook to our internal variables
|
||||||
addGroup("Model");
|
addGroup("Model");
|
||||||
addProtectedField("MeshAsset", TypeShapeAssetPtr, Offset(mShapeAsset, MeshComponent), &_setMesh, &defaultProtectedGetFn,
|
addProtectedField("MeshAsset", TypeShapeAssetPtr, Offset(mShapeAsset, MeshComponent), &_setMesh, &defaultProtectedGetFn, &writeShape,
|
||||||
"The asset Id used for the mesh.", AbstractClassRep::FieldFlags::FIELD_ComponentInspectors);
|
"The asset Id used for the mesh.", AbstractClassRep::FieldFlags::FIELD_ComponentInspectors);
|
||||||
endGroup("Model");
|
endGroup("Model");
|
||||||
}
|
}
|
||||||
|
|
@ -182,6 +164,8 @@ bool MeshComponent::setMeshAsset(const char* assetName)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mMeshAsset->onShapeChanged.notify(this, &MeshComponent::_shapeAssetUpdated);
|
||||||
|
|
||||||
mShapeName = mMeshAssetId;
|
mShapeName = mMeshAssetId;
|
||||||
mShapeAsset = mShapeName;
|
mShapeAsset = mShapeName;
|
||||||
updateShape(); //make sure we force the update to resize the owner bounds
|
updateShape(); //make sure we force the update to resize the owner bounds
|
||||||
|
|
@ -190,6 +174,11 @@ bool MeshComponent::setMeshAsset(const char* assetName)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MeshComponent::_shapeAssetUpdated(ShapeAsset* asset)
|
||||||
|
{
|
||||||
|
updateShape();
|
||||||
|
}
|
||||||
|
|
||||||
void MeshComponent::updateShape()
|
void MeshComponent::updateShape()
|
||||||
{
|
{
|
||||||
if (mInterfaceData == nullptr)
|
if (mInterfaceData == nullptr)
|
||||||
|
|
@ -197,7 +186,6 @@ void MeshComponent::updateShape()
|
||||||
|
|
||||||
//if ((mShapeName && mShapeName[0] != '\0') || (mShapeAsset && mShapeAsset[0] != '\0'))
|
//if ((mShapeName && mShapeName[0] != '\0') || (mShapeAsset && mShapeAsset[0] != '\0'))
|
||||||
if ((mShapeName && mShapeName[0] != '\0') || (mMeshAssetId && mMeshAssetId[0] != '\0'))
|
if ((mShapeName && mShapeName[0] != '\0') || (mMeshAssetId && mMeshAssetId[0] != '\0'))
|
||||||
|
|
||||||
{
|
{
|
||||||
if (mMeshAsset == NULL)
|
if (mMeshAsset == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
@ -210,7 +198,7 @@ void MeshComponent::updateShape()
|
||||||
setupShape();
|
setupShape();
|
||||||
|
|
||||||
//Do this on both the server and client
|
//Do this on both the server and client
|
||||||
S32 materialCount = mMeshAsset->getShape()->materialList->getMaterialNameList().size();
|
S32 materialCount = mMeshAsset->getShape()->materialList->getMaterialNameList().size(); //mMeshAsset->getMaterialCount();
|
||||||
|
|
||||||
if (isServerObject())
|
if (isServerObject())
|
||||||
{
|
{
|
||||||
|
|
@ -234,13 +222,21 @@ void MeshComponent::updateShape()
|
||||||
|
|
||||||
for (U32 i = 0; i < materialCount; i++)
|
for (U32 i = 0; i < materialCount; i++)
|
||||||
{
|
{
|
||||||
String materialname = mMeshAsset->getShape()->materialList->getMaterialName(i);
|
StringTableEntry materialname = StringTable->insert(mMeshAsset->getShape()->materialList->getMaterialName(i).c_str());
|
||||||
if (materialname == String("ShapeBounds"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
dSprintf(matFieldName, 128, "MaterialSlot%d", i);
|
//Iterate through our assetList to find the compliant entry in our matList
|
||||||
|
for (U32 m = 0; m < mMeshAsset->getMaterialCount(); m++)
|
||||||
|
{
|
||||||
|
AssetPtr<MaterialAsset> matAsset = mMeshAsset->getMaterialAsset(m);
|
||||||
|
|
||||||
addComponentField(matFieldName, "A material used in the shape file", "Material", materialname, "");
|
if (matAsset->getMaterialDefinitionName() == materialname)
|
||||||
|
{
|
||||||
|
dSprintf(matFieldName, 128, "MaterialSlot%d", i);
|
||||||
|
|
||||||
|
addComponentField(matFieldName, "A material used in the shape file", "Material", matAsset->getAssetId(), "");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (materialCount > 0)
|
if (materialCount > 0)
|
||||||
|
|
@ -272,27 +268,6 @@ void MeshComponent::updateShape()
|
||||||
mOwner->getSceneManager()->notifyObjectDirty(mOwner);
|
mOwner->getSceneManager()->notifyObjectDirty(mOwner);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isClientObject() && mInterfaceData)
|
|
||||||
{
|
|
||||||
if (mRenderMode == StaticBatch)
|
|
||||||
{
|
|
||||||
mInterfaceData->mStatic = true;
|
|
||||||
|
|
||||||
OptimizedPolyList geom;
|
|
||||||
MatrixF transform = mInterfaceData->mTransform;
|
|
||||||
mInterfaceData->mGeometry.setTransform(&transform, mInterfaceData->mScale);
|
|
||||||
mInterfaceData->mGeometry.setObject(mOwner);
|
|
||||||
|
|
||||||
mInterfaceData->mShapeInstance->buildPolyList(&mInterfaceData->mGeometry, 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mInterfaceData->mStatic = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
MeshRenderSystem::rebuildBuffers();
|
|
||||||
}
|
|
||||||
|
|
||||||
//finally, notify that our shape was changed
|
//finally, notify that our shape was changed
|
||||||
onShapeInstanceChanged.trigger(this);
|
onShapeInstanceChanged.trigger(this);
|
||||||
}
|
}
|
||||||
|
|
@ -305,6 +280,8 @@ void MeshComponent::setupShape()
|
||||||
|
|
||||||
void MeshComponent::_onResourceChanged( const Torque::Path &path )
|
void MeshComponent::_onResourceChanged( const Torque::Path &path )
|
||||||
{
|
{
|
||||||
|
/*bool srv = isServerObject();
|
||||||
|
|
||||||
if (mInterfaceData == nullptr)
|
if (mInterfaceData == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -316,7 +293,7 @@ void MeshComponent::_onResourceChanged( const Torque::Path &path )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
updateShape();
|
updateShape();
|
||||||
setMaskBits(ShapeMask);
|
setMaskBits(ShapeMask);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshComponent::inspectPostApply()
|
void MeshComponent::inspectPostApply()
|
||||||
|
|
@ -343,8 +320,6 @@ U32 MeshComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
|
||||||
if (stream->writeFlag(mask & ShapeMask))
|
if (stream->writeFlag(mask & ShapeMask))
|
||||||
{
|
{
|
||||||
stream->writeString(mShapeName);
|
stream->writeString(mShapeName);
|
||||||
|
|
||||||
stream->writeInt(mRenderMode, 8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stream->writeFlag( mask & MaterialMask ))
|
if (stream->writeFlag( mask & MaterialMask ))
|
||||||
|
|
@ -373,7 +348,6 @@ void MeshComponent::unpackUpdate(NetConnection *con, BitStream *stream)
|
||||||
{
|
{
|
||||||
mShapeName = stream->readSTString();
|
mShapeName = stream->readSTString();
|
||||||
|
|
||||||
mRenderMode = (RenderMode)stream->readInt(8);
|
|
||||||
setMeshAsset(mShapeName);
|
setMeshAsset(mShapeName);
|
||||||
updateShape();
|
updateShape();
|
||||||
}
|
}
|
||||||
|
|
@ -460,28 +434,34 @@ void MeshComponent::updateMaterials()
|
||||||
TSMaterialList* pMatList = mInterfaceData->mShapeInstance->getMaterialList();
|
TSMaterialList* pMatList = mInterfaceData->mShapeInstance->getMaterialList();
|
||||||
pMatList->setTextureLookupPath(getShapeResource().getPath().getPath());
|
pMatList->setTextureLookupPath(getShapeResource().getPath().getPath());
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
const Vector<String> &materialNames = pMatList->getMaterialNameList();
|
const Vector<String> &materialNames = pMatList->getMaterialNameList();
|
||||||
for ( S32 i = 0; i < materialNames.size(); i++ )
|
for ( S32 i = 0; i < materialNames.size(); i++ )
|
||||||
{
|
{
|
||||||
|
if (found)
|
||||||
|
break;
|
||||||
|
|
||||||
for(U32 m=0; m < mChangingMaterials.size(); m++)
|
for(U32 m=0; m < mChangingMaterials.size(); m++)
|
||||||
{
|
{
|
||||||
if(mChangingMaterials[m].slot == i)
|
if(mChangingMaterials[m].slot == i)
|
||||||
{
|
{
|
||||||
//Fetch the actual material asset
|
//Fetch the actual material asset
|
||||||
pMatList->renameMaterial( i, mChangingMaterials[m].matAsset->getMaterialDefinitionName());
|
pMatList->renameMaterial( i, mChangingMaterials[m].matAsset->getMaterialDefinitionName());
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mChangingMaterials.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mChangingMaterials.clear();
|
||||||
|
|
||||||
// Initialize the material instances
|
// Initialize the material instances
|
||||||
mInterfaceData->mShapeInstance->initMaterialList();
|
mInterfaceData->mShapeInstance->initMaterialList();
|
||||||
}
|
}
|
||||||
|
|
||||||
MatrixF MeshComponent::getNodeTransform(S32 nodeIdx)
|
MatrixF MeshComponent::getNodeTransform(S32 nodeIdx)
|
||||||
{
|
{
|
||||||
if (mInterfaceData != nullptr && mMeshAsset->getShape())
|
if (mInterfaceData != nullptr && !mMeshAsset.isNull() && mMeshAsset->isAssetValid() && mMeshAsset->getShape())
|
||||||
{
|
{
|
||||||
S32 nodeCount = getShape()->nodes.size();
|
S32 nodeCount = getShape()->nodes.size();
|
||||||
|
|
||||||
|
|
@ -589,7 +569,6 @@ void MeshComponent::onDynamicModified(const char* slotName, const char* newValue
|
||||||
|
|
||||||
void MeshComponent::changeMaterial(U32 slot, MaterialAsset* newMat)
|
void MeshComponent::changeMaterial(U32 slot, MaterialAsset* newMat)
|
||||||
{
|
{
|
||||||
|
|
||||||
char fieldName[512];
|
char fieldName[512];
|
||||||
|
|
||||||
//update our respective field
|
//update our respective field
|
||||||
|
|
@ -629,4 +608,4 @@ void MeshComponent::ownerTransformSet(MatrixF *mat)
|
||||||
MatrixF newTransform = *mat;
|
MatrixF newTransform = *mat;
|
||||||
mInterfaceData->mTransform = newTransform;
|
mInterfaceData->mTransform = newTransform;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -101,18 +101,6 @@ protected:
|
||||||
Vector<matMap> mChangingMaterials;
|
Vector<matMap> mChangingMaterials;
|
||||||
Vector<matMap> mMaterials;
|
Vector<matMap> mMaterials;
|
||||||
|
|
||||||
public:
|
|
||||||
enum RenderMode
|
|
||||||
{
|
|
||||||
Individual = 0,
|
|
||||||
DynamicBatch,
|
|
||||||
StaticBatch,
|
|
||||||
Instanced
|
|
||||||
};
|
|
||||||
|
|
||||||
protected:
|
|
||||||
RenderMode mRenderMode;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
StringTableEntry mMeshAssetId;
|
StringTableEntry mMeshAssetId;
|
||||||
AssetPtr<ShapeAsset> mMeshAsset;
|
AssetPtr<ShapeAsset> mMeshAsset;
|
||||||
|
|
@ -144,6 +132,8 @@ public:
|
||||||
void updateShape();
|
void updateShape();
|
||||||
void updateMaterials();
|
void updateMaterials();
|
||||||
|
|
||||||
|
void _shapeAssetUpdated(ShapeAsset* asset);
|
||||||
|
|
||||||
virtual void onComponentRemove();
|
virtual void onComponentRemove();
|
||||||
virtual void onComponentAdd();
|
virtual void onComponentAdd();
|
||||||
|
|
||||||
|
|
@ -153,6 +143,8 @@ public:
|
||||||
static bool _setShape(void *object, const char *index, const char *data);
|
static bool _setShape(void *object, const char *index, const char *data);
|
||||||
const char* _getShape(void *object, const char *data);
|
const char* _getShape(void *object, const char *data);
|
||||||
|
|
||||||
|
static bool writeShape(void* obj, StringTableEntry pFieldName) { return static_cast<MeshComponent*>(obj)->mMeshAsset.notNull(); }
|
||||||
|
|
||||||
bool setMeshAsset(const char* assetName);
|
bool setMeshAsset(const char* assetName);
|
||||||
|
|
||||||
virtual TSShape* getShape() { if (mMeshAsset) return mMeshAsset->getShape(); else return NULL; }
|
virtual TSShape* getShape() { if (mMeshAsset) return mMeshAsset->getShape(); else return NULL; }
|
||||||
|
|
@ -186,7 +178,4 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef MeshComponent::RenderMode BatchingMode;
|
|
||||||
DefineEnumType(BatchingMode);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@
|
||||||
|
|
||||||
#include "T3D/components/coreInterfaces.h"
|
#include "T3D/components/coreInterfaces.h"
|
||||||
#include "T3D/components/render/renderComponentInterface.h"
|
#include "T3D/components/render/renderComponentInterface.h"
|
||||||
#include "T3D/components/collision/collisionInterfaces.h"
|
#include "T3D/components/collision/collisionComponent.h"
|
||||||
|
|
||||||
#include "gui/controls/guiTreeViewCtrl.h"
|
#include "gui/controls/guiTreeViewCtrl.h"
|
||||||
#include "assets/assetManager.h"
|
#include "assets/assetManager.h"
|
||||||
|
|
@ -1123,8 +1123,8 @@ bool Entity::buildPolyList(PolyListContext context, AbstractPolyList* polyList,
|
||||||
|
|
||||||
void Entity::buildConvex(const Box3F& box, Convex* convex)
|
void Entity::buildConvex(const Box3F& box, Convex* convex)
|
||||||
{
|
{
|
||||||
Vector<BuildConvexInterface*> updaters = getComponents<BuildConvexInterface>();
|
Vector<CollisionComponent*> colliders = getComponents<CollisionComponent>();
|
||||||
for (Vector<BuildConvexInterface*>::iterator it = updaters.begin(); it != updaters.end(); it++)
|
for (Vector<CollisionComponent*>::iterator it = colliders.begin(); it != colliders.end(); it++)
|
||||||
{
|
{
|
||||||
(*it)->buildConvex(box, convex);
|
(*it)->buildConvex(box, convex);
|
||||||
}
|
}
|
||||||
|
|
@ -1398,10 +1398,7 @@ void Entity::clearComponents(bool deleteComponents)
|
||||||
{
|
{
|
||||||
comp->onComponentRemove(); //in case the behavior needs to do cleanup on the owner
|
comp->onComponentRemove(); //in case the behavior needs to do cleanup on the owner
|
||||||
|
|
||||||
//we only need to delete them on the server side. they'll be cleaned up on the client side
|
comp->deleteObject();
|
||||||
//via the ghosting system for us
|
|
||||||
if (isServerObject())
|
|
||||||
comp->deleteObject();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1915,12 +1912,9 @@ DefineEngineMethod(Entity, getMoveVector, VectorF, (),,
|
||||||
"Get the number of static fields on the object.\n"
|
"Get the number of static fields on the object.\n"
|
||||||
"@return The number of static fields defined on the object.")
|
"@return The number of static fields defined on the object.")
|
||||||
{
|
{
|
||||||
if (object->getControllingClient() != NULL)
|
//fetch our last move
|
||||||
{
|
if (object->lastMove.x != 0 || object->lastMove.y != 0 || object->lastMove.z != 0)
|
||||||
//fetch our last move
|
return VectorF(object->lastMove.x, object->lastMove.y, object->lastMove.z);
|
||||||
if (object->lastMove.x != 0 || object->lastMove.y != 0 || object->lastMove.z != 0)
|
|
||||||
return VectorF(object->lastMove.x, object->lastMove.y, object->lastMove.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
return VectorF::Zero;
|
return VectorF::Zero;
|
||||||
}
|
}
|
||||||
|
|
@ -1929,12 +1923,9 @@ DefineEngineMethod(Entity, getMoveRotation, VectorF, (), ,
|
||||||
"Get the number of static fields on the object.\n"
|
"Get the number of static fields on the object.\n"
|
||||||
"@return The number of static fields defined on the object.")
|
"@return The number of static fields defined on the object.")
|
||||||
{
|
{
|
||||||
if(object->getControllingClient() != NULL)
|
//fetch our last move
|
||||||
{
|
if (object->lastMove.pitch != 0 || object->lastMove.roll != 0 || object->lastMove.yaw != 0)
|
||||||
//fetch our last move
|
return VectorF(object->lastMove.pitch, object->lastMove.roll, object->lastMove.yaw);
|
||||||
if (object->lastMove.pitch != 0 || object->lastMove.roll != 0 || object->lastMove.yaw != 0)
|
|
||||||
return VectorF(object->lastMove.pitch, object->lastMove.roll, object->lastMove.yaw);
|
|
||||||
}
|
|
||||||
|
|
||||||
return VectorF::Zero;
|
return VectorF::Zero;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -207,7 +207,7 @@ public:
|
||||||
//Components
|
//Components
|
||||||
virtual bool deferAddingComponents() const { return true; }
|
virtual bool deferAddingComponents() const { return true; }
|
||||||
|
|
||||||
void notifyComponents(String signalFunction, String argA, String argB, String argC, String argD, String argE);
|
void notifyComponents(String signalFunction, String argA, String argB="", String argC = "", String argD = "", String argE = "");
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
T* getComponent();
|
T* getComponent();
|
||||||
|
|
@ -286,8 +286,9 @@ public:
|
||||||
MatrixF getWorldToObj() { return mWorldToObj; }
|
MatrixF getWorldToObj() { return mWorldToObj; }
|
||||||
MatrixF getObjToWorld() { return mObjToWorld; }
|
MatrixF getObjToWorld() { return mObjToWorld; }
|
||||||
|
|
||||||
DECLARE_CONOBJECT(Entity);
|
StateDelta getNetworkDelta() { return mDelta; }
|
||||||
|
|
||||||
|
DECLARE_CONOBJECT(Entity);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,8 @@ public:
|
||||||
virtual void findContact(SceneObject **contactObject, VectorF *contactNormal, Vector<SceneObject*> *outOverlapObjects) const;
|
virtual void findContact(SceneObject **contactObject, VectorF *contactNormal, Vector<SceneObject*> *outOverlapObjects) const;
|
||||||
virtual void moveKinematicTo(const MatrixF &xfm);
|
virtual void moveKinematicTo(const MatrixF &xfm);
|
||||||
|
|
||||||
|
virtual bool isValid() { return mActor != nullptr; }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _T3D_PHYSICS_BTBODY_H_
|
#endif // _T3D_PHYSICS_BTBODY_H_
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,8 @@ public:
|
||||||
///
|
///
|
||||||
virtual void moveKinematicTo(const MatrixF &xfm) = 0;
|
virtual void moveKinematicTo(const MatrixF &xfm) = 0;
|
||||||
|
|
||||||
|
virtual bool isValid() = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,6 @@
|
||||||
#include "materials/materialManager.h"
|
#include "materials/materialManager.h"
|
||||||
#include "materials/baseMatInstance.h"
|
#include "materials/baseMatInstance.h"
|
||||||
|
|
||||||
Vector<MeshRenderSystem::BufferMaterials> MeshRenderSystem::mBufferMaterials(0);
|
|
||||||
Vector<MeshRenderSystem::BufferSet> MeshRenderSystem::mStaticBuffers(0);
|
|
||||||
|
|
||||||
void MeshRenderSystem::render(SceneManager *sceneManager, SceneRenderState* state)
|
void MeshRenderSystem::render(SceneManager *sceneManager, SceneRenderState* state)
|
||||||
{
|
{
|
||||||
if (sceneManager == nullptr || state == nullptr)
|
if (sceneManager == nullptr || state == nullptr)
|
||||||
|
|
@ -24,9 +21,6 @@ void MeshRenderSystem::render(SceneManager *sceneManager, SceneRenderState* stat
|
||||||
if (!MeshRenderSystemInterface::all[i]->mIsClient)
|
if (!MeshRenderSystemInterface::all[i]->mIsClient)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (MeshRenderSystemInterface::all[i]->mStatic)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
//First, do frustum culling
|
//First, do frustum culling
|
||||||
if (viewFrustum.isCulled(MeshRenderSystemInterface::all[i]->mBounds))
|
if (viewFrustum.isCulled(MeshRenderSystemInterface::all[i]->mBounds))
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -52,90 +46,6 @@ void MeshRenderSystem::render(SceneManager *sceneManager, SceneRenderState* stat
|
||||||
//if we've made it this far, call down to the render function to actually display our stuff
|
//if we've made it this far, call down to the render function to actually display our stuff
|
||||||
renderInterface(i, state);
|
renderInterface(i, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Static Batch rendering
|
|
||||||
if ( /*!mMaterialInst ||*/ !state)
|
|
||||||
return;
|
|
||||||
|
|
||||||
BaseMatInstance *matInst = MATMGR->getWarningMatInstance();
|
|
||||||
|
|
||||||
// Get a handy pointer to our RenderPassmanager
|
|
||||||
RenderPassManager *renderPass = state->getRenderPass();
|
|
||||||
|
|
||||||
for (U32 i = 0; i < mStaticBuffers.size(); i++)
|
|
||||||
{
|
|
||||||
for (U32 b = 0; b < mStaticBuffers[i].buffers.size(); b++)
|
|
||||||
{
|
|
||||||
if (mStaticBuffers[i].buffers[b].vertData.empty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
MeshRenderInst *ri = renderPass->allocInst<MeshRenderInst>();
|
|
||||||
|
|
||||||
// Set our RenderInst as a standard mesh render
|
|
||||||
ri->type = RenderPassManager::RIT_Mesh;
|
|
||||||
|
|
||||||
//If our material has transparency set on this will redirect it to proper render bin
|
|
||||||
if (matInst->getMaterial()->isTranslucent())
|
|
||||||
{
|
|
||||||
ri->type = RenderPassManager::RIT_Translucent;
|
|
||||||
ri->translucentSort = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate our sorting point
|
|
||||||
if (state)
|
|
||||||
{
|
|
||||||
// Calculate our sort point manually.
|
|
||||||
const Box3F& rBox = Box3F(1000);// getRenderWorldBox();
|
|
||||||
ri->sortDistSq = rBox.getSqDistanceToPoint(state->getCameraPosition());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ri->sortDistSq = 0.0f;
|
|
||||||
|
|
||||||
// Set up our transforms
|
|
||||||
MatrixF objectToWorld = MatrixF::Identity;//getRenderTransform();
|
|
||||||
//objectToWorld.scale(getScale());
|
|
||||||
|
|
||||||
ri->objectToWorld = renderPass->allocUniqueXform(objectToWorld);
|
|
||||||
ri->worldToCamera = renderPass->allocSharedXform(RenderPassManager::View);
|
|
||||||
ri->projection = renderPass->allocSharedXform(RenderPassManager::Projection);
|
|
||||||
|
|
||||||
// If our material needs lights then fill the RIs
|
|
||||||
// light vector with the best lights.
|
|
||||||
/*if (matInst->isForwardLit())
|
|
||||||
{
|
|
||||||
LightQuery query;
|
|
||||||
query.init(getWorldSphere());
|
|
||||||
query.getLights(ri->lights, 8);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// Make sure we have an up-to-date backbuffer in case
|
|
||||||
// our Material would like to make use of it
|
|
||||||
// NOTICE: SFXBB is removed and refraction is disabled!
|
|
||||||
//ri->backBuffTex = GFX->getSfxBackBuffer();
|
|
||||||
|
|
||||||
// Set our Material
|
|
||||||
ri->matInst = matInst;
|
|
||||||
|
|
||||||
// Set up our vertex buffer and primitive buffer
|
|
||||||
ri->vertBuff = &mStaticBuffers[i].buffers[b].vertexBuffer;
|
|
||||||
ri->primBuff = &mStaticBuffers[i].buffers[b].primitiveBuffer;
|
|
||||||
|
|
||||||
ri->prim = renderPass->allocPrim();
|
|
||||||
ri->prim->type = GFXTriangleList;
|
|
||||||
ri->prim->minIndex = 0;
|
|
||||||
ri->prim->startIndex = 0;
|
|
||||||
ri->prim->numPrimitives = mStaticBuffers[i].buffers[b].primData.size();
|
|
||||||
ri->prim->startVertex = 0;
|
|
||||||
ri->prim->numVertices = mStaticBuffers[i].buffers[b].vertData.size();
|
|
||||||
|
|
||||||
// We sort by the material then vertex buffer
|
|
||||||
ri->defaultKey = matInst->getStateHint();
|
|
||||||
ri->defaultKey2 = (uintptr_t)ri->vertBuff;
|
|
||||||
|
|
||||||
// Submit our RenderInst to the RenderPassManager
|
|
||||||
state->getRenderPass()->addInst(ri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshRenderSystem::renderInterface(U32 interfaceIndex, SceneRenderState* state)
|
void MeshRenderSystem::renderInterface(U32 interfaceIndex, SceneRenderState* state)
|
||||||
|
|
@ -181,196 +91,4 @@ void MeshRenderSystem::renderInterface(U32 interfaceIndex, SceneRenderState* sta
|
||||||
GFX->setWorldMatrix(mat);
|
GFX->setWorldMatrix(mat);
|
||||||
|
|
||||||
interface->mShapeInstance->render(rdata);
|
interface->mShapeInstance->render(rdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshRenderSystem::rebuildBuffers()
|
|
||||||
{
|
|
||||||
U32 BUFFER_SIZE = 65000;
|
|
||||||
Vector<U32> tempIndices;
|
|
||||||
tempIndices.reserve(4);
|
|
||||||
|
|
||||||
Box3F newBounds = Box3F::Zero;
|
|
||||||
|
|
||||||
mStaticBuffers.clear();
|
|
||||||
|
|
||||||
for (U32 i = 0; i < MeshRenderSystemInterface::all.size(); i++)
|
|
||||||
{
|
|
||||||
if (!MeshRenderSystemInterface::all[i]->mIsEnabled)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!MeshRenderSystemInterface::all[i]->mIsClient || !MeshRenderSystemInterface::all[i]->mStatic)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
//TODO: Properly re-implement StaticElements to container owner interfaces and buffer sets
|
|
||||||
for (U32 j = 0; j < MeshRenderSystemInterface::all[i]->mGeometry.mPolyList.size(); j++)
|
|
||||||
{
|
|
||||||
const OptimizedPolyList::Poly& poly = MeshRenderSystemInterface::all[i]->mGeometry.mPolyList[j];
|
|
||||||
|
|
||||||
if (poly.vertexCount < 3)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
tempIndices.setSize(poly.vertexCount);
|
|
||||||
dMemset(tempIndices.address(), 0, poly.vertexCount);
|
|
||||||
|
|
||||||
if (poly.type == OptimizedPolyList::TriangleStrip ||
|
|
||||||
poly.type == OptimizedPolyList::TriangleFan)
|
|
||||||
{
|
|
||||||
tempIndices[0] = 0;
|
|
||||||
U32 idx = 1;
|
|
||||||
|
|
||||||
for (U32 k = 1; k < poly.vertexCount; k += 2)
|
|
||||||
tempIndices[idx++] = k;
|
|
||||||
|
|
||||||
for (U32 k = ((poly.vertexCount - 1) & (~0x1)); k > 0; k -= 2)
|
|
||||||
tempIndices[idx++] = k;
|
|
||||||
}
|
|
||||||
else if (poly.type == OptimizedPolyList::TriangleList)
|
|
||||||
{
|
|
||||||
for (U32 k = 0; k < poly.vertexCount; k++)
|
|
||||||
tempIndices[k] = k;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
|
|
||||||
//got our data, now insert it into the correct buffer!
|
|
||||||
S32 bufferId = findBufferSetByMaterial(poly.material);
|
|
||||||
|
|
||||||
if (bufferId == -1)
|
|
||||||
{
|
|
||||||
//add a new buffer set if we didn't get a match!
|
|
||||||
BufferSet newSet;
|
|
||||||
newSet.surfaceMaterialId = poly.material;
|
|
||||||
|
|
||||||
mStaticBuffers.push_back(newSet);
|
|
||||||
|
|
||||||
bufferId = mStaticBuffers.size() - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//see if this would push us over our buffer size limit, if it is, make a new buffer for this set
|
|
||||||
if (mStaticBuffers[bufferId].buffers.last().vertData.size() + 3 > BUFFER_SIZE
|
|
||||||
|| mStaticBuffers[bufferId].buffers.last().primData.size() + 1 > BUFFER_SIZE)
|
|
||||||
{
|
|
||||||
//yep, we'll overstep with this, so spool up a new buffer in this set
|
|
||||||
BufferSet::Buffers newBuffer = BufferSet::Buffers();
|
|
||||||
mStaticBuffers[bufferId].buffers.push_back(newBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
const U32& firstIdx = MeshRenderSystemInterface::all[i]->mGeometry.mIndexList[poly.vertexStart];
|
|
||||||
const OptimizedPolyList::VertIndex& firstVertIdx = MeshRenderSystemInterface::all[i]->mGeometry.mVertexList[firstIdx];
|
|
||||||
|
|
||||||
//Vector<Point3F> geomPoints = MeshRenderSystemInterface::all[i]->mGeometry.mPoints;
|
|
||||||
//Vector<Point3F> geomNormals = MeshRenderSystemInterface::all[i]->mGeometry.mNormals;
|
|
||||||
//Vector<Point2F> geoUVs = MeshRenderSystemInterface::all[i]->mGeometry.mUV0s;
|
|
||||||
|
|
||||||
for (U32 k = 1; k < poly.vertexCount - 1; k++)
|
|
||||||
{
|
|
||||||
const U32& secondIdx = MeshRenderSystemInterface::all[i]->mGeometry.mIndexList[poly.vertexStart + tempIndices[k]];
|
|
||||||
const U32& thirdIdx = MeshRenderSystemInterface::all[i]->mGeometry.mIndexList[poly.vertexStart + tempIndices[k + 1]];
|
|
||||||
|
|
||||||
const OptimizedPolyList::VertIndex& secondVertIdx = MeshRenderSystemInterface::all[i]->mGeometry.mVertexList[secondIdx];
|
|
||||||
const OptimizedPolyList::VertIndex& thirdVertIdx = MeshRenderSystemInterface::all[i]->mGeometry.mVertexList[thirdIdx];
|
|
||||||
|
|
||||||
Point3F points[3];
|
|
||||||
points[0] = MeshRenderSystemInterface::all[i]->mGeometry.mPoints[firstVertIdx.vertIdx];
|
|
||||||
points[1] = MeshRenderSystemInterface::all[i]->mGeometry.mPoints[secondVertIdx.vertIdx];
|
|
||||||
points[2] = MeshRenderSystemInterface::all[i]->mGeometry.mPoints[thirdVertIdx.vertIdx];
|
|
||||||
|
|
||||||
Point3F normals[3];
|
|
||||||
normals[0] = MeshRenderSystemInterface::all[i]->mGeometry.mNormals[firstVertIdx.normalIdx];
|
|
||||||
normals[1] = MeshRenderSystemInterface::all[i]->mGeometry.mNormals[secondVertIdx.normalIdx];
|
|
||||||
normals[2] = MeshRenderSystemInterface::all[i]->mGeometry.mNormals[thirdVertIdx.normalIdx];
|
|
||||||
|
|
||||||
Point3F tangents[3];
|
|
||||||
tangents[0] = mCross(points[1] - points[0], normals[0]);
|
|
||||||
tangents[1] = mCross(points[2] - points[1], normals[1]);
|
|
||||||
tangents[2] = mCross(points[0] - points[2], normals[2]);
|
|
||||||
|
|
||||||
Point2F uvs[3];
|
|
||||||
uvs[0] = MeshRenderSystemInterface::all[i]->mGeometry.mUV0s[firstVertIdx.uv0Idx];
|
|
||||||
uvs[1] = MeshRenderSystemInterface::all[i]->mGeometry.mUV0s[secondVertIdx.uv0Idx];
|
|
||||||
uvs[2] = MeshRenderSystemInterface::all[i]->mGeometry.mUV0s[thirdVertIdx.uv0Idx];
|
|
||||||
|
|
||||||
mStaticBuffers[bufferId].vertCount += 3;
|
|
||||||
mStaticBuffers[bufferId].primCount += 1;
|
|
||||||
|
|
||||||
for (U32 v = 0; v < 3; ++v)
|
|
||||||
{
|
|
||||||
//Build the vert and store it to the buffers!
|
|
||||||
GFXVertexPNTT bufVert;
|
|
||||||
bufVert.point = points[v];
|
|
||||||
bufVert.normal = normals[v];
|
|
||||||
bufVert.tangent = tangents[v];
|
|
||||||
bufVert.texCoord = uvs[v];
|
|
||||||
|
|
||||||
newBounds.extend(points[v]);
|
|
||||||
|
|
||||||
mStaticBuffers[bufferId].buffers.last().vertData.push_back(bufVert);
|
|
||||||
|
|
||||||
U32 vertPrimId = mStaticBuffers[bufferId].buffers.last().vertData.size() - 1;
|
|
||||||
mStaticBuffers[bufferId].buffers.last().primData.push_back(vertPrimId);
|
|
||||||
|
|
||||||
mStaticBuffers[bufferId].center += points[v];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Now, iterate through the organized data and turn them into renderable buffers
|
|
||||||
for (U32 i = 0; i < mStaticBuffers.size(); i++)
|
|
||||||
{
|
|
||||||
for (U32 b = 0; b < mStaticBuffers[i].buffers.size(); b++)
|
|
||||||
{
|
|
||||||
BufferSet::Buffers& buffers = mStaticBuffers[i].buffers[b];
|
|
||||||
|
|
||||||
//if there's no data to be had in this buffer, just skip it
|
|
||||||
if (buffers.vertData.empty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
buffers.vertexBuffer.set(GFX, buffers.vertData.size(), GFXBufferTypeStatic);
|
|
||||||
GFXVertexPNTT *pVert = buffers.vertexBuffer.lock();
|
|
||||||
|
|
||||||
for (U32 v = 0; v < buffers.vertData.size(); v++)
|
|
||||||
{
|
|
||||||
pVert->normal = buffers.vertData[v].normal;
|
|
||||||
pVert->tangent = buffers.vertData[v].tangent;
|
|
||||||
//pVert->color = buffers.vertData[v].color;
|
|
||||||
pVert->point = buffers.vertData[v].point;
|
|
||||||
pVert->texCoord = buffers.vertData[v].texCoord;
|
|
||||||
|
|
||||||
pVert++;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffers.vertexBuffer.unlock();
|
|
||||||
|
|
||||||
// Allocate PB
|
|
||||||
buffers.primitiveBuffer.set(GFX, buffers.primData.size(), buffers.primData.size() / 3, GFXBufferTypeStatic);
|
|
||||||
|
|
||||||
U16 *pIndex;
|
|
||||||
buffers.primitiveBuffer.lock(&pIndex);
|
|
||||||
|
|
||||||
for (U16 primDataIDx = 0; primDataIDx < buffers.primData.size(); primDataIDx++)
|
|
||||||
{
|
|
||||||
*pIndex = primDataIDx;
|
|
||||||
pIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffers.primitiveBuffer.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
mStaticBuffers[i].center /= mStaticBuffers[i].vertCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
//mObjBox = newBounds;
|
|
||||||
//resetWorldBox();
|
|
||||||
}
|
|
||||||
|
|
||||||
U32 MeshRenderSystem::findBufferSetByMaterial(U32 matId)
|
|
||||||
{
|
|
||||||
for (U32 i = 0; i < mStaticBuffers.size(); i++)
|
|
||||||
{
|
|
||||||
if (mStaticBuffers[i].surfaceMaterialId == matId)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
@ -38,12 +38,7 @@ public:
|
||||||
Vector<matMap> mChangingMaterials;
|
Vector<matMap> mChangingMaterials;
|
||||||
Vector<matMap> mMaterials;
|
Vector<matMap> mMaterials;
|
||||||
|
|
||||||
//Static geometry stuff
|
MeshRenderSystemInterface() : SystemInterface(), mShapeInstance(nullptr), mTransform(MatrixF::Identity), mScale(Point3F::One), mIsClient(false)
|
||||||
bool mStatic;
|
|
||||||
|
|
||||||
OptimizedPolyList mGeometry;
|
|
||||||
|
|
||||||
MeshRenderSystemInterface() : SystemInterface(), mShapeInstance(nullptr), mTransform(MatrixF::Identity), mScale(Point3F::One), mIsClient(false), mStatic(false)
|
|
||||||
{
|
{
|
||||||
mBounds = Box3F(1);
|
mBounds = Box3F(1);
|
||||||
mSphere = SphereF();
|
mSphere = SphereF();
|
||||||
|
|
@ -58,150 +53,10 @@ public:
|
||||||
|
|
||||||
class MeshRenderSystem
|
class MeshRenderSystem
|
||||||
{
|
{
|
||||||
protected:
|
|
||||||
/*struct StaticBatchElement
|
|
||||||
{
|
|
||||||
SimObject* owner;
|
|
||||||
OptimizedPolyList geometry;
|
|
||||||
String batchName;
|
|
||||||
};
|
|
||||||
|
|
||||||
static Vector<StaticBatchElement> mStaticElements;*/
|
|
||||||
|
|
||||||
//We retain the pushed geometry data for rendering here. It's static(unless forced to change through editing or whatnot)
|
|
||||||
//so rendering the batches is real fast
|
|
||||||
struct BufferMaterials
|
|
||||||
{
|
|
||||||
// The name of the Material we will use for rendering
|
|
||||||
String mMaterialName;
|
|
||||||
// The actual Material instance
|
|
||||||
BaseMatInstance* mMaterialInst;
|
|
||||||
|
|
||||||
BufferMaterials()
|
|
||||||
{
|
|
||||||
mMaterialName = "";
|
|
||||||
mMaterialInst = NULL;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static Vector<BufferMaterials> mBufferMaterials;
|
|
||||||
|
|
||||||
struct BufferSet
|
|
||||||
{
|
|
||||||
U32 surfaceMaterialId;
|
|
||||||
|
|
||||||
U32 vertCount;
|
|
||||||
U32 primCount;
|
|
||||||
|
|
||||||
Point3F center;
|
|
||||||
|
|
||||||
struct Buffers
|
|
||||||
{
|
|
||||||
U32 vertStart;
|
|
||||||
U32 primStart;
|
|
||||||
U32 vertCount;
|
|
||||||
U32 primCount;
|
|
||||||
|
|
||||||
Vector<GFXVertexPNTT> vertData;
|
|
||||||
Vector<U32> primData;
|
|
||||||
|
|
||||||
GFXVertexBufferHandle< GFXVertexPNTT > vertexBuffer;
|
|
||||||
GFXPrimitiveBufferHandle primitiveBuffer;
|
|
||||||
|
|
||||||
Buffers()
|
|
||||||
{
|
|
||||||
vertStart = 0;
|
|
||||||
primStart = 0;
|
|
||||||
vertCount = 0;
|
|
||||||
primCount = 0;
|
|
||||||
|
|
||||||
vertexBuffer = NULL;
|
|
||||||
primitiveBuffer = NULL;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Vector<Buffers> buffers;
|
|
||||||
|
|
||||||
BufferSet()
|
|
||||||
{
|
|
||||||
Buffers newBuffer;
|
|
||||||
buffers.push_back(newBuffer);
|
|
||||||
|
|
||||||
surfaceMaterialId = 0;
|
|
||||||
|
|
||||||
vertCount = 0;
|
|
||||||
primCount = 0;
|
|
||||||
|
|
||||||
center = Point3F::Zero;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static Vector<BufferSet> mStaticBuffers;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/*virtual void prepRenderImage(SceneRenderState *state);
|
|
||||||
|
|
||||||
bool setMeshAsset(const char* assetName);
|
|
||||||
|
|
||||||
virtual TSShape* getShape() { if (mMeshAsset) return mMeshAsset->getShape(); else return NULL; }
|
|
||||||
virtual TSShapeInstance* getShapeInstance() { return mShapeInstance; }
|
|
||||||
|
|
||||||
Resource<TSShape> getShapeResource() { return mMeshAsset->getShapeResource(); }
|
|
||||||
|
|
||||||
void _onResourceChanged(const Torque::Path &path);
|
|
||||||
|
|
||||||
virtual bool castRayRendered(const Point3F &start, const Point3F &end, RayInfo *info);
|
|
||||||
|
|
||||||
void mountObjectToNode(SceneObject* objB, String node, MatrixF txfm);
|
|
||||||
|
|
||||||
virtual void onDynamicModified(const char* slotName, const char* newValue);
|
|
||||||
|
|
||||||
void changeMaterial(U32 slot, MaterialAsset* newMat);
|
|
||||||
bool setMatInstField(U32 slot, const char* field, const char* value);
|
|
||||||
|
|
||||||
virtual void onInspect();
|
|
||||||
virtual void onEndInspect();
|
|
||||||
|
|
||||||
virtual Vector<MatrixF> getNodeTransforms()
|
|
||||||
{
|
|
||||||
Vector<MatrixF> bob;
|
|
||||||
return bob;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void setNodeTransforms(Vector<MatrixF> transforms)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/*MeshRenderSystem()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
virtual ~MeshRenderSystem()
|
|
||||||
{
|
|
||||||
smInterfaceList.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
static MeshComponentInterface* GetNewInterface()
|
|
||||||
{
|
|
||||||
smInterfaceList.increment();
|
|
||||||
|
|
||||||
return &smInterfaceList.last();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RemoveInterface(T* q)
|
|
||||||
{
|
|
||||||
smInterfaceList.erase(q);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
//Core render function, which does all the real work
|
//Core render function, which does all the real work
|
||||||
static void render(SceneManager *sceneManager, SceneRenderState* state);
|
static void render(SceneManager *sceneManager, SceneRenderState* state);
|
||||||
|
|
||||||
//Render our particular interface's data
|
//Render our particular interface's data
|
||||||
static void renderInterface(U32 interfaceIndex, SceneRenderState* state);
|
static void renderInterface(U32 interfaceIndex, SceneRenderState* state);
|
||||||
|
|
||||||
//Static Batch rendering
|
|
||||||
static void rebuildBuffers();
|
|
||||||
|
|
||||||
static U32 findBufferSetByMaterial(U32 matId);
|
|
||||||
};
|
};
|
||||||
|
|
@ -11,4 +11,9 @@
|
||||||
canSaveDynamicFields="true"
|
canSaveDynamicFields="true"
|
||||||
Extension="asset.taml"
|
Extension="asset.taml"
|
||||||
Recurse="true" />
|
Recurse="true" />
|
||||||
|
<AutoloadAssets
|
||||||
|
canSave="true"
|
||||||
|
canSaveDynamicFields="true"
|
||||||
|
AssetType="ComponentAsset"
|
||||||
|
Recurse="true" />
|
||||||
</ModuleDefinition>
|
</ModuleDefinition>
|
||||||
|
|
@ -3,8 +3,7 @@
|
||||||
canSaveDynamicFields="true"
|
canSaveDynamicFields="true"
|
||||||
AssetName="ControlObjectComponentAsset"
|
AssetName="ControlObjectComponentAsset"
|
||||||
componentName="ControlObjectComponent"
|
componentName="ControlObjectComponent"
|
||||||
componentClass="Component"
|
componentClass="ControlObjectComponent"
|
||||||
friendlyName="Control Object"
|
friendlyName="Control Object"
|
||||||
componentType="Game"
|
componentType="Game"
|
||||||
description="Allows the component owner to be controlled by a client."
|
description="Allows the component owner to be controlled by a client." />
|
||||||
scriptFile="core/components/components/game/controlObject.cs" />
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
//--- OBJECT WRITE BEGIN ---
|
||||||
|
%guiContent = new GuiControl(TypeMaskFieldGui) {
|
||||||
|
position = "0 0";
|
||||||
|
extent = "1024 768";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "right";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "ToolsGuiDefaultNonModalProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "1";
|
||||||
|
|
||||||
|
new GuiWindowCtrl(TypeMaskFieldWindow) {
|
||||||
|
text = "Select Type Masks";
|
||||||
|
resizeWidth = "0";
|
||||||
|
resizeHeight = "1";
|
||||||
|
canMove = "1";
|
||||||
|
canClose = "1";
|
||||||
|
canMinimize = "0";
|
||||||
|
canMaximize = "0";
|
||||||
|
canCollapse = "0";
|
||||||
|
closeCommand = "Canvas.popDialog(TypeMaskFieldGui);";
|
||||||
|
edgeSnap = "1";
|
||||||
|
docking = "None";
|
||||||
|
margin = "4 4 4 4";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "0";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "0";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "430 176";
|
||||||
|
extent = "161 250";
|
||||||
|
minExtent = "161 86";
|
||||||
|
horizSizing = "windowRelative";
|
||||||
|
vertSizing = "windowRelative";
|
||||||
|
profile = "ToolsGuiWindowProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "GuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
|
||||||
|
new GuiScrollCtrl() {
|
||||||
|
willFirstRespond = "1";
|
||||||
|
hScrollBar = "alwaysOff";
|
||||||
|
vScrollBar = "dynamic";
|
||||||
|
lockHorizScroll = "0";
|
||||||
|
lockVertScroll = "0";
|
||||||
|
constantThumbHeight = "0";
|
||||||
|
childMargin = "2 0";
|
||||||
|
mouseWheelScrollSpeed = "-1";
|
||||||
|
docking = "Client";
|
||||||
|
margin = "0 0 0 0";
|
||||||
|
padding = "0 0 0 0";
|
||||||
|
anchorTop = "0";
|
||||||
|
anchorBottom = "0";
|
||||||
|
anchorLeft = "1";
|
||||||
|
anchorRight = "0";
|
||||||
|
position = "1 9";
|
||||||
|
extent = "159 238";
|
||||||
|
minExtent = "8 2";
|
||||||
|
horizSizing = "width";
|
||||||
|
vertSizing = "height";
|
||||||
|
profile = "ToolsGuiScrollProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "ToolsGuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
|
||||||
|
new GuiStackControl() {
|
||||||
|
stackingType = "Vertical";
|
||||||
|
horizStacking = "Left to Right";
|
||||||
|
vertStacking = "Top to Bottom";
|
||||||
|
padding = "-2";
|
||||||
|
dynamicSize = "1";
|
||||||
|
dynamicNonStackExtent = "0";
|
||||||
|
dynamicPos = "0";
|
||||||
|
changeChildSizeToFit = "1";
|
||||||
|
changeChildPosition = "1";
|
||||||
|
position = "3 1";
|
||||||
|
extent = "153 18";
|
||||||
|
minExtent = "16 16";
|
||||||
|
horizSizing = "width";
|
||||||
|
vertSizing = "bottom";
|
||||||
|
profile = "ToolsGuiDefaultProfile";
|
||||||
|
visible = "1";
|
||||||
|
active = "1";
|
||||||
|
tooltipProfile = "ToolsGuiToolTipProfile";
|
||||||
|
hovertime = "1000";
|
||||||
|
isContainer = "1";
|
||||||
|
internalName = "TypeMaskList";
|
||||||
|
canSave = "1";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
//--- OBJECT WRITE END ---
|
||||||
|
|
@ -0,0 +1,276 @@
|
||||||
|
function GuiInspectorComponentGroup::buildMaterialField(%this, %component, %fieldName)
|
||||||
|
{
|
||||||
|
%extent = 200;
|
||||||
|
|
||||||
|
%currentMaterial = %component.getFieldValue(%fieldName);
|
||||||
|
|
||||||
|
//if we don't have a new material set on this slot, just use the default
|
||||||
|
if(%currentMaterial $= "" || %currentMaterial == 0)
|
||||||
|
%currentMaterial = %material;
|
||||||
|
|
||||||
|
%container = new GuiControl() {
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
Profile = "EditorContainerProfile";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "0 0";
|
||||||
|
Extent = "300 110";
|
||||||
|
MinExtent = "8 2";
|
||||||
|
canSave = "0";
|
||||||
|
Visible = "1";
|
||||||
|
hovertime = "100";
|
||||||
|
tooltip = %tooltip;
|
||||||
|
tooltipProfile = "EditorToolTipProfile";
|
||||||
|
};
|
||||||
|
|
||||||
|
%labelControl = new GuiTextCtrl() {
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
Profile = "EditorFontHLBold";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "16 3";
|
||||||
|
Extent = "100 18";
|
||||||
|
MinExtent = "8 2";
|
||||||
|
canSave = "0";
|
||||||
|
Visible = "1";
|
||||||
|
hovertime = "100";
|
||||||
|
tooltip = %tooltip;
|
||||||
|
tooltipProfile = "EditorToolTipProfile";
|
||||||
|
text = %fieldName;
|
||||||
|
maxLength = "1024";
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
%imageContainer = new GuiControl(){
|
||||||
|
profile = "ToolsGuiDefaultProfile";
|
||||||
|
Position = "20 25";
|
||||||
|
Extent = "74 87";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
isContainer = "1";
|
||||||
|
|
||||||
|
new GuiTextCtrl(){
|
||||||
|
position = "7 71";
|
||||||
|
profile = "ToolsGuiTextCenterProfile";
|
||||||
|
extent = "64 16";
|
||||||
|
text = %matName;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
%previewButton = new GuiBitmapButtonCtrl(){
|
||||||
|
internalName = %matName;
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
profile = "ToolsGuiButtonProfile";
|
||||||
|
position = "7 4";
|
||||||
|
extent = "64 64";
|
||||||
|
buttonType = "PushButton";
|
||||||
|
bitmap = "";
|
||||||
|
Command = "";
|
||||||
|
text = "Loading...";
|
||||||
|
useStates = false;
|
||||||
|
tooltip = "Change material";
|
||||||
|
|
||||||
|
new GuiBitmapButtonCtrl(){
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
profile = "ToolsGuiButtonProfile";
|
||||||
|
position = "0 0";
|
||||||
|
extent = "64 64";
|
||||||
|
Variable = "";
|
||||||
|
buttonType = "toggleButton";
|
||||||
|
bitmap = "tools/materialEditor/gui/cubemapBtnBorder";
|
||||||
|
groupNum = "0";
|
||||||
|
text = "";
|
||||||
|
tooltip = "Change material";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
%previewBorder = new GuiButtonCtrl(){
|
||||||
|
className = "materialFieldBtn";
|
||||||
|
internalName = %matName@"Border";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
profile = "ToolsGuiThumbHighlightButtonProfile";
|
||||||
|
position = "3 0";
|
||||||
|
extent = "72 88";
|
||||||
|
Variable = "";
|
||||||
|
buttonType = "toggleButton";
|
||||||
|
tooltip = %matName;
|
||||||
|
groupNum = "0";
|
||||||
|
text = "";
|
||||||
|
Object = %component;
|
||||||
|
targetField = %fieldName;
|
||||||
|
};
|
||||||
|
%previewBorder.Command = %previewBorder @ ".getMaterialName();";
|
||||||
|
|
||||||
|
%imageContainer.add(%previewButton);
|
||||||
|
%imageContainer.add(%previewBorder);
|
||||||
|
%container.add(%imageContainer);
|
||||||
|
//
|
||||||
|
|
||||||
|
%mapToLabel = new GuiTextCtrl() {
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
Profile = "EditorFontHLBold";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "100 26";
|
||||||
|
Extent = %extent SPC "18";
|
||||||
|
MinExtent = "8 2";
|
||||||
|
canSave = "0";
|
||||||
|
Visible = "1";
|
||||||
|
hovertime = "100";
|
||||||
|
tooltip = %tooltip;
|
||||||
|
tooltipProfile = "EditorToolTipProfile";
|
||||||
|
text = "Mapped to:" SPC %material.mapTo;
|
||||||
|
maxLength = "1024";
|
||||||
|
};
|
||||||
|
|
||||||
|
%editControl = new GuiTextEditCtrl() {
|
||||||
|
class = "BehaviorEdTextField";
|
||||||
|
internalName = %accessor @ "File";
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
Profile = "EditorTextEdit";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "100 50";
|
||||||
|
Extent = %extent SPC "22";
|
||||||
|
MinExtent = "8 2";
|
||||||
|
canSave = "0";
|
||||||
|
Visible = "1";
|
||||||
|
hovertime = "100";
|
||||||
|
tooltip = %tooltip;
|
||||||
|
tooltipProfile = "EditorToolTipProfile";
|
||||||
|
maxLength = "1024";
|
||||||
|
historySize = "0";
|
||||||
|
password = "0";
|
||||||
|
text = %currentMaterial;
|
||||||
|
|
||||||
|
tabComplete = "0";
|
||||||
|
sinkAllKeyEvents = "0";
|
||||||
|
password = "0";
|
||||||
|
passwordMask = "*";
|
||||||
|
precision = %precision;
|
||||||
|
accessor = %accessor;
|
||||||
|
isProperty = true;
|
||||||
|
undoLabel = %fieldName;
|
||||||
|
object = %this.object;
|
||||||
|
useWords = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
%resetButton = new GuiButtonCtrl() {
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
className = "materialFieldBtn";
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "100 75";
|
||||||
|
Extent = (%extent * 0.3)-3 SPC "22";
|
||||||
|
MinExtent = "8 2";
|
||||||
|
canSave = "0";
|
||||||
|
Visible = "1";
|
||||||
|
hovertime = "100";
|
||||||
|
tooltip = "Reset to default material";
|
||||||
|
tooltipProfile = "EditorToolTipProfile";
|
||||||
|
text = "Reset";
|
||||||
|
pathField = %editControl;
|
||||||
|
};
|
||||||
|
|
||||||
|
%editMatButton = new GuiButtonCtrl() {
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
className = "materialFieldBtn";
|
||||||
|
Profile = "GuiButtonProfile";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = %resetButton.position.x + (%extent * 0.3) + 6 SPC "75";
|
||||||
|
Extent = (%extent * 0.6)-3 SPC "22";
|
||||||
|
MinExtent = "8 2";
|
||||||
|
canSave = "0";
|
||||||
|
Visible = "1";
|
||||||
|
hovertime = "100";
|
||||||
|
tooltip = "Edit in Material Editor";
|
||||||
|
tooltipProfile = "EditorToolTipProfile";
|
||||||
|
text = "Open in Editor";
|
||||||
|
pathField = %editControl;
|
||||||
|
};
|
||||||
|
|
||||||
|
%container.add(%mapToLabel);
|
||||||
|
%container.add(%labelControl);
|
||||||
|
%container.add(%editControl);
|
||||||
|
%container.add(%resetButton);
|
||||||
|
%container.add(%editMatButton);
|
||||||
|
|
||||||
|
//load the material
|
||||||
|
%matName = "";
|
||||||
|
|
||||||
|
// CustomMaterials are not available for selection
|
||||||
|
/*if ( !isObject( %currentMaterial ) || %currentMaterial.isMemberOfClass( "CustomMaterial" ) )
|
||||||
|
return;*/
|
||||||
|
%assetDef = AssetDatabase.acquireAsset(%currentMaterial);
|
||||||
|
|
||||||
|
%materialDef = %assetDef.materialDefinitionName;
|
||||||
|
|
||||||
|
if( %materialDef.isMemberOfClass("TerrainMaterial") )
|
||||||
|
{
|
||||||
|
%matName = %currentMaterial.getInternalName();
|
||||||
|
|
||||||
|
if( %materialDef.diffuseMap $= "")
|
||||||
|
%previewImage = "core/art/warnmat";
|
||||||
|
else
|
||||||
|
%previewImage = %materialDef.diffuseMap;
|
||||||
|
}
|
||||||
|
else if( %materialDef.toneMap[0] $= "" && %materialDef.diffuseMap[0] $= "" && !isObject(%materialDef.cubemap) )
|
||||||
|
{
|
||||||
|
%matName = %materialDef.name;
|
||||||
|
%previewImage = "core/art/warnmat";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
%matName = %materialDef.name;
|
||||||
|
|
||||||
|
if( %materialDef.toneMap[0] !$= "" )
|
||||||
|
%previewImage = %materialDef.toneMap[0];
|
||||||
|
else if( %materialDef.diffuseMap[0] !$= "" )
|
||||||
|
%previewImage = %materialDef.diffuseMap[0];
|
||||||
|
else if( %materialDef.cubemap.cubeFace[0] !$= "" )
|
||||||
|
%previewImage = %materialDef.cubemap.cubeFace[0];
|
||||||
|
|
||||||
|
//%previewImage = MaterialEditorGui.searchForTexture( %material, %previewImage );
|
||||||
|
|
||||||
|
// were going to use a couple of string commands in order to properly
|
||||||
|
// find out what the img src path is
|
||||||
|
// **NEW** this needs to be updated with the above, but has some timing issues
|
||||||
|
%materialDiffuse = %previewImage;
|
||||||
|
%materialPath = %materialDef.getFilename();
|
||||||
|
|
||||||
|
if( strchr( %materialDiffuse, "/") $= "" )
|
||||||
|
{
|
||||||
|
%k = 0;
|
||||||
|
while( strpos( %materialPath, "/", %k ) != -1 )
|
||||||
|
{
|
||||||
|
%foo = strpos( %materialPath, "/", %k );
|
||||||
|
%k = %foo + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
%foobar = getSubStr( %materialPath , %k , 99 );
|
||||||
|
%previewImage = strreplace( %materialPath, %foobar, %previewImage );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
%previewImage = strreplace( %materialPath, %materialPath, %previewImage );
|
||||||
|
}
|
||||||
|
|
||||||
|
%previewButton.setBitmap(%previewImage);
|
||||||
|
%previewButton.setText("");
|
||||||
|
|
||||||
|
%this.stack.add(%container);
|
||||||
|
}
|
||||||
|
|
||||||
|
function materialFieldBtn::onClick(%this)
|
||||||
|
{
|
||||||
|
AssetBrowser.showDialog("MaterialAsset", "", %this.Object, %this.targetField, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function materialFieldBtn::setMaterial(%this, %matAssetName)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,215 @@
|
||||||
|
function BehaviorFieldStack::createStateMachineEditor(%this, %behavior, %fieldIndex)
|
||||||
|
{
|
||||||
|
%fieldInfo = %behavior.template.getBehaviorField(%fieldIndex);
|
||||||
|
%name = getField(%fieldInfo, 0);
|
||||||
|
|
||||||
|
%button = new GuiButtonCtrl()
|
||||||
|
{
|
||||||
|
class = EditStateMachineBtn;
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "0 2";
|
||||||
|
Extent = (%this.extent.x - 8) SPC 13;
|
||||||
|
text = "Edit States";
|
||||||
|
tooltip = "Open window to edit the state machine";
|
||||||
|
behavior = %behavior;
|
||||||
|
};
|
||||||
|
%this.add(%button);
|
||||||
|
}
|
||||||
|
|
||||||
|
function EditStateMachineBtn::onClick(%this)
|
||||||
|
{
|
||||||
|
Canvas.pushDialog(StateMachineEditor);
|
||||||
|
StateMachineEditor.behavior = %this.behavior;
|
||||||
|
|
||||||
|
StateMachineEditor.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
function StateMachineEditor::open(%this)
|
||||||
|
{
|
||||||
|
//check our behavior and see if we have any existing state/field info to work with
|
||||||
|
//if we do, load those up first
|
||||||
|
for(%i = 0; %i < %this.behavior.stateMachine.count(); %i++)
|
||||||
|
{
|
||||||
|
%stateName = %this.behavior.stateMachine.getKey(%i);
|
||||||
|
|
||||||
|
%this.addState(%stateName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function StateMachineEditor::addState(%this, %stateName)
|
||||||
|
{
|
||||||
|
if(%stateName $= "")
|
||||||
|
%stateName = "New State";
|
||||||
|
|
||||||
|
%state = new GuiControl() {
|
||||||
|
position = "0 0";
|
||||||
|
extent = "285 50";
|
||||||
|
horizSizing = "horizResizeWidth";
|
||||||
|
vertSizing = "vertResizeTop";
|
||||||
|
isContainer = "1";
|
||||||
|
|
||||||
|
new GuiTextEditCtrl() {
|
||||||
|
position = "0 0";
|
||||||
|
extent = "100 15";
|
||||||
|
text = %stateName;
|
||||||
|
};
|
||||||
|
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
//buttonMargin = "4 4";
|
||||||
|
text = "Remove State";
|
||||||
|
position = "184 0";
|
||||||
|
extent = "100 15";
|
||||||
|
//profile = "GuiButtonProfile";
|
||||||
|
command = "ScriptEditorGui.save();";
|
||||||
|
};
|
||||||
|
|
||||||
|
new GuiSeparatorCtrl() {
|
||||||
|
position = "0 15";
|
||||||
|
extent = %this.extent.x SPC "10";
|
||||||
|
type = "horizontal";
|
||||||
|
};
|
||||||
|
|
||||||
|
new GuiStackControl(%stateName@"StateStack")
|
||||||
|
{
|
||||||
|
//Profile = "EditorContainerProfile";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "0 25";
|
||||||
|
Extent = "285 20";
|
||||||
|
padding = 4;
|
||||||
|
|
||||||
|
new GuiButtonCtrl() {
|
||||||
|
text = "Add field";
|
||||||
|
position = "3 0";
|
||||||
|
extent = "280 20";
|
||||||
|
horizSizing = "left";
|
||||||
|
vertSizing = "top";
|
||||||
|
command = "StateMachineEditor.addField("@%stateName@");";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
%this-->Stack.add(%state);
|
||||||
|
//%this-->stateStackScroll.computeSizes();
|
||||||
|
}
|
||||||
|
|
||||||
|
function StateMachineEditor::addField(%this, %stateName)
|
||||||
|
{
|
||||||
|
%index = %this.behavior.stateMachine.count();
|
||||||
|
%field = new GuiControl() {
|
||||||
|
position = "0 0";
|
||||||
|
extent = "285 20";
|
||||||
|
horizSizing = "width";
|
||||||
|
vertSizing = "height";
|
||||||
|
isContainer = "1";
|
||||||
|
fieldValueCtrl = "";
|
||||||
|
fieldID = %index++;
|
||||||
|
};
|
||||||
|
|
||||||
|
%fieldList = new GuiPopUpMenuCtrlEx()
|
||||||
|
{
|
||||||
|
class = "stateMachineFieldList";
|
||||||
|
Profile = "GuiPopupMenuProfile";
|
||||||
|
HorizSizing = "width";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
position = "0 1";
|
||||||
|
Extent = "120 18";
|
||||||
|
behavior = %this.behavior;
|
||||||
|
};
|
||||||
|
|
||||||
|
%field.add(%fieldList);
|
||||||
|
%fieldList.refresh();
|
||||||
|
|
||||||
|
(%stateName@"StateStack").addToStack(%field);
|
||||||
|
|
||||||
|
%this-->Stack.updateStack();
|
||||||
|
%this-->stateStackScroll.computeSizes();
|
||||||
|
|
||||||
|
%this.behavior.addStateField(%stateName, "", "");
|
||||||
|
|
||||||
|
return %field;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
function stateMachineFieldList::refresh(%this)
|
||||||
|
{
|
||||||
|
%this.clear();
|
||||||
|
|
||||||
|
// Find all the types.
|
||||||
|
%count = getWordCount(%this.behavior.stateFields);
|
||||||
|
%index = 0;
|
||||||
|
for (%j = 0; %j < %count; %j++)
|
||||||
|
{
|
||||||
|
%item = getWord(%this.behavior.stateFields, %j);
|
||||||
|
%this.add(%item, %index);
|
||||||
|
%this.fieldType[%index] = %item;
|
||||||
|
%index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function stateMachineFieldList::onSelect(%this)
|
||||||
|
{
|
||||||
|
//if(%this.getParent().fieldValueCtrl $= "")
|
||||||
|
%this.fieldType = %this.fieldType[%this.getSelected()];
|
||||||
|
|
||||||
|
if(%this.fieldType $= "transitionOnAnimEnd" || %this.fieldType $= "transitionOnAnimTrigger"
|
||||||
|
|| %this.fieldType $= "transitionOnTimeout")
|
||||||
|
{
|
||||||
|
%fieldCtrl = new GuiPopUpMenuCtrlEx()
|
||||||
|
{
|
||||||
|
class = "stateMachineFieldList";
|
||||||
|
Profile = "GuiPopupMenuProfile";
|
||||||
|
HorizSizing = "width";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
position = "124 1";
|
||||||
|
Extent = "120 18";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if(%this.fieldType $= "animation")
|
||||||
|
{
|
||||||
|
%fieldCtrl = new GuiPopUpMenuCtrlEx()
|
||||||
|
{
|
||||||
|
class = "stateMachineFieldList";
|
||||||
|
Profile = "GuiPopupMenuProfile";
|
||||||
|
HorizSizing = "width";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
position = "124 1";
|
||||||
|
Extent = "120 18";
|
||||||
|
};
|
||||||
|
|
||||||
|
%index = 0;
|
||||||
|
%animBhvr = %this.behavior.owner.getBehavior("AnimationController");
|
||||||
|
for(%i = 0; %i < %animBhvr.getAnimationCount(); %i++)
|
||||||
|
{
|
||||||
|
%item = %animBhvr.getAnimationName(%i);
|
||||||
|
%fieldCtrl.add(%item, %index);
|
||||||
|
%fieldCtrl.fieldValue[%index] = %item;
|
||||||
|
%index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
%fieldCtrl = new GuiTextEditCtrl() {
|
||||||
|
position = "124 1";
|
||||||
|
extent = "120 10";
|
||||||
|
text = "";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//get the state machine entry
|
||||||
|
%index = %this.getParent().fieldID;
|
||||||
|
|
||||||
|
%oldValue = %this.behavior.stateMachine.getValue(%index);
|
||||||
|
%this.behavior.stateMachine.setValue(%fieldType SPC %oldValue.y);
|
||||||
|
|
||||||
|
%this.getParent().add(%fieldCtrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
//Now for the unique field types
|
||||||
|
/*function stateMachineFieldList::refresh(%this)
|
||||||
|
{
|
||||||
|
|
||||||
|
}*/
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
function GuiInspectorComponentGroup::buildTypeMaskField(%this, %component, %fieldName)
|
||||||
|
{
|
||||||
|
%extent = 200;
|
||||||
|
|
||||||
|
%container = new GuiControl() {
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
Profile = "EditorContainerProfile";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "0 0";
|
||||||
|
Extent = "300 110";
|
||||||
|
MinExtent = "8 2";
|
||||||
|
canSave = "0";
|
||||||
|
Visible = "1";
|
||||||
|
hovertime = "100";
|
||||||
|
tooltip = %tooltip;
|
||||||
|
tooltipProfile = "EditorToolTipProfile";
|
||||||
|
};
|
||||||
|
|
||||||
|
%labelControl = new GuiTextCtrl() {
|
||||||
|
canSaveDynamicFields = "0";
|
||||||
|
Profile = "EditorFontHLBold";
|
||||||
|
HorizSizing = "right";
|
||||||
|
VertSizing = "bottom";
|
||||||
|
Position = "16 3";
|
||||||
|
Extent = "100 18";
|
||||||
|
MinExtent = "8 2";
|
||||||
|
canSave = "0";
|
||||||
|
Visible = "1";
|
||||||
|
hovertime = "100";
|
||||||
|
tooltip = %tooltip;
|
||||||
|
tooltipProfile = "EditorToolTipProfile";
|
||||||
|
text = %fieldName;
|
||||||
|
maxLength = "1024";
|
||||||
|
};
|
||||||
|
|
||||||
|
%container.add(%container);
|
||||||
|
|
||||||
|
%this.stack.add(%container);
|
||||||
|
}
|
||||||
|
|
@ -22,7 +22,14 @@
|
||||||
|
|
||||||
//Scripts
|
//Scripts
|
||||||
exec("./scripts/componentEditor.ed.cs");
|
exec("./scripts/componentEditor.ed.cs");
|
||||||
|
exec("./scripts/stateMachineEditor.ed.cs");
|
||||||
exec("./scripts/superToolTipDlg.ed.cs");
|
exec("./scripts/superToolTipDlg.ed.cs");
|
||||||
|
|
||||||
//gui
|
//gui
|
||||||
exec("./gui/superToolTipDlg.ed.gui");
|
exec("./gui/superToolTipDlg.ed.gui");
|
||||||
|
exec("./gui/stateMachineDlg.ed.gui");
|
||||||
|
|
||||||
|
//field types
|
||||||
|
exec("./interface/materialFieldType.cs");
|
||||||
|
exec("./interface/typeMaskFieldType.cs");
|
||||||
|
exec("./interface/stateMachineField.cs");
|
||||||
|
|
@ -154,13 +154,13 @@ function QuickEditComponentList::onHotTrackItem( %this, %itemID )
|
||||||
SuperTooltipDlg.setTitle(%componentObj.friendlyName);
|
SuperTooltipDlg.setTitle(%componentObj.friendlyName);
|
||||||
SuperTooltipDlg.addParam("", %componentObj.description @ "\n");
|
SuperTooltipDlg.addParam("", %componentObj.description @ "\n");
|
||||||
|
|
||||||
/*%fieldCount = %componentObj.getComponentFieldCount();
|
%fieldCount = %componentObj.getComponentFieldCount();
|
||||||
for (%i = 0; %i < %fieldCount; %i++)
|
for (%i = 0; %i < %fieldCount; %i++)
|
||||||
{
|
{
|
||||||
%name = getField(%componentObj.getComponentField(%i), 0);
|
%name = getField(%componentObj.getComponentField(%i), 0);
|
||||||
|
|
||||||
SuperTooltipDlg.addParam(%name, %description @ "\n");
|
SuperTooltipDlg.addParam(%name, %description @ "\n");
|
||||||
}*/
|
}
|
||||||
%position = %this.getGlobalPosition();
|
%position = %this.getGlobalPosition();
|
||||||
SuperTooltipDlg.processTooltip( %position,0,1 );
|
SuperTooltipDlg.processTooltip( %position,0,1 );
|
||||||
%this.opened = true;
|
%this.opened = true;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue