mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-04 20:57:49 +00:00
fahhh
This commit is contained in:
@@ -0,0 +1,220 @@
|
||||
/* Copyright 2003-2007 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Util/IndexedMesh.h"
|
||||
#include "V8World/Enum.h"
|
||||
#include "V8World/Primitive.h"
|
||||
#include "V8World/IPipelined.h"
|
||||
#include "Util/ComputeProp.h"
|
||||
#include "Util/PhysicsCoord.h"
|
||||
#include "Util/Average.h"
|
||||
#include "rbx/Debug.h"
|
||||
#include <set>
|
||||
#include "boost/intrusive/list.hpp"
|
||||
#include "Network/CompactCFrame.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Joint;
|
||||
class Primitive;
|
||||
class Clump;
|
||||
class Edge;
|
||||
class MotorJoint;
|
||||
class Clump;
|
||||
class SimulateStage;
|
||||
class AssemblyHistory;
|
||||
|
||||
typedef boost::intrusive::list_base_hook< boost::intrusive::tag<SimulateStage> > SimulateStageHook;
|
||||
|
||||
class Assembly
|
||||
: public IPipelined
|
||||
, public boost::noncopyable
|
||||
, public IndexedMesh
|
||||
, public SimulateStageHook
|
||||
{
|
||||
friend class SimJobStage;
|
||||
|
||||
public:
|
||||
typedef enum {Sim_SendIfSim, Sim_BufferZone, NoSim_Send, NoSim_SendIfSim, NoSim_Send_Anim, NoSim_SendIfSim_Anim, NUM_PHASES, Fixed, NOT_ASSIGNED} FilterPhase;
|
||||
|
||||
private:
|
||||
bool animationControlled;
|
||||
mutable bool inCode;
|
||||
|
||||
unsigned char networkHumanoidState;
|
||||
|
||||
AssemblyHistory* history;
|
||||
|
||||
Sim::AssemblyState state;
|
||||
|
||||
G3D::Array<Edge*> assemblyExternalEdges;
|
||||
G3D::Array<Joint*> assemblyMotors;
|
||||
|
||||
// SimJobStage - index into either the stage, or a mechanism
|
||||
class SimJob* simJob;
|
||||
|
||||
// SleepStage - helper for recursive algorithm - elminate need for external std::set
|
||||
int recursivePassId;
|
||||
int recursiveDepth;
|
||||
|
||||
// SpatialFilter - helper for current Phase
|
||||
FilterPhase filterPhase;
|
||||
|
||||
// Compute Props
|
||||
ComputeProp<float, Assembly> maxRadius; // farthest point on the primitives - used for getting max velocity
|
||||
float computeAssemblyMaxRadius();
|
||||
|
||||
void gatherPrimitiveExternalEdges(Primitive* p);
|
||||
|
||||
Clump* getAssemblyClump();
|
||||
const Clump* getConstAssemblyClump() const;
|
||||
|
||||
void getAssemblyMotors(G3D::Array<Joint*>& motors, bool nonAnimatedOnly);
|
||||
void getConstAssemblyMotors(G3D::Array<const Joint*>& motors, bool nonAnimatedOnly) const;
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
// IndexedMesh
|
||||
//
|
||||
/*override*/ void onLowersChanged(); // Primitives added/removed beneath me
|
||||
|
||||
public:
|
||||
Assembly();
|
||||
|
||||
~Assembly();
|
||||
|
||||
Primitive* getAssemblyPrimitive();
|
||||
const Primitive* getConstAssemblyPrimitive() const;
|
||||
|
||||
static Assembly* getPrimitiveAssembly(Primitive* p);
|
||||
static const Assembly* getConstPrimitiveAssembly(const Primitive* p);
|
||||
static Assembly* getPrimitiveAssemblyFast(Primitive* p); // primitive must have an assembly
|
||||
|
||||
static bool isAssemblyRootPrimitive(const Primitive* p);
|
||||
|
||||
Assembly* otherAssembly(Edge* edge);
|
||||
const Assembly* otherConstAssembly(const Edge* edge) const;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
bool getCanThrottle() const;
|
||||
|
||||
static bool computeCanThrottle(Edge* edge);
|
||||
|
||||
Vector2 get2dPosition() const;
|
||||
|
||||
static bool computeIsGroundingPrimitive(const Primitive* p); // in the engine, requestFIxed or RigidJoined to a fixed primitive
|
||||
|
||||
bool computeIsGrounded() const;
|
||||
|
||||
void notifyMovedFromInternalPhysics();
|
||||
|
||||
void notifyMovedFromExternal();
|
||||
|
||||
// From SpatialFilter
|
||||
FilterPhase getFilterPhase() const {return filterPhase;}
|
||||
void setFilterPhase(FilterPhase value) {filterPhase = value;}
|
||||
|
||||
// From SimJobStage
|
||||
void setSimJob(SimJob* s) {simJob = s;}
|
||||
SimJob* getSimJob() {return simJob;}
|
||||
const SimJob* getConstSimJob() const {return simJob;}
|
||||
|
||||
// From SleepStage
|
||||
void reset(Sim::AssemblyState newState); // resets state, sleep count, running average
|
||||
bool sampleAndNotMoving();
|
||||
bool preventNeighborSleep();
|
||||
void wakeUp(); // moving from sleeping to non-Sleeping state
|
||||
|
||||
Sim::AssemblyState getAssemblyState() const;
|
||||
void setAssemblyState(Sim::AssemblyState value) {state = value;}
|
||||
|
||||
void setRecursivePassId(int value) {recursivePassId = value;}
|
||||
int getRecursivePassId() const {return recursivePassId;}
|
||||
|
||||
void setRecursiveDepth(int value) {recursiveDepth= value;}
|
||||
int getRecursiveDepth() const {return recursiveDepth;}
|
||||
|
||||
bool getAssemblyIsMovingState() const {
|
||||
return (Sim::isMovingAssemblyState(state));
|
||||
}
|
||||
|
||||
float computeMaxRadius() {return maxRadius.getValue();}
|
||||
float getLastComputedRadius() const {return maxRadius.getLastComputedValue();}
|
||||
float isComputedRadiusDirty() const {return maxRadius.getDirty();}
|
||||
|
||||
// Replicated attributes (essentially used as Humanoid State)
|
||||
unsigned char getNetworkHumanoidState() const {return networkHumanoidState;}
|
||||
void setNetworkHumanoidState(unsigned char value) {networkHumanoidState = value;}
|
||||
|
||||
const G3D::Array<Edge*>& getAssemblyEdges();
|
||||
|
||||
void setPhysics(const G3D::Array<CompactCFrame>& motorAngles, const PV& pv);
|
||||
void getPhysics(G3D::Array<CompactCFrame>& motorAngles) const;
|
||||
|
||||
template<class Func>
|
||||
inline void visitAssemblies(Func func) {
|
||||
this->visitMeAndChildren<Assembly, Func>(func);
|
||||
}
|
||||
|
||||
template<class Func>
|
||||
inline void visitDescendentAssemblies(Func func) {
|
||||
this->visitDescendents<Assembly, Func>(func);
|
||||
}
|
||||
|
||||
template<class Func>
|
||||
inline void visitConstDescendentAssemblies(Func func) const {
|
||||
this->visitConstDescendents<Assembly, Func>(func);
|
||||
}
|
||||
|
||||
bool isAnimationControlled() const { return animationControlled; }
|
||||
void setAnimationControlled(bool val) { animationControlled = val; }
|
||||
|
||||
// Primitive Visiting Functions
|
||||
|
||||
private:
|
||||
template<class Func>
|
||||
inline void visitPrimitivesImpl(Func func, Primitive* p) {
|
||||
func(p);
|
||||
for (int i = 0; i < p->numChildren(); ++i) {
|
||||
Primitive* child = p->getTypedChild<Primitive>(i);
|
||||
if (!Assembly::isAssemblyRootPrimitive(child)) {
|
||||
visitPrimitivesImpl(func, child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class Func>
|
||||
inline Primitive* findFirstPrimitiveImpl(Func func, Primitive* p) {
|
||||
if (func(p)) {
|
||||
return p;
|
||||
}
|
||||
for (int i = 0; i < p->numChildren(); ++i) {
|
||||
Primitive* child = p->getTypedChild<Primitive>(i);
|
||||
if (!Assembly::isAssemblyRootPrimitive(child)) {
|
||||
if (findFirstPrimitiveImpl(func, child)) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
public:
|
||||
template<class Func>
|
||||
inline void visitPrimitives(Func func) {
|
||||
Primitive* p = getAssemblyPrimitive();
|
||||
RBXASSERT(p);
|
||||
visitPrimitivesImpl(func, p);
|
||||
}
|
||||
|
||||
template<class Func>
|
||||
inline Primitive* findFirstPrimitive(Func func) {
|
||||
Primitive* p = getAssemblyPrimitive();
|
||||
RBXASSERT(p);
|
||||
return findFirstPrimitiveImpl(func, p);
|
||||
}
|
||||
};
|
||||
|
||||
}// namespace
|
||||
@@ -0,0 +1,44 @@
|
||||
/* Copyright 2003-2007 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Util/PhysicsCoord.h"
|
||||
#include "Util/Average.h"
|
||||
#include "rbx/Debug.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Assembly;
|
||||
|
||||
class AssemblyHistory
|
||||
{
|
||||
private:
|
||||
Average<PhysicsCoord> average;
|
||||
int stepsSinceSample;
|
||||
int awakeSteps;
|
||||
float maxDeviationSquared;
|
||||
|
||||
static size_t sampleSkip();
|
||||
static size_t bufferSize();
|
||||
static float sleepTolerance();
|
||||
static float sleepToleranceSquared();
|
||||
|
||||
bool notMoving();
|
||||
void updateMaxDeviationSquared();
|
||||
PhysicsCoord getAssemblyPhysicsCoord(Assembly& a);
|
||||
|
||||
public:
|
||||
AssemblyHistory(Assembly& a);
|
||||
|
||||
~AssemblyHistory();
|
||||
|
||||
void clear(Assembly& a);
|
||||
|
||||
bool sampleAndNotMoving(Assembly& a);
|
||||
|
||||
bool preventNeighborSleep();
|
||||
|
||||
void wakeUp();
|
||||
};
|
||||
|
||||
}// namespace
|
||||
@@ -0,0 +1,37 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/EdgeBuffer.h"
|
||||
|
||||
namespace RBX {
|
||||
class Assembly;
|
||||
class Primitive;
|
||||
|
||||
class AssemblyStage : public EdgeBuffer {
|
||||
public:
|
||||
AssemblyStage(IStage* upstream, World* world);
|
||||
|
||||
~AssemblyStage();
|
||||
|
||||
/*override*/ IStage::StageType getStageType() const {return IStage::ASSEMBLY_STAGE;}
|
||||
|
||||
void onFixedAssemblyRootAdded(Assembly* a);
|
||||
void onFixedAssemblyRootRemoving(Assembly* a);
|
||||
|
||||
void onNoSimulateAssemblyRootAdded(Assembly* a) {onFixedAssemblyRootAdded(a);}
|
||||
void onNoSimulateAssemblyRootRemoving(Assembly* a) {onFixedAssemblyRootRemoving(a);}
|
||||
|
||||
void onNoSimulateAssemblyDescendentAdded(Assembly* a);
|
||||
void onNoSimulateAssemblyDescendentRemoving(Assembly* a);
|
||||
|
||||
void onSimulateAssemblyRootAdded(Assembly* a);
|
||||
void onSimulateAssemblyRootRemoving(Assembly* a);
|
||||
|
||||
void onSimulateAssemblyDescendentAdded(Assembly* a);
|
||||
void onSimulateAssemblyDescendentRemoving(Assembly* a);
|
||||
|
||||
Assembly* onEngineChanging(Primitive* p);
|
||||
void onEngineChanged(Assembly* a);
|
||||
};
|
||||
} // namespace
|
||||
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
#include "V8World/Geometry.h"
|
||||
#include "V8World/GeometryPool.h"
|
||||
#include "V8World/BulletGeometryPoolObjects.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Ball : public Geometry {
|
||||
public:
|
||||
typedef GeometryPool<float, BulletSphereShapeWrapper, FloatComparer> BulletSphereShapePool;
|
||||
|
||||
private:
|
||||
typedef Geometry Super;
|
||||
float realRadius; // in real world units, == size.x/2
|
||||
BulletSphereShapePool::Token bulletSphereShape;
|
||||
|
||||
|
||||
Matrix3 getMomentSolid(float mass) const;
|
||||
|
||||
/*override*/ void setSize(const G3D::Vector3& _size);
|
||||
|
||||
void updateBulletCollisionData();
|
||||
|
||||
public:
|
||||
Ball() : realRadius(0.0) {}
|
||||
~Ball() {}
|
||||
|
||||
// Primitive Overrides
|
||||
/*override*/ virtual bool hitTest(const RbxRay& rayInMe, Vector3& localHitPoint, Vector3& surfaceNormal);
|
||||
|
||||
/*override*/ virtual GeometryType getGeometryType() const {return GEOMETRY_BALL;}
|
||||
/*override*/ virtual CollideType getCollideType() const {return COLLIDE_BALL;}
|
||||
|
||||
// Real Radius
|
||||
/*override*/ virtual float getRadius() const {return realRadius;}
|
||||
|
||||
// Real Corner
|
||||
/*override*/ virtual Vector3 getCenterToCorner(const Matrix3& rotation) const {
|
||||
return Vector3(realRadius, realRadius, realRadius);
|
||||
}
|
||||
|
||||
// Moment
|
||||
/*override*/ virtual Matrix3 getMoment(float mass) const {
|
||||
return getMomentSolid(mass);
|
||||
}
|
||||
|
||||
// Volume
|
||||
/*override*/ float getVolume() const;
|
||||
|
||||
// Dragger support
|
||||
size_t closestSurfaceToPoint( const Vector3& pointInBody ) const;
|
||||
Plane getPlaneFromSurface( const size_t surfaceId ) const;
|
||||
CoordinateFrame getSurfaceCoordInBody( const size_t surfaceId ) const;
|
||||
Vector3 getSurfaceNormalInBody( const size_t surfaceId ) const;
|
||||
size_t getMostAlignedSurface( const Vector3& vecInWorld, const G3D::Matrix3& objectR ) const;
|
||||
int getNumSurfaces( void ) const { return 6; }
|
||||
Vector3 getSurfaceVertInBody( const size_t surfaceId, const int vertId ) const;
|
||||
int getNumVertsInSurface( const size_t surfaceId ) const;
|
||||
bool vertOverlapsFace( const Vector3& pointInBody, const size_t surfaceId ) const;
|
||||
|
||||
bool findTouchingSurfacesConvex( const CoordinateFrame& myCf, size_t& myFaceId, const Geometry& otherGeom, const CoordinateFrame& otherCf, size_t& otherFaceId ) const {return false;}
|
||||
bool FacesOverlapped( const CoordinateFrame& myCf, size_t& myFaceId, const Geometry& otherGeom, const CoordinateFrame& otherCf, size_t& otherFaceId, float tol ) const {RBXASSERT(0); return false;}
|
||||
bool FaceVerticesOverlapped( const CoordinateFrame& myCf, size_t& myFaceId, const Geometry& otherGeom, const CoordinateFrame& otherCf, size_t& otherFaceId, float tol ) const{RBXASSERT(0); return false;}
|
||||
bool FaceEdgesOverlapped( const CoordinateFrame& myCf, size_t& myFaceId, const Geometry& otherGeom, const CoordinateFrame& otherCf, size_t& otherFaceId, float tol ) const {RBXASSERT(0); return false;}
|
||||
|
||||
/*override*/ bool setUpBulletCollisionData(void);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,46 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/CellContact.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Poly;
|
||||
class BallPlaneConnector;
|
||||
class BallEdgeConnector;
|
||||
class BallVertexConnector;
|
||||
|
||||
namespace POLY {
|
||||
class Face;
|
||||
class Edge;
|
||||
class Vertex;
|
||||
}
|
||||
|
||||
class BallCellContact
|
||||
: public CellMeshContact
|
||||
, public Allocator<BallCellContact>
|
||||
{
|
||||
private:
|
||||
const POLY::Face* getFarthestPlane(float& planeToCenter, const Vector3& ballInCell);
|
||||
const POLY::Edge* getClosestEdge(const POLY::Face* face, float& edgeToCenter, const Vector3& ballInCell);
|
||||
const POLY::Edge* getClosestInVoronoiEdge(const POLY::Face* face, float& edgeToCenter, const Vector3& ballInCell);
|
||||
const POLY::Vertex* getClosestVertex(const POLY::Edge* edge, float& vertexToCenter, const Vector3& ballInCell);
|
||||
|
||||
BallPlaneConnector* newBallPlaneConnector(const POLY::Face* face);
|
||||
BallEdgeConnector* newBallEdgeConnector(const POLY::Edge* edge);
|
||||
BallVertexConnector* newBallVertexConnector(const POLY::Vertex* vertex);
|
||||
|
||||
const Ball* ball() const;
|
||||
const Poly* poly() const;
|
||||
|
||||
/*override*/ void findClosestFeatures(ConnectorArray& newConnectors);
|
||||
public:
|
||||
BallCellContact(Primitive* p0, Primitive* p1, const Vector3int16& cell);
|
||||
~BallCellContact();
|
||||
|
||||
void generateDataForMovingAssemblyStage(void); /*override*/
|
||||
};
|
||||
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,44 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/PolyContact.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Poly;
|
||||
class BallPlaneConnector;
|
||||
class BallEdgeConnector;
|
||||
class BallVertexConnector;
|
||||
|
||||
namespace POLY {
|
||||
class Face;
|
||||
class Edge;
|
||||
class Vertex;
|
||||
}
|
||||
|
||||
class BallPolyContact
|
||||
: public PolyContact
|
||||
, public Allocator<BallPolyContact>
|
||||
{
|
||||
private:
|
||||
const POLY::Face* getFarthestPlane(float& planeToCenter, const Vector3& ballInPoly);
|
||||
const POLY::Edge* getClosestEdge(const POLY::Face* face, float& edgeToCenter, const Vector3& ballInPoly);
|
||||
const POLY::Edge* getClosestInVoronoiEdge(const POLY::Face* face, float& edgeToCenter, const Vector3& ballInPoly);
|
||||
const POLY::Vertex* getClosestVertex(const POLY::Edge* edge, float& vertexToCenter, const Vector3& ballInPoly);
|
||||
|
||||
BallPlaneConnector* newBallPlaneConnector(const POLY::Face* face);
|
||||
BallEdgeConnector* newBallEdgeConnector(const POLY::Edge* edge);
|
||||
BallVertexConnector* newBallVertexConnector(const POLY::Vertex* vertex);
|
||||
|
||||
const Ball* ball() const;
|
||||
const Poly* poly() const;
|
||||
|
||||
/*override*/ void findClosestFeatures(ConnectorArray& newConnectors);
|
||||
public:
|
||||
BallPolyContact(Primitive* p0, Primitive* p1);
|
||||
void generateDataForMovingAssemblyStage(void); /*override*/
|
||||
};
|
||||
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#include "Util/G3DCore.h"
|
||||
#include "Util/ExtentsInt32.h"
|
||||
#include "Util/Extents.h"
|
||||
#include "rbx/Debug.h"
|
||||
|
||||
//#define _RBX_DEBUGGING_SPATIAL_HASH
|
||||
|
||||
#ifdef _RBX_DEBUGGING_SPATIAL_HASH
|
||||
#define RBXASSERT_SPATIAL_HASH(expr) RBXASSERT(expr)
|
||||
const bool assertingSpatialHash = true;
|
||||
#else
|
||||
#define RBXASSERT_SPATIAL_HASH(expr) ((void)0)
|
||||
const bool assertingSpatialHash = false;
|
||||
#endif
|
||||
|
||||
namespace RBX {
|
||||
|
||||
/** use the SpatialHash with classes that contain these members:
|
||||
* basic Primitive must implement:
|
||||
*/
|
||||
class BasicSpatialHashPrimitive
|
||||
{
|
||||
private:
|
||||
ExtentsInt32 oldSpatialExtents;
|
||||
int spatialNodeLevel;
|
||||
|
||||
#ifdef _RBX_DEBUGGING_SPATIAL_HASH
|
||||
void* spatialNodes;
|
||||
int spatialNodeCount;
|
||||
#endif
|
||||
|
||||
public:
|
||||
BasicSpatialHashPrimitive()
|
||||
: spatialNodeLevel(-1)
|
||||
#ifdef _RBX_DEBUGGING_SPATIAL_HASH
|
||||
, spatialNodes(0)
|
||||
, spatialNodeCount(0)
|
||||
#endif
|
||||
{};
|
||||
|
||||
~BasicSpatialHashPrimitive()
|
||||
{
|
||||
RBXASSERT(spatialNodeLevel == -1); //
|
||||
RBXASSERT_SPATIAL_HASH(spatialNodes == NULL);
|
||||
RBXASSERT_SPATIAL_HASH(spatialNodeCount == 0);
|
||||
spatialNodeLevel = -2;
|
||||
}
|
||||
|
||||
bool IsInSpatialHash() { return spatialNodeLevel > -1;}
|
||||
|
||||
// The remaining functions are used by the SpatialHash<> implementation
|
||||
int getSpatialNodeLevel() const {
|
||||
RBXASSERT(spatialNodeLevel >= -1);
|
||||
return spatialNodeLevel;
|
||||
}
|
||||
void setSpatialNodeLevel(int value) {spatialNodeLevel = value;}
|
||||
|
||||
const ExtentsInt32& getOldSpatialExtents() const {return oldSpatialExtents;}
|
||||
void setOldSpatialExtents(const ExtentsInt32& value) {oldSpatialExtents = value;}
|
||||
|
||||
const Vector3int32& getOldSpatialMin() {return oldSpatialExtents.low;}
|
||||
const Vector3int32& getOldSpatialMax() {return oldSpatialExtents.high;}
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,139 @@
|
||||
#pragma once
|
||||
|
||||
#include "V8World/Poly.h"
|
||||
#include "V8World/GeometryPool.h"
|
||||
#include "V8World/BlockCorners.h"
|
||||
#include "V8World/BlockMesh.h"
|
||||
#include "V8World/BulletGeometryPoolObjects.h"
|
||||
|
||||
#include "V8Kernel/ContactParams.h"
|
||||
#include "Util/NormalID.h"
|
||||
#include "rbx/Debug.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Block : public Poly {
|
||||
friend class TriangleMesh;
|
||||
private:
|
||||
typedef Poly Super;
|
||||
public:
|
||||
typedef GeometryPool<Vector3, POLY::BlockMesh, Vector3Comparer> BlockMeshPool;
|
||||
typedef GeometryPool<Vector3, POLY::BlockCorners, Vector3Comparer> BlockCornersPool;
|
||||
typedef GeometryPool<Vector3, BulletBoxShapeWrapper, Vector3Comparer> BulletBoxShapePool;
|
||||
private:
|
||||
BlockCornersPool::Token blockCorners;
|
||||
BlockMeshPool::Token blockMesh;
|
||||
BulletBoxShapePool::Token bulletBoxShape;
|
||||
|
||||
const Vector3* vertices; // in Real World units, object coords - shortcut to wrapper data
|
||||
|
||||
static const int BLOCK_FACE_TO_VERTEX[6][4];
|
||||
static const int BLOCK_FACE_VERTEX_TO_EDGE[6][4];
|
||||
|
||||
// loading GeoPair stuff
|
||||
const Vector3* getCornerPoint(const Vector3int16& clip) const;
|
||||
const Vector3* getEdgePoint(const Vector3int16& clip, NormalId& normalID) const;
|
||||
const Vector3* getPlanePoint(const Vector3int16& clip, NormalId& normalID) const;
|
||||
|
||||
Matrix3 getMomentHollow(float mass) const;
|
||||
|
||||
/*override*/ void setSize(const G3D::Vector3& _size);
|
||||
|
||||
// Primitive Overrides
|
||||
/*override*/ virtual bool hitTest(const RbxRay& rayInMe, Vector3& localHitPoint, Vector3& surfaceNormal);
|
||||
|
||||
/*override*/ virtual GeometryType getGeometryType() const {return GEOMETRY_BLOCK;}
|
||||
/*override*/ virtual CollideType getCollideType() const {return COLLIDE_BLOCK;}
|
||||
|
||||
public:
|
||||
// Real Corner
|
||||
/*override*/ virtual Vector3 getCenterToCorner(const Matrix3& rotation) const;
|
||||
|
||||
private:
|
||||
// Moment
|
||||
/*override*/ virtual Matrix3 getMoment(float mass) const {return getMomentHollow(mass);}
|
||||
|
||||
// Volume
|
||||
/*override*/ float getVolume() const;
|
||||
|
||||
// Poly Overrides
|
||||
/*override*/ void buildMesh();
|
||||
|
||||
void updateBulletCollisionData();
|
||||
|
||||
public:
|
||||
Block() : vertices(NULL) {}
|
||||
|
||||
~Block() {}
|
||||
|
||||
static void init();
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Block Specific Collision Detection
|
||||
void projectToFace(Vector3& ray, Vector3int16& clip, int& onBorder);
|
||||
|
||||
GeoPairType getBallInsideInfo(const Vector3& ray, const Vector3* &offset,
|
||||
NormalId& normalID);
|
||||
GeoPairType getBallBlockInfo(int onBorder, const Vector3int16 clip, const Vector3* &offset,
|
||||
NormalId& normalID);
|
||||
|
||||
inline const float* getVertices() const {
|
||||
return (float*)vertices;
|
||||
}
|
||||
|
||||
inline const Vector3& getExtent() const {
|
||||
return vertices[0];
|
||||
}
|
||||
|
||||
const Vector3* getFaceVertex(NormalId faceID, int vertID) const {
|
||||
return &vertices[ BLOCK_FACE_TO_VERTEX[faceID][vertID] ];
|
||||
}
|
||||
|
||||
int getClosestEdge(const Matrix3& rotation, NormalId normalID, const Vector3& crossAxis);
|
||||
|
||||
// tricky - given a face and a vertex on it, find the edge
|
||||
// assumes that the vertices are in counterclockwise order on the face,
|
||||
// and gives the edge that connects this vertex with the next one in
|
||||
// counter-clockwise order
|
||||
inline int faceVertexToEdge(NormalId faceID, int vertID) {
|
||||
return BLOCK_FACE_VERTEX_TO_EDGE[faceID][vertID];
|
||||
}
|
||||
|
||||
// same as the previsous, but gives the edge that
|
||||
// connects with the next in clockwise order
|
||||
inline int faceVertexToClockwiseEdge(NormalId faceID, int vertID) {
|
||||
return 12 + BLOCK_FACE_VERTEX_TO_EDGE[faceID][vertID];
|
||||
}
|
||||
|
||||
const Vector3* getEdgeVertex(int edgeId) const {
|
||||
if (edgeId < 12) {
|
||||
return &vertices[ Block::BLOCK_FACE_TO_VERTEX[edgeId / 4][edgeId % 4] ];
|
||||
}
|
||||
else {
|
||||
int ccwEdge = edgeId - 12; // convert to regular..
|
||||
NormalId faceId = (NormalId) (ccwEdge / 4);
|
||||
RBXASSERT(validNormalId(faceId));
|
||||
int vertId = ccwEdge+1 % 4; // one higher - add
|
||||
return &vertices[ Block::BLOCK_FACE_TO_VERTEX[faceId][vertId] ];
|
||||
}
|
||||
}
|
||||
|
||||
// returns X,-X,X,-X,Y,-Y,Y,-Y,Z,-Z,Z,-Z
|
||||
inline NormalId getEdgeNormal(int edgeId) {
|
||||
NormalId ans = static_cast<NormalId>((edgeId / 4) + (3*(edgeId % 2)));
|
||||
if (edgeId > 12) {
|
||||
ans = static_cast<NormalId>((ans + 3) % 6);
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
Vector2 getProjectedVertex(const Vector3& vertex, NormalId normalID);
|
||||
|
||||
// Currently used by dragger
|
||||
/*override*/ CoordinateFrame getSurfaceCoordInBody( const size_t surfaceId ) const;
|
||||
|
||||
/*override*/ bool setUpBulletCollisionData(void);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include "Util/Memory.h"
|
||||
|
||||
|
||||
/*
|
||||
Utility class - holds Vector3 [8] so that all blocks of the same size use the same geometry to improve cache / ram size for collisions
|
||||
*/
|
||||
|
||||
namespace RBX {
|
||||
|
||||
namespace POLY {
|
||||
|
||||
class BlockCorners : public Allocator<BlockCorners>
|
||||
{
|
||||
private:
|
||||
Vector3 vertices[8];
|
||||
public:
|
||||
BlockCorners(const Vector3& _corner)
|
||||
{
|
||||
Vector3 corner;
|
||||
corner.x = - std::abs(_corner.x);
|
||||
corner.y = - std::abs(_corner.y);
|
||||
corner.z = - std::abs(_corner.z);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
corner.x *= -1.0; // positive for i = 0, negative for i = -1
|
||||
for (int j = 0; j < 2; j++) {
|
||||
corner.y *= -1.0; // positive for j = 0...
|
||||
for (int k = 0; k < 2; k++) {
|
||||
corner.z *= -1.0;
|
||||
vertices[i*4 + j*2 + k] = corner;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const Vector3* getVertices() const {return vertices;}
|
||||
};
|
||||
|
||||
} // namespace POLY
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
Utility class - holds Block Meshes of same size for use by Geometry Pool.
|
||||
*/
|
||||
|
||||
#include "V8World/Mesh.h"
|
||||
#include "Util/Memory.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
namespace POLY {
|
||||
|
||||
class BlockMesh : public Allocator<BlockMesh>
|
||||
{
|
||||
Mesh mesh;
|
||||
public:
|
||||
BlockMesh(const Vector3& size) {
|
||||
mesh.makeBlock(size);
|
||||
}
|
||||
const Mesh* getMesh() const {return &mesh;}
|
||||
};
|
||||
|
||||
} // namespace POLY
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,83 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "v8kernel/ContactConnector.h"
|
||||
#include "v8world/Contact.h"
|
||||
#include "v8world/CellContact.h"
|
||||
|
||||
#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
|
||||
#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
|
||||
|
||||
class btPersistentManifold;
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class BulletConnector: public ContactConnector, public Allocator<BulletConnector>
|
||||
{
|
||||
public:
|
||||
BulletConnector(Body* b0, Body* b1, const ContactParams& contactParams, int manifoldIndex, int cacheIndex);
|
||||
|
||||
int bulletManifoldIndex;
|
||||
int bulletPointCacheIndex;
|
||||
};
|
||||
|
||||
typedef FixedArray<BulletConnector*, 4> BulletConnectorArray;
|
||||
|
||||
class BulletContact: public Contact
|
||||
{
|
||||
public:
|
||||
BulletContact(World* world, Primitive* p0, Primitive* p1);
|
||||
~BulletContact();
|
||||
|
||||
// Contact
|
||||
void deleteAllConnectors() override;
|
||||
int numConnectors() const override;
|
||||
ContactConnector* getConnector(int i) override;
|
||||
|
||||
bool computeIsColliding(float overlapIgnored) override;
|
||||
bool stepContact() override;
|
||||
|
||||
void invalidateContactCache() override;
|
||||
|
||||
private:
|
||||
World* world;
|
||||
|
||||
btCollisionAlgorithm* algorithm;
|
||||
|
||||
btManifoldArray manifoldArray;
|
||||
BulletConnectorArray connectors;
|
||||
};
|
||||
|
||||
class BulletCellContact: public CellContact
|
||||
{
|
||||
public:
|
||||
BulletCellContact(World* world, Primitive* p0, Primitive* p1, const Vector3int32& feature, const shared_ptr<btCollisionShape>& cellShape);
|
||||
~BulletCellContact();
|
||||
|
||||
// Contact
|
||||
void deleteAllConnectors() override;
|
||||
int numConnectors() const override;
|
||||
ContactConnector* getConnector(int i) override;
|
||||
|
||||
bool computeIsColliding(float overlapIgnored) override;
|
||||
bool stepContact() override;
|
||||
|
||||
void invalidateContactCache() override;
|
||||
void onPrimitiveContactParametersChanged() override;
|
||||
|
||||
private:
|
||||
World* world;
|
||||
|
||||
btCollisionAlgorithm* algorithm;
|
||||
|
||||
btManifoldArray manifoldArray;
|
||||
BulletConnectorArray connectors;
|
||||
|
||||
btCollisionObject cellCollisionObject; // collision object for the cell involved in contact
|
||||
shared_ptr<btCollisionShape> cellShape;
|
||||
|
||||
void updateContactParemeters(btCollisionObject* cellObj);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,112 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
Utility class - holds Bullet Shapes for use by Geometry Pool.
|
||||
*/
|
||||
|
||||
#include "Util/Memory.h"
|
||||
|
||||
#include "BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h"
|
||||
#include "BulletCollision/CollisionShapes/btConvexHullShape.h"
|
||||
#include "BulletCollision/CollisionShapes/btConvexPolyhedron.h"
|
||||
#include "BulletCollision/CollisionShapes/btShapeHull.h"
|
||||
#include "BulletCollision/GImpact/btGImpactShape.h"
|
||||
#include "Extras/GIMPACTUtils/btGImpactConvexDecompositionShape.h"
|
||||
#include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h"
|
||||
#include "btBulletCollisionCommon.h"
|
||||
|
||||
// Comment this out to use btCompoundShape and the more robust narrow phase
|
||||
// Uncomment to use btGImpactConvexDecompositionShape
|
||||
#define USE_GIMPACT
|
||||
|
||||
const float bulletCollisionMargin = 0.05f;
|
||||
|
||||
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class BulletDecompWrapper : public Allocator<BulletDecompWrapper>
|
||||
{
|
||||
public:
|
||||
#ifdef USE_GIMPACT
|
||||
typedef btGImpactConvexDecompositionShape ShapeType;
|
||||
#else
|
||||
typedef btCompoundShape ShapeType;
|
||||
#endif
|
||||
|
||||
struct ConvexExtents
|
||||
{
|
||||
Vector3 center;
|
||||
Vector3 size;
|
||||
};
|
||||
|
||||
BulletDecompWrapper(const std::string& str);
|
||||
~BulletDecompWrapper();
|
||||
|
||||
const ShapeType* getCompound() const { return decomp; }
|
||||
const std::vector<ConvexExtents>& getExtentArray() const { return extentArray; }
|
||||
|
||||
private:
|
||||
ShapeType* decomp;
|
||||
std::vector<ConvexExtents> extentArray;
|
||||
};
|
||||
|
||||
class BulletBoxShapeWrapper : public Allocator<BulletBoxShapeWrapper>
|
||||
{
|
||||
private:
|
||||
btBoxShape* boxShape;
|
||||
|
||||
public:
|
||||
const btBoxShape* getShape(void) const { return boxShape; }
|
||||
BulletBoxShapeWrapper(const Vector3& key);
|
||||
~BulletBoxShapeWrapper();
|
||||
|
||||
};
|
||||
|
||||
class BulletSphereShapeWrapper : public Allocator<BulletSphereShapeWrapper>
|
||||
{
|
||||
private:
|
||||
btSphereShape* sphereShape;
|
||||
|
||||
public:
|
||||
const btSphereShape* getShape(void) const { return sphereShape; }
|
||||
BulletSphereShapeWrapper(const float& key);
|
||||
~BulletSphereShapeWrapper();
|
||||
|
||||
};
|
||||
|
||||
class BulletCylinderShapeWrapper : public Allocator<BulletCylinderShapeWrapper>
|
||||
{
|
||||
private:
|
||||
btCylinderShape* cylinderShape;
|
||||
|
||||
public:
|
||||
const btCylinderShape* getShape(void) const { return cylinderShape; }
|
||||
BulletCylinderShapeWrapper(const Vector3& key);
|
||||
~BulletCylinderShapeWrapper();
|
||||
};
|
||||
|
||||
class BulletWedgeShapeWrapper : public Allocator<BulletWedgeShapeWrapper>
|
||||
{
|
||||
private:
|
||||
btConvexHullShape* wedgeShape;
|
||||
|
||||
public:
|
||||
const btConvexHullShape* getShape(void) const { return wedgeShape; }
|
||||
BulletWedgeShapeWrapper(const Vector3& key);
|
||||
~BulletWedgeShapeWrapper();
|
||||
|
||||
};
|
||||
|
||||
class BulletCornerWedgeShapeWrapper : public Allocator<BulletCornerWedgeShapeWrapper>
|
||||
{
|
||||
private:
|
||||
btConvexHullShape* cornerWedgeShape;
|
||||
|
||||
public:
|
||||
const btConvexHullShape* getShape(void) const { return cornerWedgeShape; }
|
||||
BulletCornerWedgeShapeWrapper(const Vector3& key);
|
||||
~BulletCornerWedgeShapeWrapper();
|
||||
|
||||
};
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,72 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/CellContact.h"
|
||||
#include "V8World/Mesh.h"
|
||||
#include "Voxel/Util.h"
|
||||
|
||||
#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h"
|
||||
#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
|
||||
#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
|
||||
|
||||
|
||||
class btPersistentManifold;
|
||||
class bulletNPAlgorithm;
|
||||
class btConvexHullShape;
|
||||
namespace RBX {
|
||||
class PolyConnector;
|
||||
class BulletShapeCellConnector;
|
||||
class BulletShapeCellContact : public CellMeshContact
|
||||
{
|
||||
public:
|
||||
typedef RBX::FixedArray<BulletShapeCellConnector*, BULLET_CONTACT_ARRAY_SIZE> BulletConnectorArray;
|
||||
|
||||
private:
|
||||
btCollisionAlgorithm* bulletNPAlgorithm;
|
||||
|
||||
btCollisionObject bulletCollisionObject; // collision object for the cell involved in contact
|
||||
|
||||
shared_ptr<btCollisionShape> customShape;
|
||||
|
||||
BulletConnectorArray polyConnectors;
|
||||
|
||||
World* world;
|
||||
|
||||
void removeAllConnectorsFromKernel();
|
||||
void putAllConnectorsInKernel();
|
||||
void updateClosestFeatures();
|
||||
float worstFeatureOverlap();
|
||||
void deleteConnectors(BulletConnectorArray& deleteConnectors);
|
||||
void matchClosestFeatures(BulletConnectorArray& newConnectors);
|
||||
BulletShapeCellConnector* matchClosestFeature(BulletShapeCellConnector* newConnector);
|
||||
// Terrain Materials
|
||||
void updateContactParemeters(btCollisionObject* cellObj, BulletConnectorArray& connectors);
|
||||
|
||||
|
||||
// use a BulletShapeConnector to represent this connector (we don't need a specific BulletShapeCellConnector)
|
||||
BulletShapeCellConnector* newBulletShapeCellConnector(btCollisionObject* bulletColObj0, btCollisionObject* bulletColObj1,
|
||||
btCollisionAlgorithm* algo, int manifoldIndex, int contactIndex);
|
||||
|
||||
void updateContactPoints();
|
||||
void computeManifoldsWithBulletNarrowPhase(btManifoldArray& manifoldArray);
|
||||
|
||||
// Contact
|
||||
void deleteAllConnectors() override;
|
||||
int numConnectors() const override {return polyConnectors.size();}
|
||||
ContactConnector* getConnector(int i) override;
|
||||
bool computeIsColliding(float overlapIgnored) override;
|
||||
bool stepContact() override;
|
||||
|
||||
void invalidateContactCache() override;
|
||||
|
||||
void findClosestFeatures(ConnectorArray& newConnectors) override {RBXASSERT(0);} // don't use this when using btCompound Narrow Phase
|
||||
// since it generates too many connectors
|
||||
void findClosestBulletCellFeatures(BulletConnectorArray& newConnectors);
|
||||
|
||||
public:
|
||||
BulletShapeCellContact(Primitive* p0, Primitive* p1, const Vector3int16& cell, World* contactWorld);
|
||||
BulletShapeCellContact(Primitive* p0, Primitive* p1, const Vector3int32& feature, const shared_ptr<btCollisionShape>& customShape, World* contactWorld);
|
||||
~BulletShapeCellContact();
|
||||
};
|
||||
} // namespace
|
||||
@@ -0,0 +1,55 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/Contact.h"
|
||||
#include "V8World/Mesh.h"
|
||||
#include "Voxel/Util.h"
|
||||
#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h"
|
||||
#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
|
||||
|
||||
class btPersistentManifold;
|
||||
class bulletNPAlgorithm;
|
||||
class btConvexHullShape;
|
||||
namespace RBX {
|
||||
class PolyConnector;
|
||||
class BulletShapeConnector;
|
||||
class BulletShapeContact : public Contact
|
||||
{
|
||||
public:
|
||||
typedef RBX::FixedArray<BulletShapeConnector*, BULLET_CONTACT_ARRAY_SIZE> BulletConnectorArray;
|
||||
|
||||
private:
|
||||
btPersistentManifold* bulletManifold;
|
||||
btCollisionAlgorithm* bulletNPAlgorithm;
|
||||
BulletConnectorArray polyConnectors;
|
||||
World* world;
|
||||
|
||||
void removeAllConnectorsFromKernel();
|
||||
void putAllConnectorsInKernel();
|
||||
void updateClosestFeatures();
|
||||
float worstFeatureOverlap();
|
||||
void matchClosestFeatures(BulletConnectorArray& newConnectors);
|
||||
BulletShapeConnector* matchClosestFeature(BulletShapeConnector* newConnector);
|
||||
void deleteConnectors(BulletConnectorArray& deleteConnectors);
|
||||
BulletShapeConnector* newBulletShapeConnector(btCollisionObject* bulletColObj0, btCollisionObject* bulletColObj1,
|
||||
btCollisionAlgorithm* algo, int manifoldIndex, int contactIndex, bool swapped);
|
||||
void updateContactPoints();
|
||||
void computeManifoldsWithBulletNarrowPhase(btManifoldArray& manifoldArray);
|
||||
|
||||
// Contact
|
||||
void deleteAllConnectors() override;
|
||||
int numConnectors() const override {return polyConnectors.size();}
|
||||
ContactConnector* getConnector(int i) override;
|
||||
bool computeIsColliding(float overlapIgnored) override;
|
||||
bool stepContact() override;
|
||||
|
||||
void invalidateContactCache() override;
|
||||
|
||||
/*implement*/ void findClosestFeatures(BulletConnectorArray& newConnectors);
|
||||
|
||||
public:
|
||||
BulletShapeContact(Primitive* p0, Primitive* p1, World* ourWorld);
|
||||
~BulletShapeContact();
|
||||
};
|
||||
} // namespace
|
||||
@@ -0,0 +1,181 @@
|
||||
#pragma once
|
||||
|
||||
#include "Voxel/Cell.h"
|
||||
#include "v8kernel/BuoyancyConnector.h"
|
||||
#include "v8World/Geometry.h"
|
||||
#include "v8World/Contact.h"
|
||||
|
||||
/*
|
||||
The Buoyancy feature manages all aspects of parts' interaction with water when they have come
|
||||
into contact with water.
|
||||
|
||||
The Buoyancy contact is implemented as a standard contact type managed by ContactManager.
|
||||
|
||||
Each BuoyancyContact manages a few BuoyancyConnectors that represent the buoyancy and water
|
||||
viscosity forces applied on the part.
|
||||
|
||||
Box Buoyancy is divided into 8 voxels, each voxel contributes one connector that represents
|
||||
the buoyancy and viscosity force applied on that voxel shape.
|
||||
*/
|
||||
|
||||
namespace RBX {
|
||||
|
||||
namespace Voxel { class Grid; }
|
||||
namespace Voxel2 { class Grid; }
|
||||
|
||||
class BuoyancyContact : public Contact
|
||||
{
|
||||
public:
|
||||
static const int MAX_CONNECTORS = 8;
|
||||
static float waterViscosity;
|
||||
static const float waterDensity;
|
||||
|
||||
typedef RBX::FixedArray<BuoyancyConnector*, MAX_CONNECTORS> ConnectorArray;
|
||||
|
||||
static Geometry::GeometryType determineGeometricType( Primitive *prim );
|
||||
static BuoyancyContact* create( Primitive* p0, Primitive *p1 );
|
||||
|
||||
BuoyancyContact( Primitive* p0, Primitive* p1 );
|
||||
~BuoyancyContact();
|
||||
|
||||
virtual Geometry::GeometryType getType() = 0;
|
||||
|
||||
ContactType getContactType() const override { return Contact_Buoyancy; }
|
||||
|
||||
void onPrimitiveContactParametersChanged() override;
|
||||
|
||||
private:
|
||||
void deleteConnectors();
|
||||
|
||||
void updateBuoyancyFloatingForce();
|
||||
|
||||
protected:
|
||||
ConnectorArray connectors;
|
||||
Primitive* floaterPrim;
|
||||
|
||||
Voxel::Grid* voxelGrid;
|
||||
Voxel2::Grid* smoothGrid;
|
||||
|
||||
float radius;
|
||||
float fullSurfaceArea;
|
||||
Vector3 fullBuoyancy;
|
||||
|
||||
bool worldPosUnderWater( const Vector3& pos );
|
||||
bool isTouchingWater( Primitive* prim );
|
||||
|
||||
Voxel::Cell getWaterCell( Vector3int16 pos );
|
||||
bool cellHasWater( Vector3int16 pos );
|
||||
|
||||
bool hasDistanceSubmergedUnderWater( const Vector3& worldpos, float& waterLevel, const Vector3& searchEnd );
|
||||
bool worldPosAboveWater( const Vector3& worldpos, int minY, float& waterLevel );
|
||||
Vector3 cellVelocity( const Vector3& worldpos );
|
||||
|
||||
void removeAllConnectorsFromKernel();
|
||||
void putAllConnectorsInKernel();
|
||||
void computeExtentsWaterBand( const Extents& extents, float& floatDistance, float& sinkDistance );
|
||||
void updateConnectors();
|
||||
|
||||
// Contact API
|
||||
void deleteAllConnectors() override;
|
||||
int numConnectors() const override { return connectors.size(); }
|
||||
ContactConnector* getConnector( int i ) override { return connectors[i]; }
|
||||
bool stepContact() override;
|
||||
bool computeIsColliding(float overlapIgnored) override;
|
||||
bool computeIsCollidingUi(float overlapIgnored) override; // override to always return false so can build underwater; shouldn't affect HumanoidState code
|
||||
|
||||
// Buoyancy Shape API
|
||||
virtual Vector3 getWaterVelocity(int i);
|
||||
virtual void createConnectors() = 0;
|
||||
virtual void updateWaterBand() = 0;
|
||||
virtual void updateSubmergeRatio();
|
||||
virtual void getSurfaceAreaInDirection(const Vector3& relativeVelocity, float& crossArea, float& tangentArea) = 0;
|
||||
virtual void initializeCrossSections() = 0;
|
||||
virtual Vector3 getCrossSections(int i, const Vector3& velocity) = 0;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class BuoyancyBallContact : public BuoyancyContact
|
||||
{
|
||||
|
||||
protected:
|
||||
float crossSectionArea;
|
||||
|
||||
bool computeIsColliding(float overlapIgnored);
|
||||
void createConnectors();
|
||||
Vector3 getWaterVelocity(int i);
|
||||
void updateWaterBand();
|
||||
void updateSubmergeRatio();
|
||||
void getSurfaceAreaInDirection(const Vector3& relativeVelocity, float& crossArea, float& tangentArea);
|
||||
void initializeCrossSections();
|
||||
virtual Vector3 getCrossSections(int, const Vector3&);
|
||||
|
||||
public:
|
||||
BuoyancyBallContact( Primitive* p0, Primitive* p1 ) : BuoyancyContact(p0, p1) {}
|
||||
Geometry::GeometryType getType() { return Geometry::GEOMETRY_BALL; }
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class BuoyancyBoxContact : public BuoyancyContact
|
||||
{
|
||||
|
||||
protected:
|
||||
Vector3 crossSectionSurfaceAreas;
|
||||
Vector3 tangentSurfaceAreas;
|
||||
|
||||
void createConnectors();
|
||||
void updateWaterBand();
|
||||
virtual void getSurfaceAreaInDirection(const Vector3& relativeVelocity, float& crossSectionArea, float& tangentSurfaceAread);
|
||||
virtual void initializeCrossSections();
|
||||
Vector3 getCrossSections( int i, const Vector3& velocity );
|
||||
public:
|
||||
BuoyancyBoxContact( Primitive* p0, Primitive* p1 );
|
||||
Geometry::GeometryType getType() { return Geometry::GEOMETRY_BLOCK; }
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class BuoyancyCylinderContact : public BuoyancyBoxContact
|
||||
{
|
||||
protected:
|
||||
void updateSubmergeRatio();
|
||||
void initializeCrossSections();
|
||||
|
||||
public:
|
||||
BuoyancyCylinderContact( Primitive* p0, Primitive* p1 ) : BuoyancyBoxContact(p0, p1) {}
|
||||
Geometry::GeometryType getType() { return Geometry::GEOMETRY_CYLINDER; }
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class BuoyancyWedgeContact : public BuoyancyBoxContact
|
||||
{
|
||||
|
||||
protected:
|
||||
void updateSubmergeRatio();
|
||||
void initializeCrossSections();
|
||||
|
||||
public:
|
||||
BuoyancyWedgeContact( Primitive* p0, Primitive* p1 ) : BuoyancyBoxContact(p0, p1) {}
|
||||
Geometry::GeometryType getType() { return Geometry::GEOMETRY_WEDGE; }
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class BuoyancyCornerWedgeContact : public BuoyancyBoxContact
|
||||
{
|
||||
protected:
|
||||
void updateSubmergeRatio();
|
||||
void initializeCrossSections();
|
||||
|
||||
public:
|
||||
BuoyancyCornerWedgeContact( Primitive* p0, Primitive* p1 ) : BuoyancyBoxContact(p0, p1) {}
|
||||
Geometry::GeometryType getType() { return Geometry::GEOMETRY_CORNERWEDGE; }
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/Contact.h"
|
||||
#include "V8World/Mesh.h"
|
||||
#include "Voxel/Util.h"
|
||||
#include "Util/Vector3int32.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class PolyConnector;
|
||||
|
||||
const Vector3int16 kFaceDirectionToLocationOffset[7] =
|
||||
{
|
||||
Vector3int16( 1, 0, 0),
|
||||
Vector3int16( 0, 0, 1),
|
||||
Vector3int16(-1, 0, 0),
|
||||
Vector3int16( 0, 0,-1),
|
||||
Vector3int16( 0, 1, 0),
|
||||
Vector3int16( 0,-1, 0),
|
||||
Vector3int16( 0, 0, 0),
|
||||
};
|
||||
|
||||
static inline Voxel::FaceDirection oppositeSideOffset(Voxel::FaceDirection f)
|
||||
{
|
||||
static Voxel::FaceDirection OPPOSITES[6] = { Voxel::MinusX, Voxel::MinusZ, Voxel::PlusX, Voxel::PlusZ, Voxel::MinusY, Voxel::PlusY };
|
||||
return OPPOSITES[f];
|
||||
}
|
||||
|
||||
class CellContact: public Contact
|
||||
{
|
||||
public:
|
||||
CellContact(Primitive* p0, Primitive* p1, const Vector3int32& gridFeature)
|
||||
: Contact(p0, p1)
|
||||
, gridFeature(gridFeature)
|
||||
{}
|
||||
|
||||
const Vector3int32& getGridFeature() const { return gridFeature; }
|
||||
|
||||
virtual ContactType getContactType() const { return Contact_Cell; }
|
||||
|
||||
protected:
|
||||
Vector3int32 gridFeature;
|
||||
};
|
||||
|
||||
class CellMeshContact: public CellContact
|
||||
{
|
||||
public:
|
||||
typedef RBX::FixedArray<PolyConnector*, CONTACT_ARRAY_SIZE> ConnectorArray; // TODO - should only ever need 8
|
||||
|
||||
protected:
|
||||
POLY::Mesh* cellMesh;
|
||||
|
||||
private:
|
||||
ConnectorArray polyConnectors;
|
||||
|
||||
void removeAllConnectorsFromKernel();
|
||||
void putAllConnectorsInKernel();
|
||||
void updateClosestFeatures();
|
||||
float worstFeatureOverlap();
|
||||
void deleteConnectors(ConnectorArray& deleteConnectors);
|
||||
void matchClosestFeatures(ConnectorArray& newConnectors);
|
||||
PolyConnector* matchClosestFeature(PolyConnector* newConnector);
|
||||
void updateContactPoints();
|
||||
|
||||
// Contact
|
||||
/*override*/ void deleteAllConnectors();
|
||||
/*override*/ int numConnectors() const {return polyConnectors.size();}
|
||||
/*override*/ ContactConnector* getConnector(int i);
|
||||
/*override*/ bool computeIsColliding(float overlapIgnored);
|
||||
/*override*/ bool stepContact();
|
||||
|
||||
/*implement*/ virtual void findClosestFeatures(ConnectorArray& newConnectors) = 0;
|
||||
|
||||
public:
|
||||
CellMeshContact(Primitive* p0, Primitive* p1, const Vector3int32& gridFeature)
|
||||
: CellContact(p0, p1, gridFeature)
|
||||
, cellMesh(NULL)
|
||||
{}
|
||||
|
||||
~CellMeshContact();
|
||||
|
||||
POLY::Mesh* getCellMesh(void) {return cellMesh;}
|
||||
|
||||
bool cellFaceIsInterior(const Vector3int16& mainCellLoc, RBX::Voxel::FaceDirection faceDir);
|
||||
};
|
||||
} // namespace
|
||||
@@ -0,0 +1,49 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/IWorldStage.h"
|
||||
#include <map>
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Joint;
|
||||
class Primitive;
|
||||
/*
|
||||
Sits between the world and the JointStage (for now, the engine);
|
||||
|
||||
Receives:
|
||||
1) Primitives
|
||||
2) Edges (Joints and Contacts)
|
||||
|
||||
Passes Downstream:
|
||||
1) Primitives
|
||||
2) Edges
|
||||
a) between two primitives, both different, both non-null
|
||||
*/
|
||||
|
||||
class CleanStage : public IWorldStage {
|
||||
private:
|
||||
class JointStage* getJointStage();
|
||||
|
||||
bool primitivesAreOk(Edge* e);
|
||||
|
||||
public:
|
||||
///////////////////////////////////////////
|
||||
// IStage
|
||||
CleanStage(IStage* upstream, World* world);
|
||||
|
||||
~CleanStage() {}
|
||||
|
||||
/*override*/ IStage::StageType getStageType() const {return IStage::CLEAN_STAGE;}
|
||||
|
||||
/*override*/ void onEdgeAdded(Edge* e);
|
||||
/*override*/ void onEdgeRemoving(Edge* e);
|
||||
|
||||
void onPrimitiveAdded(Primitive* p);
|
||||
void onPrimitiveRemoving(Primitive* p);
|
||||
|
||||
void onJointPrimitiveNulling(Joint* j, Primitive* nulling);
|
||||
void onJointPrimitiveSet(Joint* j, Primitive* p);
|
||||
};
|
||||
} // namespace
|
||||
@@ -0,0 +1,63 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "rbx/Debug.h"
|
||||
#include "Util/IndexedMesh.h"
|
||||
#include "Primitive.h"
|
||||
#include <set>
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Edge;
|
||||
class Joint;
|
||||
class Clump;
|
||||
class PrimIterator;
|
||||
|
||||
class Clump
|
||||
: public boost::noncopyable
|
||||
, public IndexedMesh
|
||||
{
|
||||
private:
|
||||
template<class Func>
|
||||
inline void visitPrimitivesImpl(Func func, Primitive* p) {
|
||||
func(p);
|
||||
for (int i = 0; i < p->numChildren(); ++i) {
|
||||
Primitive* child = p->getTypedChild<Primitive>(i);
|
||||
if (!Clump::isClumpRootPrimitive(child)) {
|
||||
visitPrimitivesImpl(func, child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
Clump();
|
||||
|
||||
~Clump();
|
||||
|
||||
Clump* getRootClump() {return getRoot<Clump>();}
|
||||
const Clump* getRootClump() const {return getRoot<Clump>();}
|
||||
|
||||
Primitive* getClumpPrimitive() {return rbx_static_cast<Primitive*>(getLower());}
|
||||
const Primitive* getConstClumpPrimitive() const {return rbx_static_cast<const Primitive*>(getConstLower());}
|
||||
|
||||
static Clump* getPrimitiveClump(Primitive* p);
|
||||
static const Clump* getConstPrimitiveClump(const Primitive* p);
|
||||
static bool isClumpRootPrimitive(const Primitive* p);
|
||||
|
||||
void loadMotors(G3D::Array<Joint*>& load, bool nonAnimatedOnly);
|
||||
void loadConstMotors(G3D::Array<const Joint*>& load, bool nonAnimatedOnly) const;
|
||||
|
||||
template<class Func>
|
||||
inline void visitPrimitives(Func func) {
|
||||
Primitive* p = getClumpPrimitive();
|
||||
RBXASSERT(p);
|
||||
visitPrimitivesImpl(func, p);
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,327 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/Edge.h"
|
||||
#include "V8World/Feature.h"
|
||||
#include "V8Kernel/ContactParams.h"
|
||||
#include "Util/G3DCore.h"
|
||||
#include "Util/Memory.h"
|
||||
#include "Util/NormalId.h"
|
||||
#include "Util/Math.h"
|
||||
#include "Util/FixedArray.h"
|
||||
#include "rbx/Debug.h"
|
||||
#include "rbx/Declarations.h"
|
||||
|
||||
#define CONTACT_ARRAY_SIZE 40
|
||||
#define BULLET_CONTACT_ARRAY_SIZE 40
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Kernel;
|
||||
class CollisionStage;
|
||||
class ContactConnector;
|
||||
class GeoPairConnector;
|
||||
class BallBlockConnector;
|
||||
class BallBallConnector;
|
||||
class Body;
|
||||
class Ball;
|
||||
class Block;
|
||||
class BlockBlockContactData;
|
||||
|
||||
class RBXBaseClass Contact : public Edge
|
||||
{
|
||||
private:
|
||||
typedef Edge Super;
|
||||
|
||||
friend class CollisionStage;
|
||||
|
||||
|
||||
static bool ignoreBool;
|
||||
|
||||
// CollisionStage
|
||||
int lastUiContactStep;
|
||||
int steppingIndex; // For fast removal from the collision stage stepping list
|
||||
short numTouchCycles;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//
|
||||
// Edge
|
||||
|
||||
/*override*/ void putInKernel(Kernel* _kernel) {
|
||||
Super::putInKernel(_kernel);
|
||||
}
|
||||
|
||||
/*override*/ void removeFromKernel() {
|
||||
RBXASSERT(getKernel());
|
||||
deleteAllConnectors();
|
||||
Super::removeFromKernel();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// Edge Virtuals
|
||||
//
|
||||
/*override*/ virtual EdgeType getEdgeType() const {return Edge::CONTACT;}
|
||||
|
||||
protected:
|
||||
ContactParams* contactParams;
|
||||
Body* getBody(int i);
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//
|
||||
// ContactPairData management
|
||||
|
||||
void deleteConnector(ContactConnector* c);
|
||||
|
||||
virtual void deleteAllConnectors() = 0; // everyone implements this
|
||||
|
||||
virtual bool stepContact() = 0;
|
||||
|
||||
public:
|
||||
enum ContactType
|
||||
{
|
||||
Contact_Simple,
|
||||
Contact_Cell,
|
||||
Contact_Buoyancy,
|
||||
};
|
||||
|
||||
Contact(Primitive* p0, Primitive* p1);
|
||||
|
||||
virtual ~Contact();
|
||||
|
||||
short getNumTouchCycles() {return numTouchCycles;}
|
||||
|
||||
int& steppingIndexFunc() {return steppingIndex;} // fast removal from stepping list
|
||||
|
||||
// Proximite tests - compute
|
||||
typedef bool (Contact::*ProximityTest)(float);
|
||||
|
||||
bool computeIsAdjacentUi(float spaceAllowed);
|
||||
|
||||
virtual bool computeIsCollidingUi(float overlapIgnored);
|
||||
|
||||
virtual bool computeIsColliding(float overlapIgnored) = 0;
|
||||
|
||||
static bool isContact(Edge* e) {return (e->getEdgeType() == Edge::CONTACT);}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//
|
||||
// From The Contact Manager
|
||||
virtual void onPrimitiveContactParametersChanged();
|
||||
|
||||
bool step(int uiStepId);
|
||||
|
||||
virtual int numConnectors() const = 0;
|
||||
|
||||
virtual ContactConnector* getConnector(int i) = 0;
|
||||
|
||||
void primitiveMovedExternally();
|
||||
|
||||
virtual void generateDataForMovingAssemblyStage(void);
|
||||
|
||||
virtual void invalidateContactCache();
|
||||
|
||||
ContactParams* getContactParams(void) { return contactParams; }
|
||||
|
||||
bool isInContact() { return lastUiContactStep > 0; }
|
||||
|
||||
virtual ContactType getContactType() const { return Contact_Simple; }
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class BallBallContact
|
||||
: public Contact
|
||||
, public Allocator<BallBallContact>
|
||||
{
|
||||
private:
|
||||
BallBallConnector* ballBallConnector;
|
||||
|
||||
Ball* ball(int i);
|
||||
|
||||
/*override*/ void deleteAllConnectors();
|
||||
/*override*/ bool computeIsColliding(float overlapIgnored);
|
||||
/*override*/ bool stepContact();
|
||||
|
||||
/*override*/ int numConnectors() const {return ballBallConnector ? 1 : 0;}
|
||||
/*override*/ ContactConnector* getConnector(int i);
|
||||
|
||||
public:
|
||||
BallBallContact(Primitive* p0, Primitive* p1)
|
||||
: Contact(p0, p1)
|
||||
, ballBallConnector(NULL)
|
||||
{}
|
||||
|
||||
~BallBallContact() {RBXASSERT(!ballBallConnector);}
|
||||
|
||||
void generateDataForMovingAssemblyStage(void); /*override*/
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
class BallBlockContact
|
||||
: public Contact
|
||||
, public Allocator<BallBlockContact>
|
||||
{
|
||||
private:
|
||||
BallBlockConnector* ballBlockConnector;
|
||||
|
||||
Primitive* ballPrim();
|
||||
Primitive* blockPrim();
|
||||
|
||||
Ball* ball();
|
||||
Block* block();
|
||||
|
||||
bool computeIsColliding(
|
||||
int& onBorder,
|
||||
Vector3int16& clip,
|
||||
Vector3& projectionInBlock,
|
||||
float overlapIgnored);
|
||||
|
||||
/*override*/ void deleteAllConnectors();
|
||||
/*override*/ bool computeIsColliding(float overlapIgnored);
|
||||
/*override*/ bool stepContact();
|
||||
|
||||
/*override*/ int numConnectors() const {return ballBlockConnector ? 1 : 0;}
|
||||
/*override*/ ContactConnector* getConnector(int i);
|
||||
|
||||
public:
|
||||
BallBlockContact(Primitive* p0, Primitive* p1)
|
||||
: Contact(p0, p1)
|
||||
, ballBlockConnector(NULL)
|
||||
{}
|
||||
|
||||
~BallBlockContact() {RBXASSERT(!ballBlockConnector);}
|
||||
|
||||
void generateDataForMovingAssemblyStage(void); /*override*/
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class BlockBlockContact
|
||||
: public Contact
|
||||
, public Allocator<BlockBlockContact>
|
||||
{
|
||||
private:
|
||||
static int pairMatches;
|
||||
static int pairMisses;
|
||||
static int featureMatches;
|
||||
static int featureMisses;
|
||||
|
||||
typedef RBX::FixedArray<GeoPairConnector*, 8> ConnectorArray;
|
||||
|
||||
friend class BlockBlockContactData;
|
||||
BlockBlockContactData* myData;
|
||||
|
||||
Block* block(int i);
|
||||
|
||||
GeoPairConnector* findGeoPairConnector(
|
||||
Body* b0,
|
||||
Body* b1,
|
||||
GeoPairType _pairType,
|
||||
int param0,
|
||||
int param1);
|
||||
|
||||
void loadGeoPairEdgeEdge(
|
||||
int b0,
|
||||
int b1,
|
||||
int edge0,
|
||||
int edge1);
|
||||
|
||||
void loadGeoPairPointPlane(
|
||||
int pointBody,
|
||||
int planeBody, int pointID,
|
||||
NormalId pointFaceID,
|
||||
NormalId planeFaceID);
|
||||
|
||||
// plane contact - first compute the feature0, feature1
|
||||
bool getBestPlaneEdge(float overlapIgnored, bool& planeContact);
|
||||
|
||||
int intersectRectQuad(Vector2& planeRect, Vector2 (&otherQuad)[4]);
|
||||
|
||||
bool computeIsColliding(float overlapIgnored, bool& planeContact);
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// Contact
|
||||
/*override*/ void deleteAllConnectors(void);
|
||||
/*override*/ bool computeIsColliding(float overlapIgnored);
|
||||
/*override*/ bool stepContact();
|
||||
|
||||
/*override*/ int numConnectors() const;
|
||||
/*override*/ ContactConnector* getConnector(int i);
|
||||
|
||||
public:
|
||||
BlockBlockContact(Primitive* p0, Primitive* p1);
|
||||
~BlockBlockContact();
|
||||
|
||||
static float pairHitRatio();
|
||||
static float featureHitRatio();
|
||||
|
||||
void generateDataForMovingAssemblyStage(void); /*override*/
|
||||
|
||||
private:
|
||||
inline static void boxProjection(const Vector3& normal0, const Matrix3& R1, const Vector3& extent1, float& projectedExtent)
|
||||
{
|
||||
Vector3 temp = Math::vectorToObjectSpace(normal0, R1);
|
||||
projectedExtent = std::abs( extent1[0] * temp[0] )
|
||||
+ std::abs( extent1[1] * temp[1] )
|
||||
+ std::abs( extent1[2] * temp[2] );
|
||||
}
|
||||
|
||||
// if length < 0, no overlap, and no block/block contact
|
||||
// proj0 >0 on entry
|
||||
// proj1 >0 on entry
|
||||
|
||||
inline static bool updateBestAxis(float proj0, float p0p1, float proj1, float& _overlap, float overlapIgnored)
|
||||
{
|
||||
// no overlap along this axis - bail, not in contact
|
||||
_overlap = proj0 + proj1 - std::abs(p0p1);
|
||||
return (_overlap > overlapIgnored);
|
||||
}
|
||||
|
||||
bool geoFeaturesOverlap(
|
||||
int pointBody,
|
||||
int planeBody,
|
||||
int pointID,
|
||||
NormalId pointFaceID,
|
||||
NormalId planeFaceID);
|
||||
};
|
||||
|
||||
class BlockBlockContactData
|
||||
{
|
||||
friend class BlockBlockContact;
|
||||
|
||||
private:
|
||||
BlockBlockContact::ConnectorArray connectors[2];
|
||||
int connectorsIndex;
|
||||
|
||||
// for hysteresis:
|
||||
int witnessId;
|
||||
int separatingAxisId;
|
||||
|
||||
int feature[2]; // -1 no feature, 0..5 plane, 6..8 edge Normal,
|
||||
int bPlane;
|
||||
int bOther;
|
||||
RBX::NormalId planeID;
|
||||
RBX::NormalId otherPlaneID;
|
||||
|
||||
BlockBlockContact* myOwner;
|
||||
|
||||
public:
|
||||
BlockBlockContactData(BlockBlockContact* owner);
|
||||
~BlockBlockContactData() {}
|
||||
|
||||
int numConnectors() const { return connectors[connectorsIndex].size(); }
|
||||
ContactConnector* getConnector( int i );
|
||||
void clearConnectors( void );
|
||||
GeoPairConnector* findGeoPairConnector( Body* b0, Body* b1, GeoPairType _pairType, int param0, int param1 );
|
||||
bool stepContact();
|
||||
void loadGeoPairEdgeEdgePlane( int edgeBody, int planeBody, int edge0, int edge1 );
|
||||
bool getBestPlaneEdge(float overlapIgnored, bool& planeContact);
|
||||
int computePlaneContact(void);
|
||||
int intersectRectQuad(Vector2& planeRect, Vector2 (&otherQuad)[4]);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,209 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "G3D/Array.h"
|
||||
#include "Util/ConcurrencyValidator.h"
|
||||
#include "Util/G3DCore.h"
|
||||
#include "Util/HitTestFilter.h"
|
||||
#include "Util/SpatialRegion.h"
|
||||
#include "Util/SystemAddress.h"
|
||||
#include "Voxel/CellChangeListener.h"
|
||||
#include "Util/Extents.h"
|
||||
#include "Util/Region3.h"
|
||||
#include "Voxel2/GridListener.h"
|
||||
#include "v8world/TerrainPartition.h"
|
||||
#include "v8tree/Instance.h"
|
||||
#include "util/PartMaterial.h"
|
||||
|
||||
#include "rbx/DenseHash.h"
|
||||
|
||||
#include <set>
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
namespace RBX {
|
||||
namespace Graphics {
|
||||
class CullableSceneNode;
|
||||
} }
|
||||
|
||||
namespace RBX {
|
||||
|
||||
namespace Profiling
|
||||
{
|
||||
class CodeProfiler;
|
||||
}
|
||||
|
||||
class Primitive;
|
||||
class Contact;
|
||||
class Joint;
|
||||
class World;
|
||||
class ContactManagerSpatialHash;
|
||||
class MegaClusterInstance;
|
||||
|
||||
namespace Voxel { class Grid; }
|
||||
namespace Voxel2 { class Grid; }
|
||||
|
||||
class ContactManager:
|
||||
public Voxel::CellChangeListener,
|
||||
public Voxel2::GridListener
|
||||
{
|
||||
ConcurrencyValidator concurrencyValidator;
|
||||
ContactManagerSpatialHash* spatialHash;
|
||||
Primitive* myMegaClusterPrim;
|
||||
World* world;
|
||||
|
||||
typedef boost::unordered_set<SpatialRegion::Id, SpatialRegion::Id::boost_compatible_hash_value> UpdatedTerrainRegionsSet;
|
||||
UpdatedTerrainRegionsSet updatedTerrainRegions;
|
||||
|
||||
typedef boost::unordered_set<Vector3int32> UpdatedTerrainChunksSet;
|
||||
UpdatedTerrainChunksSet updatedTerrainChunks;
|
||||
|
||||
std::vector<TerrainPartitionSmooth::ChunkResult> tempChunks;
|
||||
std::vector<Primitive*> tempPrimitives;
|
||||
|
||||
static Vector3 dummySurfaceNormal;
|
||||
static PartMaterial dummySurfaceMaterial;
|
||||
|
||||
Contact* createContact(Primitive* p0, Primitive* p1);
|
||||
|
||||
// TODO: All private and public *Hit() methods have too many arguments!
|
||||
// Refactor to use struct to bundle arguments
|
||||
Primitive* getSlowHit( const G3D::Array<Primitive*>& primitives,
|
||||
const RbxRay& unitRay,
|
||||
const G3D::Array<const Primitive*>& ignorePrim,
|
||||
const HitTestFilter* filter,
|
||||
Vector3& hitPointWorld,
|
||||
Vector3& surfaceNormal,
|
||||
PartMaterial& surfaceMaterial,
|
||||
float maxDistance,
|
||||
bool& stopped) const;
|
||||
|
||||
Primitive* getFastHit( const RbxRay& worldRay, // implies distance as well
|
||||
const G3D::Array<const Primitive*>& ignorePrim, // set to NULL to not use
|
||||
const HitTestFilter* filter, // set to NULL to not use
|
||||
Vector3& hitPointWorld,
|
||||
bool& stopped,
|
||||
bool terrainCellsAreCubes,
|
||||
bool ignoreWater,
|
||||
Vector3& surfaceNormal,
|
||||
PartMaterial& surfaceMaterial) const;
|
||||
|
||||
/*override*/ virtual void terrainCellChanged(const Voxel::CellChangeInfo& info);
|
||||
/*override*/ virtual void onTerrainRegionChanged(const Voxel2::Region& region);
|
||||
|
||||
bool checkMegaClusterWaterContact(Primitive* p, const Vector3int16& extentStart,
|
||||
const Vector3int16& extentEnd, const Vector3int16& extentSize);
|
||||
bool checkMegaClusterSmallTerrainContact(Primitive* otherPrim, const Vector3int16& extentStart,
|
||||
const Vector3int16& extentEnd, const Vector3int16& extentSize,
|
||||
bool cellChanged);
|
||||
bool checkMegaClusterBigTerrainContact(Primitive* p);
|
||||
void checkMegaClusterContact(Primitive* p, bool checkTerrain, bool checkWater, bool cellChanged);
|
||||
|
||||
void applyDeferredMegaClusterChanges();
|
||||
|
||||
bool checkSmoothClusterSolidContact(Primitive* p);
|
||||
bool checkSmoothClusterWaterContact(Primitive* p);
|
||||
void checkSmoothClusterContact(Primitive* p, bool cellChanged);
|
||||
|
||||
void applyDeferredSmoothClusterChanges();
|
||||
|
||||
bool setUpbulletCollisionShapes(Primitive* p0, Primitive* p1);
|
||||
|
||||
Voxel::Grid* getVoxelGrid();
|
||||
Voxel2::Grid* getSmoothGrid();
|
||||
|
||||
public:
|
||||
|
||||
ContactManager(World* world);
|
||||
~ContactManager();
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// General Inquiry
|
||||
//
|
||||
ContactManagerSpatialHash* getSpatialHash() {return spatialHash;}
|
||||
|
||||
// Returns NULL on no hit
|
||||
Primitive* getHit( const RbxRay& worldRay,
|
||||
const std::vector<const Primitive*>* ignorePrim, // set to NULL to not use
|
||||
const HitTestFilter* filter, // set to NULL to not use
|
||||
Vector3& hitPointWorld,
|
||||
bool terrainCellsAreCubes = false,
|
||||
bool ignoreWater = false,
|
||||
Vector3& surfaceNormal = dummySurfaceNormal,
|
||||
PartMaterial& surfaceMaterial = dummySurfaceMaterial) const;
|
||||
|
||||
void getPrimitivesTouchingExtents(
|
||||
const Extents& extents,
|
||||
const Primitive* ignore,
|
||||
int maxCount,
|
||||
G3D::Array<Primitive*>& found);
|
||||
|
||||
void getPrimitivesTouchingExtents(
|
||||
const Extents& extents,
|
||||
const boost::unordered_set<const Primitive*>& ignorePrimitives,
|
||||
int maxCount,
|
||||
G3D::Array<Primitive*>& found);
|
||||
|
||||
void getPrimitivesOverlapping(const Extents& extents, DenseHashSet<Primitive*>& result);
|
||||
|
||||
bool intersectingGroundPlane(const G3D::Array<Primitive*>& check, float yHeight);
|
||||
bool intersectingOthers(Primitive* check, float overlapIgnored);
|
||||
bool intersectingOthers(const G3D::Array<Primitive*>& check, float overlapIgnored);
|
||||
bool intersectingOthers(Primitive* check, const std::set<Primitive*>& checkSet, float overlapIgnored);
|
||||
bool intersectingMySimulation(Primitive* check, RBX::SystemAddress myLocalAddress, float overlapIgnored);
|
||||
|
||||
shared_ptr<const Instances> getPartCollisions(Primitive* check);
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// From the collision engine
|
||||
//
|
||||
void onNewPair(Primitive* p0, Primitive* p1);
|
||||
void onNewPair(RBX::Graphics::CullableSceneNode* p0, RBX::Graphics::CullableSceneNode* p1) { RBXASSERT(0); }
|
||||
|
||||
void checkTerrainContact(Primitive* p);
|
||||
void checkTerrainContact(RBX::Graphics::CullableSceneNode* p0) {}
|
||||
|
||||
bool primitiveIsExcludedFromSpatialHash(Primitive* p);
|
||||
bool primitiveIsExcludedFromSpatialHash(RBX::Graphics::CullableSceneNode* p0) {return false;}
|
||||
|
||||
void releasePair(Primitive* p0, Primitive* p1);
|
||||
void releasePair(RBX::Graphics::CullableSceneNode* p0, RBX::Graphics::CullableSceneNode* p1) { RBXASSERT(0); }
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// From the world
|
||||
//
|
||||
void onPrimitiveAdded(Primitive* p);
|
||||
void onPrimitiveRemoved(Primitive* p);
|
||||
void onPrimitiveExtentsChanged(Primitive* p);
|
||||
void onPrimitiveGeometryChanged(Primitive* p);
|
||||
void onPrimitiveAssembled(Primitive* p);
|
||||
|
||||
void onAssemblyMovedFromStep(Assembly& a);
|
||||
|
||||
void applyDeferredTerrainChanges();
|
||||
|
||||
void fastClear();
|
||||
void doStats(); // spit out hash stats
|
||||
|
||||
///////////////////////////////////////////
|
||||
// Profiler
|
||||
boost::scoped_ptr<Profiling::CodeProfiler> profilingBroadphase;
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// LEGACY
|
||||
Primitive* getHitLegacy( const RbxRay& originDirection,
|
||||
const Primitive* ignorePrim, // set to NULL to not use
|
||||
const HitTestFilter* filter, // set to NULL to not use
|
||||
Vector3& hitPointWorld,
|
||||
float& distanceToHit,
|
||||
const float& maxSearchDepth,
|
||||
bool ignoreWater) const;
|
||||
|
||||
Primitive* getMegaClusterPrimitive( void ) const { return myMegaClusterPrim; }
|
||||
|
||||
bool terrainCellsInRegion3(Region3 region) const;
|
||||
Vector3 findUpNearestLocationWithSpaceNeeded(const float maxSearchDepth, const Vector3 &startCenter, const Vector3 &spaceNeededToCorner);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,24 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/SpatialHashMultiRes.h"
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
class Primitive;
|
||||
class Contact;
|
||||
class ContactManager;
|
||||
class World;
|
||||
class Assembly;
|
||||
|
||||
#define CONTACTMANAGER_MAXLEVELS 4
|
||||
class ContactManagerSpatialHash : public SpatialHash<Primitive, Contact, ContactManager, CONTACTMANAGER_MAXLEVELS>
|
||||
{
|
||||
public:
|
||||
ContactManagerSpatialHash(World* world, ContactManager* contactManager);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/IWorldStage.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Primitive;
|
||||
|
||||
class ContactStage : public IWorldStage {
|
||||
private:
|
||||
class TreeStage* getTreeStage();
|
||||
|
||||
public:
|
||||
///////////////////////////////////////////
|
||||
// IStage
|
||||
ContactStage(IStage* upstream, World* world);
|
||||
|
||||
~ContactStage() {}
|
||||
|
||||
/*override*/ IStage::StageType getStageType() const {return IStage::CONTACT_STAGE;}
|
||||
|
||||
/*override*/ void onEdgeAdded(Edge* e);
|
||||
/*override*/ void onEdgeRemoving(Edge* e);
|
||||
|
||||
void onPrimitiveAdded(Primitive* p);
|
||||
void onPrimitiveRemoving(Primitive* p);
|
||||
};
|
||||
} // namespace
|
||||
@@ -0,0 +1,29 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class LegacyController
|
||||
{
|
||||
public:
|
||||
typedef enum InputType {NO_INPUT = 0,
|
||||
LEFT_TRACK_INPUT,
|
||||
RIGHT_TRACK_INPUT,
|
||||
RIGHT_LEFT_INPUT, // -1.0 == right, 1.0 == left
|
||||
BACK_FORWARD_INPUT, // -1.0 == back, 1.0 == forward
|
||||
STRAFE_INPUT,
|
||||
UP_DOWN_INPUT,
|
||||
BUTTON_1_INPUT,
|
||||
BUTTON_2_INPUT,
|
||||
BUTTON_3_INPUT,
|
||||
BUTTON_4_INPUT,
|
||||
BUTTON_3_4_INPUT,
|
||||
CONSTANT_INPUT,
|
||||
SIN_INPUT,
|
||||
NUM_INPUT_TYPES} InputType;
|
||||
// If you add more items here,
|
||||
// please update the associated string matrix in ControllerTypes.cpp
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
Utility class - holds CornerWedge Meshes of same size for use by Geometry Pool.
|
||||
*/
|
||||
|
||||
#include "Util/Memory.h"
|
||||
#include "V8World/Mesh.h"
|
||||
|
||||
|
||||
namespace RBX {
|
||||
|
||||
namespace POLY {
|
||||
|
||||
class CornerWedgeMesh : public Allocator<CornerWedgeMesh>
|
||||
{
|
||||
private:
|
||||
Mesh mesh;
|
||||
Vector3 LocalCofM;
|
||||
|
||||
public:
|
||||
CornerWedgeMesh(const Vector3& size)
|
||||
{
|
||||
mesh.makeCornerWedge(size, LocalCofM);
|
||||
}
|
||||
const Mesh* getMesh() const {return &mesh;}
|
||||
const Vector3& GetLocalCofMFromMesh() const { return LocalCofM; }
|
||||
};
|
||||
|
||||
} // namespace POLY
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include "V8World/Poly.h"
|
||||
#include "V8World/GeometryPool.h"
|
||||
#include "V8World/CornerWedgeMesh.h"
|
||||
#include "V8World/BlockMesh.h"
|
||||
#include "V8World/BulletGeometryPoolObjects.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class CornerWedgePoly : public Poly {
|
||||
public:
|
||||
typedef GeometryPool<Vector3, POLY::CornerWedgeMesh, Vector3Comparer> CornerWedgeMeshPool;
|
||||
typedef GeometryPool<Vector3, BulletCornerWedgeShapeWrapper, Vector3Comparer> BulletCornerWedgeShapePool;
|
||||
|
||||
/*override*/ Matrix3 getMoment(float mass) const;
|
||||
/*override*/ Vector3 getCofmOffset() const;
|
||||
/*override*/ CoordinateFrame getSurfaceCoordInBody( const size_t surfaceId ) const;
|
||||
/*override*/ bool isGeometryOrthogonal( void ) const { return false; }
|
||||
/*override*/ bool setUpBulletCollisionData(void);
|
||||
/*override*/ void setSize(const G3D::Vector3& _size);
|
||||
|
||||
private:
|
||||
typedef Poly Super;
|
||||
|
||||
CornerWedgeMeshPool::Token aCornerWedgeMesh;
|
||||
BulletCornerWedgeShapePool::Token bulletCornerWedgeShape;
|
||||
|
||||
/*override*/ virtual Vector3 getCenterToCorner(const Matrix3& rotation) const;
|
||||
|
||||
void updateBulletCollisionData();
|
||||
|
||||
protected:
|
||||
// Geometry Overrides
|
||||
/*override*/ virtual GeometryType getGeometryType() const {return GEOMETRY_CORNERWEDGE;}
|
||||
|
||||
// Poly Overrides
|
||||
/*override*/ void buildMesh();
|
||||
/*override*/ size_t getFaceFromLegacyNormalId( const NormalId nId ) const;
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
#include "V8World/Geometry.h"
|
||||
#include "V8World/GeometryPool.h"
|
||||
#include "V8World/BulletGeometryPoolObjects.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Cylinder: public Geometry
|
||||
{
|
||||
public:
|
||||
typedef GeometryPool<Vector3, BulletCylinderShapeWrapper, Vector3Comparer> BulletCylinderShapePool;
|
||||
|
||||
private:
|
||||
typedef Geometry Super;
|
||||
|
||||
float realLength, realWidth;
|
||||
|
||||
BulletCylinderShapePool::Token bulletCylinderShape;
|
||||
|
||||
void updateBulletCollisionData();
|
||||
|
||||
public:
|
||||
Cylinder();
|
||||
~Cylinder();
|
||||
|
||||
GeometryType getGeometryType() const override {return GEOMETRY_CYLINDER;}
|
||||
CollideType getCollideType() const override {return COLLIDE_BULLET;}
|
||||
|
||||
bool setUpBulletCollisionData() override;
|
||||
|
||||
bool hitTest(const RbxRay& rayInMe, Vector3& localHitPoint, Vector3& surfaceNormal) override;
|
||||
void setSize(const Vector3& _size) override;
|
||||
|
||||
Matrix3 getMoment(float mass) const override;
|
||||
float getVolume() const override;
|
||||
|
||||
float getRadius() const override;
|
||||
|
||||
Vector3 getCenterToCorner(const Matrix3& rotation) const override;
|
||||
|
||||
size_t closestSurfaceToPoint(const Vector3& pointInBody) const override;
|
||||
Plane getPlaneFromSurface(const size_t surfaceId) const override;
|
||||
CoordinateFrame getSurfaceCoordInBody(const size_t surfaceId) const override;
|
||||
Vector3 getSurfaceNormalInBody(const size_t surfaceId) const override;
|
||||
size_t getMostAlignedSurface(const Vector3& vecInWorld, const G3D::Matrix3& objectR) const override;
|
||||
int getNumSurfaces() const override;
|
||||
Vector3 getSurfaceVertInBody(const size_t surfaceId, const int vertId) const override;
|
||||
int getNumVertsInSurface(const size_t surfaceId) const override;
|
||||
bool vertOverlapsFace(const Vector3& pointInBody, const size_t surfaceId) const override;
|
||||
|
||||
bool findTouchingSurfacesConvex(const CoordinateFrame& myCf, size_t& myFaceId, const Geometry& otherGeom, const CoordinateFrame& otherCf, size_t& otherFaceId) const override;
|
||||
bool FacesOverlapped(const CoordinateFrame& myCf, size_t& myFaceId, const Geometry& otherGeom, const CoordinateFrame& otherCf, size_t& otherFaceId, float tol) const override;
|
||||
bool FaceVerticesOverlapped(const CoordinateFrame& myCf, size_t& myFaceId, const Geometry& otherGeom, const CoordinateFrame& otherCf, size_t& otherFaceId, float tol) const override;
|
||||
bool FaceEdgesOverlapped(const CoordinateFrame& myCf, size_t& myFaceId, const Geometry& otherGeom, const CoordinateFrame& otherCf, size_t& otherFaceId, float tol) const override;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,17 @@
|
||||
/* Copyright 2003-2006 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace RBX {
|
||||
namespace Network {
|
||||
class DistributedPhysics
|
||||
{
|
||||
public:
|
||||
static const float MIN_CLIENT_SIMULATION_DISTANCE() {return 10.0f;}
|
||||
static const float MAX_CLIENT_SIMULATION_DISTANCE() {return 1000.0f;}
|
||||
|
||||
static const float CLIENT_SLOP() {return 1.05f;} // 105% how far out of the region before client stops simulating
|
||||
static const float SERVER_SLOP() {return 1.00f;} // server switches simulation to someone else as soon as the object leaves the region
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/IPipelined.h"
|
||||
#include "V8World/Enum.h"
|
||||
#include <list>
|
||||
|
||||
namespace RBX {
|
||||
namespace Graphics {
|
||||
class CullableSceneNode;
|
||||
} }
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class RBXBaseClass Edge : public IPipelined
|
||||
{
|
||||
private:
|
||||
Sim::EdgeState edgeState;
|
||||
Sim::ThrottleType throttleType;
|
||||
|
||||
Primitive* prim0;
|
||||
Primitive* prim1;
|
||||
|
||||
int index0; // linked lists for primitive 0 and 1
|
||||
int index1;
|
||||
|
||||
protected:
|
||||
// protected - no one should set it here
|
||||
virtual void setPrimitive(int i, Primitive* p);
|
||||
|
||||
public:
|
||||
typedef enum {JOINT, CONTACT} EdgeType; // purely to eliminate dynamic casts
|
||||
|
||||
Edge(Primitive* prim0, Primitive* prim1);
|
||||
|
||||
virtual ~Edge() {
|
||||
RBXASSERT(index0 == -1);
|
||||
RBXASSERT(index1 == -1);
|
||||
RBXASSERT(prim0 == NULL);
|
||||
RBXASSERT(prim1 == NULL);
|
||||
index0 = -1;
|
||||
index1 = -1;
|
||||
prim0 = static_cast<Primitive*>(Debugable::badMemory());
|
||||
prim1 = static_cast<Primitive*>(Debugable::badMemory());
|
||||
}
|
||||
|
||||
// poor man's way of no dynamic casts
|
||||
virtual EdgeType getEdgeType() const = 0;
|
||||
|
||||
virtual void generateDataForMovingAssemblyStage(void) {}
|
||||
|
||||
Sim::EdgeState getEdgeState() const {return edgeState;}
|
||||
void setEdgeState(Sim::EdgeState value) {edgeState = value;}
|
||||
|
||||
Sim::ThrottleType getThrottleType() const {return throttleType;}
|
||||
void setThrottleType(Sim::ThrottleType value) {throttleType = value;}
|
||||
|
||||
template<class Type>
|
||||
Type* fastCast(EdgeType edgeType) {
|
||||
bool match = (this->getEdgeType() == edgeType);
|
||||
RBXASSERT_VERY_FAST(match == (dynamic_cast<Type*>(this) != NULL));
|
||||
return match ? static_cast<Type*>(this) : NULL;
|
||||
}
|
||||
|
||||
Primitive* getPrimitive(int i) {
|
||||
RBXASSERT_VERY_FAST((i == 0) || (i == 1));
|
||||
return (&prim0)[i];
|
||||
}
|
||||
|
||||
const Primitive* getConstPrimitive(int i) const {
|
||||
RBXASSERT_VERY_FAST((i == 0) || (i == 1));
|
||||
return (&prim0)[i];
|
||||
}
|
||||
|
||||
Primitive* otherPrimitive(const Primitive* p) {return (p == prim0) ? prim1 : prim0;}
|
||||
RBX::Graphics::CullableSceneNode* otherPrimitive(const RBX::Graphics::CullableSceneNode* p) { RBXASSERT(NULL); return NULL;}
|
||||
|
||||
const Primitive* otherConstPrimitive(const Primitive* p) const {return (p == prim0) ? prim1 : prim0;}
|
||||
|
||||
Primitive* otherPrimitive(int i) {
|
||||
RBXASSERT_VERY_FAST((i == 0) || (i == 1));
|
||||
return (&prim0)[(i + 1) % 2];
|
||||
}
|
||||
|
||||
const Primitive* otherConstPrimitive(int i) const {
|
||||
RBXASSERT_VERY_FAST((i == 0) || (i == 1));
|
||||
return (&prim0)[(i + 1) % 2];
|
||||
}
|
||||
|
||||
int getPrimitiveId(const Primitive* p) const {
|
||||
RBXASSERT_VERY_FAST(links(p));
|
||||
return (p == prim0) ? 0 : 1;
|
||||
}
|
||||
|
||||
int getIndex(const Primitive* p) const {
|
||||
RBXASSERT_VERY_FAST(this->links(p));
|
||||
return (p == prim0) ? index0 : index1;
|
||||
}
|
||||
|
||||
void setIndex(Primitive* p, int index) {
|
||||
RBXASSERT_VERY_FAST(this->links(p));
|
||||
if (p == prim0) {
|
||||
index0 = index;
|
||||
}
|
||||
else {
|
||||
index1 = index;
|
||||
}
|
||||
}
|
||||
|
||||
bool links(const Primitive* p) const {
|
||||
return ((p == prim0) || (p == prim1));
|
||||
}
|
||||
|
||||
bool links(Primitive* p0, Primitive* p1) const {
|
||||
return ( ((p0 == prim0) && (p1 == prim1))
|
||||
|| ((p0 == prim1) && (p1 == prim0))
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,46 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/IWorldStage.h"
|
||||
#include "V8World/Assembly.h"
|
||||
#include "Util/BiMultiMap.h"
|
||||
|
||||
namespace RBX {
|
||||
class Assembly;
|
||||
|
||||
class EdgeBuffer : public IWorldStage {
|
||||
private:
|
||||
// DEBUG ONLY
|
||||
typedef RBX::BiMultiMap<Assembly*, Edge*> AssemblyEdgeMap; // find incomplete Joints by primitive
|
||||
AssemblyEdgeMap assemblyEdges;
|
||||
|
||||
bool debugPushEdgeToDownstream(Edge* e);
|
||||
bool debugRemoveEdgeFromDownstream(Edge* e);
|
||||
bool debugAddAssembly(Assembly* a);
|
||||
bool debugRemoveAssembly(Assembly* a);
|
||||
|
||||
bool assemblyIsHere(Assembly* a);
|
||||
|
||||
void assemblyPrimitiveAdded(Primitive* p);
|
||||
void assemblyPrimitiveRemoved(Primitive* p);
|
||||
|
||||
void pushEdgeIfOk(Edge* e);
|
||||
bool pushSpringOk(Edge* e);
|
||||
bool pushKinematicOk(Edge* e);
|
||||
void removeEdgeIfDownstream(Edge* e);
|
||||
|
||||
protected:
|
||||
void afterAssemblyAdded(Assembly* a);
|
||||
void beforeAssemblyRemoving(Assembly* a);
|
||||
|
||||
EdgeBuffer(IStage* upstream, IStage* downstream, World* world)
|
||||
: IWorldStage(upstream, downstream, world)
|
||||
{}
|
||||
|
||||
virtual ~EdgeBuffer();
|
||||
|
||||
/*override*/ void onEdgeAdded(Edge* e);
|
||||
/*override*/ void onEdgeRemoving(Edge* e);
|
||||
};
|
||||
} // namespace
|
||||
@@ -0,0 +1,32 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/IWorldStage.h"
|
||||
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Primitive;
|
||||
|
||||
class EdgeStage : public IWorldStage {
|
||||
private:
|
||||
typedef IWorldStage Super;
|
||||
class ContactStage* getContactStage();
|
||||
|
||||
public:
|
||||
///////////////////////////////////////////
|
||||
// IStage
|
||||
EdgeStage(IStage* upstream, World* world);
|
||||
|
||||
~EdgeStage() {}
|
||||
|
||||
/*override*/ IStage::StageType getStageType() const {return IStage::EDGE_STAGE;}
|
||||
|
||||
/*override*/ void onEdgeAdded(Edge* e);
|
||||
/*override*/ void onEdgeRemoving(Edge* e);
|
||||
|
||||
void onPrimitiveAdded(Primitive* p);
|
||||
void onPrimitiveRemoving(Primitive* p);
|
||||
};
|
||||
} // namespace
|
||||
@@ -0,0 +1,54 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace RBX {
|
||||
|
||||
namespace Sim {
|
||||
|
||||
typedef enum { ANCHORED,
|
||||
RECURSIVE_WAKE_PENDING,
|
||||
WAKE_PENDING,
|
||||
AWAKE,
|
||||
SLEEPING_CHECKING,
|
||||
SLEEPING_DEEPLY,
|
||||
REMOVING } AssemblyState;
|
||||
|
||||
inline bool isMovingAssemblyState(AssemblyState state) {
|
||||
return ((state == AWAKE) || (state == RECURSIVE_WAKE_PENDING) || (state == WAKE_PENDING));
|
||||
}
|
||||
|
||||
inline bool isSleepingAssemblyState(AssemblyState state) {
|
||||
return ((state == SLEEPING_CHECKING) || (state == SLEEPING_DEEPLY));
|
||||
}
|
||||
|
||||
inline bool outOfKernelAssemblyState(AssemblyState state) {
|
||||
return (isSleepingAssemblyState(state) || (state == REMOVING));
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef enum : unsigned char { CAN_NOT_THROTTLE = 0,
|
||||
CAN_THROTTLE,
|
||||
NUM_THROTTLE_TYPE,
|
||||
UNDEFINED_THROTTLE } ThrottleType;
|
||||
|
||||
typedef enum : unsigned char { UNDEFINED,
|
||||
STEPPING,
|
||||
SLEEPING,
|
||||
CONTACTING,
|
||||
CONTACTING_SLEEPING} EdgeState;
|
||||
#else
|
||||
typedef enum { CAN_NOT_THROTTLE = 0,
|
||||
CAN_THROTTLE,
|
||||
NUM_THROTTLE_TYPE,
|
||||
UNDEFINED_THROTTLE } ThrottleType;
|
||||
|
||||
typedef enum { UNDEFINED,
|
||||
STEPPING,
|
||||
SLEEPING,
|
||||
CONTACTING,
|
||||
CONTACTING_SLEEPING} EdgeState;
|
||||
#endif
|
||||
|
||||
} // namespace WORLD
|
||||
}// namespace
|
||||
@@ -0,0 +1,58 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Util/G3DCore.h"
|
||||
#include "rbx/Debug.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Primitive;
|
||||
|
||||
namespace GEO {
|
||||
|
||||
class RBXBaseClass Feature
|
||||
{
|
||||
private:
|
||||
Primitive* primitive;
|
||||
int index;
|
||||
|
||||
public:
|
||||
typedef enum {VERTEX, EDGE, FACE} FeatureType;
|
||||
|
||||
Feature(Primitive* primitive, int index) : primitive(primitive), index(index)
|
||||
{}
|
||||
|
||||
virtual FeatureType getFeatureType() const = 0;
|
||||
};
|
||||
|
||||
class Vertex : public Feature
|
||||
{
|
||||
public:
|
||||
Vertex(Primitive* primitive, int index) : Feature(primitive, index)
|
||||
{}
|
||||
|
||||
/*override*/ FeatureType getFeatureType() const {return VERTEX;}
|
||||
};
|
||||
|
||||
class Edge : public Feature
|
||||
{
|
||||
public:
|
||||
Edge(Primitive* primitive, int index) : Feature(primitive, index)
|
||||
{}
|
||||
|
||||
/*override*/ FeatureType getFeatureType() const {return EDGE;}
|
||||
};
|
||||
|
||||
class Face : public Feature
|
||||
{
|
||||
public:
|
||||
Face(Primitive* primitive, int index) : Feature(primitive, index)
|
||||
{}
|
||||
|
||||
/*override*/ FeatureType getFeatureType() const {return FACE;}
|
||||
};
|
||||
|
||||
} // namespace Feature
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,129 @@
|
||||
#pragma once
|
||||
|
||||
#include "Util/G3DCore.h"
|
||||
#include "Util/Units.h"
|
||||
#include "Util/Face.h"
|
||||
|
||||
#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
|
||||
#include "BulletCollision/CollisionShapes/btCollisionShape.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Geometry
|
||||
{
|
||||
private:
|
||||
Vector3 size;
|
||||
|
||||
protected:
|
||||
boost::scoped_ptr<btCollisionObject> bulletCollisionObject;
|
||||
|
||||
public:
|
||||
btCollisionObject* getBulletCollisionObject(void) { return bulletCollisionObject.get(); }
|
||||
virtual bool setUpBulletCollisionData(void) = 0;
|
||||
typedef enum { GEOMETRY_UNDEFINED=0,
|
||||
GEOMETRY_BALL,
|
||||
GEOMETRY_BLOCK,
|
||||
GEOMETRY_CYLINDER,
|
||||
GEOMETRY_WEDGE,
|
||||
GEOMETRY_PRISM,
|
||||
GEOMETRY_PYRAMID,
|
||||
GEOMETRY_PARALLELRAMP,
|
||||
GEOMETRY_RIGHTANGLERAMP,
|
||||
GEOMETRY_CORNERWEDGE,
|
||||
GEOMETRY_MEGACLUSTER,
|
||||
GEOMETRY_SMOOTHCLUSTER,
|
||||
GEOMETRY_TRI_MESH } GeometryType;
|
||||
|
||||
typedef enum { COLLIDE_BALL=1,
|
||||
COLLIDE_BLOCK,
|
||||
COLLIDE_POLY,
|
||||
COLLIDE_BULLET } CollideType;
|
||||
|
||||
Geometry() : bulletCollisionObject(NULL)
|
||||
{}
|
||||
|
||||
virtual ~Geometry()
|
||||
{}
|
||||
|
||||
virtual GeometryType getGeometryType() const = 0;
|
||||
|
||||
virtual CollideType getCollideType() const = 0;
|
||||
|
||||
///////////////////////////////////////////
|
||||
// Size and Extents
|
||||
//
|
||||
|
||||
// Grid Size
|
||||
virtual void setSize(const G3D::Vector3& _size) {
|
||||
size = _size;
|
||||
}
|
||||
const G3D::Vector3& getSize() const {return size;}
|
||||
|
||||
// Parameters
|
||||
virtual void setGeometryParameter(const std::string& parameter, int value) {
|
||||
RBXASSERT(0); // stock geometry does not handle parameters.
|
||||
}
|
||||
virtual int getGeometryParameter(const std::string& parameter) const {
|
||||
RBXASSERT(0); // stock geometry does not handle parameters.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Radius
|
||||
virtual float getRadius() const = 0;
|
||||
|
||||
// Dragger support
|
||||
virtual size_t closestSurfaceToPoint( const Vector3& pointInBody ) const = 0;
|
||||
virtual Plane getPlaneFromSurface( const size_t surfaceId ) const = 0;
|
||||
virtual CoordinateFrame getSurfaceCoordInBody( const size_t surfaceId ) const = 0;
|
||||
virtual Vector3 getSurfaceNormalInBody( const size_t surfaceId ) const = 0;
|
||||
virtual size_t getMostAlignedSurface( const Vector3& vecInWorld, const G3D::Matrix3& objectR ) const = 0;
|
||||
virtual int getNumSurfaces( void ) const = 0;
|
||||
virtual Vector3 getSurfaceVertInBody( const size_t surfaceId, const int vertId ) const = 0;
|
||||
virtual int getNumVertsInSurface( const size_t surfaceId ) const = 0;
|
||||
virtual bool vertOverlapsFace( const Vector3& pointInBody, const size_t surfaceId ) const = 0;
|
||||
virtual size_t getFaceFromLegacyNormalId( const NormalId nId ) const { return nId; }
|
||||
virtual bool isGeometryOrthogonal( void ) const { return true; }
|
||||
|
||||
// Relative proximity
|
||||
/*override*/virtual bool findTouchingSurfacesConvex( const CoordinateFrame& myCf, size_t& myFaceId, const Geometry& otherGeom, const CoordinateFrame& otherCf, size_t& otherFaceId ) const = 0;
|
||||
/*override*/virtual bool FacesOverlapped( const CoordinateFrame& myCf, size_t& myFaceId, const Geometry& otherGeom, const CoordinateFrame& otherCf, size_t& otherFaceId, float tol ) const = 0;
|
||||
/*override*/virtual bool FaceVerticesOverlapped( const CoordinateFrame& myCf, size_t& myFaceId, const Geometry& otherGeom, const CoordinateFrame& otherCf, size_t& otherFaceId, float tol ) const = 0;
|
||||
/*override*/virtual bool FaceEdgesOverlapped( const CoordinateFrame& myCf, size_t& myFaceId, const Geometry& otherGeom, const CoordinateFrame& otherCf, size_t& otherFaceId, float tol ) const = 0;
|
||||
|
||||
// Corner (better than radius for big blocks)
|
||||
virtual Vector3 getCenterToCorner(const Matrix3& rotation) const {return Vector3::zero();}
|
||||
|
||||
// CofmOffset
|
||||
virtual Vector3 getCofmOffset() const {return Vector3::zero();}
|
||||
|
||||
// Moment
|
||||
virtual Matrix3 getMoment(float mass) const {return Matrix3::zero();}
|
||||
|
||||
// Volume
|
||||
virtual float getVolume() const {return size.x * size.y * size.z;}
|
||||
|
||||
// Hit Test
|
||||
virtual bool hitTest(const RbxRay& rayInMe, Vector3& localHitPoint, Vector3& surfaceNormal) {return false;}
|
||||
|
||||
virtual bool collidesWithGroundPlane(const CoordinateFrame& c, float yHeight) const {
|
||||
return ((c.translation.y - getRadius()) < yHeight);
|
||||
}
|
||||
|
||||
virtual std::vector<Vector3> polygonIntersectionWithFace( const std::vector<Vector3>& polygonInBody, const size_t surfaceId ) const {
|
||||
std::vector<Vector3> empty;
|
||||
return empty;
|
||||
}
|
||||
|
||||
// Cluster RTTI helper
|
||||
bool isTerrain() const
|
||||
{
|
||||
GeometryType type = getGeometryType();
|
||||
|
||||
return type == GEOMETRY_MEGACLUSTER || type == GEOMETRY_SMOOTHCLUSTER;
|
||||
}
|
||||
|
||||
// Cluster dragger helper
|
||||
virtual bool hitTestTerrain(const RbxRay& rayInMe, Vector3& localHitPoint, int& surfId, CoordinateFrame& surfCf) { return false; }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,231 @@
|
||||
#pragma once
|
||||
#include "rbx/threadsafe.h"
|
||||
#include "rbx/debug.h"
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/weak_ptr.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
namespace RBX {
|
||||
|
||||
struct Vector3Comparer {
|
||||
bool operator()(const Vector3& a, const Vector3& b) const {
|
||||
if (a.x<b.x) return true;
|
||||
if (a.x>b.x) return false;
|
||||
if (a.y<b.y) return true;
|
||||
if (a.y>b.y) return false;
|
||||
if (a.z<b.z) return true;
|
||||
return false;
|
||||
}
|
||||
// boost::hash function
|
||||
std::size_t operator()(Vector3 const& v) const
|
||||
{
|
||||
size_t result = boost::hash<float>()(v.x);
|
||||
boost::hash_combine(result, v.y);
|
||||
boost::hash_combine(result, v.z);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
struct Vector3_2Ints
|
||||
{
|
||||
Vector3 vectPart;
|
||||
int int1;
|
||||
int int2;
|
||||
bool operator==(const Vector3_2Ints& b) const
|
||||
{
|
||||
return vectPart==b.vectPart && int1==b.int1 && int2==b.int2;
|
||||
}
|
||||
};
|
||||
|
||||
struct Vector3_2IntsComparer {
|
||||
bool operator()(const Vector3_2Ints& a, const Vector3_2Ints& b) const {
|
||||
if (a.vectPart.x<b.vectPart.x) return true;
|
||||
if (a.vectPart.x>b.vectPart.x) return false;
|
||||
if (a.vectPart.y<b.vectPart.y) return true;
|
||||
if (a.vectPart.y>b.vectPart.y) return false;
|
||||
if (a.vectPart.z<b.vectPart.z) return true;
|
||||
if (a.vectPart.z>b.vectPart.z) return false;
|
||||
if (a.int1<b.int1) return true;
|
||||
if (a.int1>b.int1) return false;
|
||||
if (a.int2<b.int2) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// boost::hash
|
||||
std::size_t operator()(Vector3_2Ints const& v) const
|
||||
{
|
||||
size_t result = Vector3Comparer()(v.vectPart);
|
||||
boost::hash_combine(result, v.int1);
|
||||
boost::hash_combine(result, v.int2);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
struct StringComparer {
|
||||
bool operator()(const std::string& a, const std::string& b) const
|
||||
{
|
||||
return (a < b);
|
||||
}
|
||||
};
|
||||
|
||||
struct IntComparer {
|
||||
bool operator()(const int& a, const int& b) const
|
||||
{
|
||||
return (a < b);
|
||||
}
|
||||
};
|
||||
|
||||
struct FloatComparer {
|
||||
bool operator()(const float& a, const float& b) const
|
||||
{
|
||||
return (a < b);
|
||||
}
|
||||
};
|
||||
|
||||
template<class Key, class Value, typename Comparer>
|
||||
class GeometryPool
|
||||
{
|
||||
private:
|
||||
struct Entry;
|
||||
typedef std::map<Key, Entry*, Comparer> Map;
|
||||
|
||||
struct Entry
|
||||
{
|
||||
Value value;
|
||||
size_t count;
|
||||
typename Map::iterator iterator;
|
||||
|
||||
Entry(const Key& key)
|
||||
: value(key)
|
||||
, count(0)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class StaticData
|
||||
{
|
||||
public:
|
||||
Map map;
|
||||
rbx::spin_mutex mutex;
|
||||
};
|
||||
|
||||
SAFE_STATIC(StaticData, staticData);
|
||||
|
||||
static StaticData& getStaticData()
|
||||
{
|
||||
return staticData();
|
||||
}
|
||||
|
||||
public:
|
||||
// This is modeled after unique_ptr with custom deleter GeometryPool::returnToken
|
||||
class Token
|
||||
{
|
||||
Token(const Token& token);
|
||||
Token& operator=(const Token& token);
|
||||
|
||||
public:
|
||||
Token(): entry(0)
|
||||
{
|
||||
}
|
||||
|
||||
explicit Token(Entry* entry)
|
||||
: entry(entry)
|
||||
{
|
||||
}
|
||||
|
||||
Token(Token&& other)
|
||||
: entry(other.entry)
|
||||
{
|
||||
other.entry = 0;
|
||||
}
|
||||
|
||||
~Token()
|
||||
{
|
||||
if (entry)
|
||||
GeometryPool::returnToken(entry);
|
||||
}
|
||||
|
||||
Token& operator=(Token&& other)
|
||||
{
|
||||
if (entry)
|
||||
GeometryPool::returnToken(entry);
|
||||
|
||||
entry = other.entry;
|
||||
other.entry = 0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Value& operator*() const
|
||||
{
|
||||
return entry->value;
|
||||
}
|
||||
|
||||
const Value* operator->() const
|
||||
{
|
||||
return &entry->value;
|
||||
}
|
||||
|
||||
// This is slightly horrible but we don't have C++11 explicit operator bool
|
||||
operator void*() const
|
||||
{
|
||||
return entry;
|
||||
}
|
||||
|
||||
private:
|
||||
Entry* entry;
|
||||
};
|
||||
|
||||
static void init() { staticData(); }
|
||||
|
||||
static Token getToken(const Key& key, const Key& data)
|
||||
{
|
||||
StaticData &d = getStaticData();
|
||||
rbx::spin_mutex::scoped_lock lock(d.mutex);
|
||||
|
||||
typename Map::iterator it = d.map.find(key);
|
||||
Entry* entry = (it != d.map.end()) ? it->second : 0;
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
entry = new Entry(data);
|
||||
entry->iterator = d.map.insert(typename Map::value_type(key, entry)).first;
|
||||
}
|
||||
|
||||
entry->count++;
|
||||
|
||||
return Token(entry);
|
||||
}
|
||||
|
||||
static Token getToken(const Key& key)
|
||||
{
|
||||
return getToken(key, key);
|
||||
}
|
||||
|
||||
static void returnToken(Entry* entry)
|
||||
{
|
||||
StaticData &d = getStaticData();
|
||||
rbx::spin_mutex::scoped_lock lock(d.mutex);
|
||||
|
||||
RBXASSERT(entry->count > 0);
|
||||
entry->count--;
|
||||
|
||||
if (entry->count == 0)
|
||||
{
|
||||
RBXASSERT(entry == entry->iterator->second);
|
||||
|
||||
d.map.erase(entry->iterator);
|
||||
delete entry;
|
||||
}
|
||||
}
|
||||
|
||||
static int getSize()
|
||||
{
|
||||
StaticData &d = getStaticData();
|
||||
rbx::spin_mutex::scoped_lock lock(d.mutex);
|
||||
|
||||
return d.map.size();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,89 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/MultiJoint.h"
|
||||
#include <vector>
|
||||
|
||||
namespace RBX {
|
||||
class Constraint;
|
||||
class GlueJoint : public MultiJoint
|
||||
{
|
||||
private:
|
||||
typedef MultiJoint Super;
|
||||
Face faceInJointSpace;
|
||||
|
||||
// Used when PGS is on
|
||||
std::vector< Constraint* > constraints;
|
||||
|
||||
float getMaxForce();
|
||||
|
||||
// Joint
|
||||
/*override*/ JointType getJointType() const {return Joint::GLUE_JOINT;}
|
||||
/*override*/ bool isBreakable() const {return true;}
|
||||
/*override*/ bool isBroken() const;
|
||||
|
||||
static bool compatibleSurfaces(
|
||||
Primitive* p0,
|
||||
Primitive* p1,
|
||||
NormalId nId0,
|
||||
NormalId nId1);
|
||||
protected:
|
||||
// Edge
|
||||
/*override*/ void putInKernel(Kernel* kernel);
|
||||
/*override*/ void removeFromKernel();
|
||||
public:
|
||||
GlueJoint();
|
||||
|
||||
GlueJoint(
|
||||
Primitive* p0,
|
||||
Primitive* p1,
|
||||
const CoordinateFrame& jointCoord0,
|
||||
const CoordinateFrame& jointCoord1,
|
||||
const Face& faceInJointSpace);
|
||||
|
||||
const Vector3& getFacePoint(int i) const { // in joint space (common to both P0 and P1)
|
||||
RBXASSERT(i >= 0 && i < 4);
|
||||
return faceInJointSpace[i];
|
||||
}
|
||||
|
||||
void setFacePoint(int i, const Vector3& value) { // in joint space
|
||||
RBXASSERT(i >= 0 && i < 4);
|
||||
faceInJointSpace[i] = value;
|
||||
}
|
||||
|
||||
static GlueJoint* canBuildJoint(
|
||||
Primitive* p0,
|
||||
Primitive* p1,
|
||||
NormalId nId0,
|
||||
NormalId nId1);
|
||||
|
||||
};
|
||||
|
||||
class ManualGlueJoint : public GlueJoint
|
||||
{
|
||||
private:
|
||||
typedef GlueJoint Super;
|
||||
size_t surface0; // surface from primitive 0
|
||||
size_t surface1; // surface from primitive 1
|
||||
|
||||
/*override*/ virtual JointType getJointType() const {return MANUAL_GLUE_JOINT;}
|
||||
/*override*/ void putInKernel(Kernel* kernel);
|
||||
/*override*/ void computeIntersectingSurfacePoints(void);
|
||||
|
||||
public:
|
||||
ManualGlueJoint() {surface0 = (size_t)-1; surface1 = (size_t)-1;}
|
||||
ManualGlueJoint(size_t s0, size_t s1, Primitive* prim0, Primitive* prim1, const CoordinateFrame& c0, const CoordinateFrame &c1, const Face& faceInJointSpace)
|
||||
: GlueJoint(prim0, prim1, c0, c1, faceInJointSpace)
|
||||
{surface0 = s0; surface1 = s1;}
|
||||
|
||||
~ManualGlueJoint() {}
|
||||
|
||||
size_t getSurface0(void) const {return surface0;}
|
||||
size_t getSurface1(void) const {return surface1;}
|
||||
void setSurface0(size_t surfId) {surface0 = surfId;}
|
||||
void setSurface1(size_t surfId) {surface1 = surfId;}
|
||||
};
|
||||
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,53 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/IWorldStage.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Primitive;
|
||||
class Joint;
|
||||
class KernelJoint;
|
||||
class RigidJoint;
|
||||
|
||||
class GroundStage : public IWorldStage {
|
||||
private:
|
||||
typedef IWorldStage Super;
|
||||
class EdgeStage* getEdgeStage();
|
||||
|
||||
bool kernelJointHere(Primitive* p);
|
||||
|
||||
void addGroundJoint(Primitive* p, bool grounded);
|
||||
void removeGroundJoint(Primitive* p, bool grounded);
|
||||
|
||||
void onKernelJointAdded(KernelJoint* k);
|
||||
void onKernelJointRemoving(KernelJoint* k);
|
||||
|
||||
void checkForFreeGroundJoint(RigidJoint* r);
|
||||
void rebuildFreeGround(Primitive* p);
|
||||
void rebuildOthers(Primitive* changedP);
|
||||
|
||||
RigidJoint* heaviestRigidToGround(Primitive* p);
|
||||
|
||||
public:
|
||||
///////////////////////////////////////////
|
||||
// IStage
|
||||
GroundStage(IStage* upstream, World* world);
|
||||
~GroundStage();
|
||||
|
||||
/*override*/ IStage::StageType getStageType() const {return IStage::GROUND_STAGE;}
|
||||
|
||||
void onPrimitiveAdded(Primitive* p);
|
||||
void onPrimitiveRemoving(Primitive* p);
|
||||
|
||||
void onPrimitiveFixedChanging(Primitive* p);
|
||||
void onPrimitiveFixedChanged(Primitive* p);
|
||||
|
||||
/*override*/ void onEdgeAdded(Edge* e);
|
||||
/*override*/ void onEdgeRemoving(Edge* e);
|
||||
};
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/IWorldStage.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Assembly;
|
||||
|
||||
class HumanoidStage : public IWorldStage
|
||||
{
|
||||
private:
|
||||
std::set<Assembly*> movingHumanoidAssemblies;
|
||||
void toDynamics(Assembly* a);
|
||||
void toHumanoid(Assembly* a);
|
||||
void fromDynamics(Assembly* a);
|
||||
void fromHumanoid(Assembly* a);
|
||||
|
||||
|
||||
public:
|
||||
HumanoidStage(IStage* upstream, World* world);
|
||||
|
||||
~HumanoidStage();
|
||||
|
||||
/*override*/ IStage::StageType getStageType() const {return IStage::HUMANOID_STAGE;}
|
||||
|
||||
void onAssemblyAdded(Assembly* assembly);
|
||||
void onAssemblyRemoving(Assembly* assembly);
|
||||
|
||||
const std::set<Assembly*>& getMovingHumanoidAssemblies() {
|
||||
return movingHumanoidAssemblies;
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
@@ -0,0 +1,97 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "rbx/Debug.h"
|
||||
#include <set>
|
||||
#include "rbx/Boost.hpp"
|
||||
#include "rbx/rbxTime.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class IMovingManager;
|
||||
class MovementHistory;
|
||||
class Velocity;
|
||||
class Primitive;
|
||||
|
||||
class RBXBaseClass IMoving
|
||||
{
|
||||
friend class IMovingManager;
|
||||
|
||||
private:
|
||||
IMovingManager* iMovingManager;
|
||||
|
||||
int stepsToSleep;
|
||||
|
||||
scoped_ptr<CoordinateFrame> lastCFrame;
|
||||
Time lastUpdateTime;
|
||||
scoped_ptr<MovementHistory> movementHistory;
|
||||
|
||||
void makeMoving();
|
||||
|
||||
protected:
|
||||
virtual void onSleepingChanged(bool sleeping) = 0;
|
||||
|
||||
void setMovingManager(IMovingManager* _iMovingManager);
|
||||
|
||||
bool checkSleep();
|
||||
|
||||
public:
|
||||
IMoving();
|
||||
|
||||
~IMoving();
|
||||
|
||||
void notifyMoved(); // done in PartInstance::setCoordinateFrame, InterpolatedCFrame, and by the World after every step
|
||||
|
||||
virtual bool reportTouches() const = 0;
|
||||
|
||||
virtual void onClumpChanged() = 0; // callback to PartInstance from Primitive
|
||||
|
||||
virtual void onNetworkIsSleepingChanged(Time now) = 0; // callback to PartInstance from Primitive
|
||||
|
||||
virtual void onBuoyancyChanged( bool value ) = 0; // callback to PartInstance from Primitive
|
||||
virtual bool isInContinousMotion() = 0;
|
||||
|
||||
virtual const Primitive* getConstPartPrimitiveVirtual() const {return NULL;}
|
||||
|
||||
bool getSleeping() const {
|
||||
return (stepsToSleep == 0);
|
||||
}
|
||||
|
||||
void forceSleep();
|
||||
|
||||
const MovementHistory& getMovementHistory() const;
|
||||
void clearMovementHistory();
|
||||
void addMovementNode(const CoordinateFrame& cFrame, const Velocity& velocity, const Time& timeStamp);
|
||||
void setLastCFrame(const CoordinateFrame& cFrame);
|
||||
const CoordinateFrame& getLastCFrame(const CoordinateFrame& defaultCFrame) const;
|
||||
bool hasLastCFrame() {return lastCFrame != NULL;}
|
||||
void setLastUpdateTime(const Time& time);
|
||||
const Time& getLastUpdateTime() const;
|
||||
};
|
||||
|
||||
class RBXBaseClass IMovingManager
|
||||
{
|
||||
friend class IMoving;
|
||||
private:
|
||||
typedef std::set<IMoving*> MovingSet;
|
||||
MovingSet moving;
|
||||
MovingSet::iterator current;
|
||||
|
||||
protected:
|
||||
void remove(IMoving* iMoving);
|
||||
void moved(IMoving* iMoving);
|
||||
|
||||
public:
|
||||
IMovingManager();
|
||||
|
||||
virtual ~IMovingManager();
|
||||
|
||||
void onMovingHeartbeat(); // put parts to sleep here if not moving for a long time, notify
|
||||
|
||||
int getNumberMoving() const {return static_cast<int>(moving.size());}
|
||||
|
||||
void updateHistory();
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,88 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/IWorldStage.h"
|
||||
#include "rbx/Debug.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Kernel;
|
||||
|
||||
class RBXBaseClass IPipelined
|
||||
{
|
||||
private:
|
||||
IStage* currentStage;
|
||||
|
||||
void removeFromStage(IStage::StageType stageType);
|
||||
|
||||
IStage* getStage(IStage::StageType stageType) const;
|
||||
public:
|
||||
IPipelined() : currentStage(NULL)
|
||||
{}
|
||||
|
||||
virtual ~IPipelined() {
|
||||
RBXASSERT(currentStage == NULL);
|
||||
currentStage = static_cast<IStage*>(Debugable::badMemory());
|
||||
}
|
||||
|
||||
void putInPipeline(IStage* stage);
|
||||
|
||||
void removeFromPipeline(IStage* stage);
|
||||
|
||||
void putInStage(IStage* stage);
|
||||
|
||||
void removeFromStage(IStage* stage);
|
||||
|
||||
bool inPipeline() const {
|
||||
return (currentStage != NULL);
|
||||
}
|
||||
|
||||
const IStage* getCurrentStage() const {return currentStage;}
|
||||
|
||||
bool inStage(IStage::StageType stageType) const {
|
||||
RBXASSERT(currentStage);
|
||||
return (currentStage && (currentStage->getStageType() == stageType));
|
||||
}
|
||||
|
||||
bool inStage(IStage* iStage) const {
|
||||
RBXASSERT(iStage);
|
||||
RBXASSERT(currentStage);
|
||||
return (currentStage == iStage);
|
||||
}
|
||||
|
||||
bool inOrDownstreamOfStage(IStage::StageType stageType) const {
|
||||
RBXASSERT(currentStage);
|
||||
return (currentStage && (currentStage->getStageType() >= stageType));
|
||||
}
|
||||
|
||||
bool inOrDownstreamOfStage(IStage* iStage) const {
|
||||
RBXASSERT(iStage);
|
||||
RBXASSERT(currentStage);
|
||||
return (currentStage && iStage && (currentStage->getStageType() >= iStage->getStageType()));
|
||||
}
|
||||
|
||||
bool downstreamOfStage(IStage* iStage) const {
|
||||
RBXASSERT(iStage);
|
||||
RBXASSERT(currentStage);
|
||||
return (currentStage && iStage && currentStage->getStageType() > iStage->getStageType());
|
||||
}
|
||||
|
||||
bool inKernel() const {return inStage(IStage::KERNEL_STAGE);}
|
||||
Kernel* getKernel() const; // should never fail
|
||||
|
||||
virtual void putInKernel(Kernel* kernel);
|
||||
virtual void removeFromKernel();
|
||||
|
||||
World* findWorld() {
|
||||
if (!currentStage) {
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
IStage* worldStage = (!inKernel()) ? currentStage : currentStage->getUpstream();
|
||||
return rbx_static_cast<IWorldStage*>(worldStage)->getWorld();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,48 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8Kernel/IStage.h"
|
||||
#include "rbx/Debug.h"
|
||||
#include "Util/G3DCore.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class World;
|
||||
class Edge;
|
||||
class Contact;
|
||||
class Primitive;
|
||||
|
||||
class RBXBaseClass IWorldStage : public IStage {
|
||||
private:
|
||||
World* world;
|
||||
|
||||
public:
|
||||
typedef enum { NUM_CONTACTSTAGE_CONTACTS,
|
||||
NUM_STEPPING_CONTACTS,
|
||||
NUM_TOUCHING_CONTACTS,
|
||||
MAX_TREE_DEPTH } MetricType;
|
||||
|
||||
IWorldStage(IStage* upstream, IStage* downstream, World* world)
|
||||
: IStage(upstream, downstream)
|
||||
, world(world)
|
||||
{}
|
||||
|
||||
IWorldStage* getUpstreamWS() {return rbx_static_cast<IWorldStage*>(getUpstream());}
|
||||
IWorldStage* getDownstreamWS() {return rbx_static_cast<IWorldStage*>(getDownstream());}
|
||||
const IWorldStage* getDownstreamWS() const {return rbx_static_cast<const IWorldStage*>(getDownstream());}
|
||||
|
||||
World* getWorld() {return world;}
|
||||
|
||||
////////////////////////////////////////////
|
||||
//
|
||||
// Calls to DOWNSTREAM stage
|
||||
virtual void onEdgeAdded(Edge* e);
|
||||
virtual void onEdgeRemoving(Edge* e);
|
||||
|
||||
virtual int getMetric(MetricType metricType) {
|
||||
RBXASSERT(getDownstreamWS());
|
||||
return getDownstreamWS()->getMetric(metricType);
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
@@ -0,0 +1,243 @@
|
||||
#pragma once
|
||||
|
||||
#include "V8World/Edge.h"
|
||||
#include "Util/SurfaceType.h"
|
||||
#include "Util/Face.h"
|
||||
#include "Util/Extents.h"
|
||||
#include "Util/SpanningEdge.h"
|
||||
#include "G3D/Array.h"
|
||||
#include "boost/intrusive/list.hpp"
|
||||
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Channel;
|
||||
class Link;
|
||||
class Joint;
|
||||
|
||||
class RBXInterface IJointOwner
|
||||
{
|
||||
public:
|
||||
virtual Joint* getJoint(void) { RBXASSERT(0); return NULL; }
|
||||
};
|
||||
|
||||
class StepJointsStage;
|
||||
typedef boost::intrusive::list_base_hook< boost::intrusive::tag<StepJointsStage> > StepJointsStageHook;
|
||||
class MovingAssemblyStage;
|
||||
typedef boost::intrusive::list_base_hook< boost::intrusive::tag<MovingAssemblyStage> > MovingAssemblyStageHook;
|
||||
|
||||
class Joint : public Edge
|
||||
, public SpanningEdge
|
||||
, public StepJointsStageHook
|
||||
, public MovingAssemblyStageHook // TODO: Can we share the same hooks?
|
||||
{
|
||||
private:
|
||||
typedef Edge Super;
|
||||
IJointOwner* jointOwner;
|
||||
|
||||
static bool canBuildJoint(
|
||||
Primitive* p0,
|
||||
Primitive* p1,
|
||||
NormalId nId0,
|
||||
NormalId nId1,
|
||||
float angleMax,
|
||||
float planarMax);
|
||||
|
||||
protected:
|
||||
CoordinateFrame jointCoord0; // in object space
|
||||
CoordinateFrame jointCoord1; // this coord is aligned with Coord0, so it points into the body
|
||||
public:
|
||||
static bool canBuildJointLoose(Primitive* p0, Primitive* p1, NormalId nId0, NormalId nId1);
|
||||
static bool canBuildJointTight(Primitive* p0, Primitive* p1, NormalId nId0, NormalId nId1);
|
||||
|
||||
protected:
|
||||
///////////////////////////////////////////////////
|
||||
// Edge
|
||||
//
|
||||
/*override*/ EdgeType getEdgeType() const {return Edge::JOINT;}
|
||||
|
||||
Joint();
|
||||
|
||||
Joint( Primitive* prim0,
|
||||
Primitive* prim1,
|
||||
const CoordinateFrame& _jointCoord0,
|
||||
const CoordinateFrame& _jointCoord1);
|
||||
|
||||
public:
|
||||
~Joint();
|
||||
|
||||
void setJointCoord(int i, const CoordinateFrame& c);
|
||||
|
||||
const CoordinateFrame& getJointCoord(int i) const {
|
||||
return (i == 0) ? jointCoord0 : jointCoord1;
|
||||
}
|
||||
|
||||
CoordinateFrame getJointWorldCoord(int i);
|
||||
|
||||
void notifyMoved();
|
||||
|
||||
// In precedence order - greatest to least
|
||||
// GROUND KINEMATIC SPRING KERNEL
|
||||
typedef enum { ANCHOR_JOINT, // X
|
||||
WELD_JOINT, // X
|
||||
MANUAL_WELD_JOINT, // X
|
||||
SNAP_JOINT, // X
|
||||
MOTOR_1D_JOINT, // X
|
||||
MOTOR_6D_JOINT, // X
|
||||
ROTATE_JOINT, // X
|
||||
ROTATE_P_JOINT, // X
|
||||
ROTATE_V_JOINT, // X
|
||||
GLUE_JOINT, // X
|
||||
MANUAL_GLUE_JOINT, // X
|
||||
FREE_JOINT, // X
|
||||
KERNEL_JOINT, // X
|
||||
NO_JOINT //
|
||||
} JointType;
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// IJointOwner
|
||||
//
|
||||
void setJointOwner(IJointOwner* value);
|
||||
IJointOwner* getJointOwner() const;
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// Edge Virtuals
|
||||
//
|
||||
/*override*/ void setPrimitive(int i, Primitive* p);
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// Joint Virtuals
|
||||
//
|
||||
virtual JointType getJointType() const {RBXASSERT(0); return Joint::NO_JOINT;}
|
||||
virtual bool isBreakable() const {return false;}
|
||||
virtual bool isBroken() const {return false;}
|
||||
virtual bool joinsFace(Primitive* g, NormalId faceId) const {return false;}
|
||||
virtual bool isAligned() {return true;}
|
||||
virtual CoordinateFrame align(Primitive* pMove, Primitive* pStay) {RBXASSERT(0); return CoordinateFrame();}
|
||||
|
||||
virtual void setPhysics() {} // occurs after networking read;
|
||||
|
||||
virtual bool canStepWorld() const {return false;}
|
||||
virtual bool canStepUi() const {return false;}
|
||||
|
||||
virtual void stepWorld() {}
|
||||
virtual bool stepUi(double distributedGameTime) {return false;}
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
//
|
||||
static bool isJoint(const Edge* e) {return (e->getEdgeType() == Edge::JOINT);}
|
||||
|
||||
static JointType getJointType(const Edge* e) {
|
||||
return isJoint(e) ? rbx_static_cast<const Joint*>(e)->getJointType() : Joint::NO_JOINT;
|
||||
}
|
||||
|
||||
static bool isGroundJoint(const Edge* e) { // alternately, created by AutoJoin
|
||||
Joint::JointType jt = getJointType(e);
|
||||
return ((jt == FREE_JOINT) || (jt == ANCHOR_JOINT));
|
||||
}
|
||||
|
||||
static bool isRigidJoint(const Edge* e) {
|
||||
Joint::JointType jt = getJointType(e);
|
||||
return ((jt == WELD_JOINT) || (jt == SNAP_JOINT) || (jt == MANUAL_WELD_JOINT));
|
||||
}
|
||||
|
||||
static bool isKinematicJoint(const Edge* e) {
|
||||
Joint::JointType jt = getJointType(e);
|
||||
return ((jt >= WELD_JOINT) && (jt <= MOTOR_6D_JOINT));
|
||||
}
|
||||
|
||||
static bool isSpringJoint(const Edge* e) {
|
||||
Joint::JointType jt = getJointType(e);
|
||||
return ((jt >= ROTATE_JOINT) && (jt <= GLUE_JOINT)) || (jt == MANUAL_GLUE_JOINT);
|
||||
}
|
||||
|
||||
static bool isMotorJoint(const Edge* e) {
|
||||
Joint::JointType jt = getJointType(e);
|
||||
return ((jt >= MOTOR_1D_JOINT) && (jt <= MOTOR_6D_JOINT));
|
||||
}
|
||||
|
||||
static bool isKernelJoint(const Edge* e) {
|
||||
Joint::JointType jt = getJointType(e);
|
||||
return (jt == Joint::KERNEL_JOINT);
|
||||
}
|
||||
|
||||
static bool isManualJoint(const Edge* e) {
|
||||
Joint::JointType jt = getJointType(e);
|
||||
return (jt == Joint::MANUAL_WELD_JOINT || jt == Joint::MANUAL_GLUE_JOINT);
|
||||
}
|
||||
|
||||
static bool isSpanningTreeJoint(const Edge* e) {
|
||||
return (isKinematicJoint(e) || isSpringJoint(e) || isGroundJoint(e));
|
||||
}
|
||||
|
||||
static bool isAutoJoint(const Joint* j) { // alternately, created by AutoJoin
|
||||
return (!isGroundJoint(j) && !isKernelJoint(j) && !isManualJoint(j));
|
||||
}
|
||||
|
||||
static Joint* getJoint(Primitive* p, Joint::JointType jointType);
|
||||
static const Joint* getConstJoint(const Primitive* p, Joint::JointType jointType);
|
||||
static const Joint* findConstJoint(const Primitive* p, Joint::JointType jointType);
|
||||
|
||||
NormalId getNormalId(int i) const {
|
||||
RBXASSERT((i==0)||(i==1));
|
||||
return (i == 0)
|
||||
? Matrix3ToNormalId(jointCoord0.rotation)
|
||||
: normalIdOpposite(Matrix3ToNormalId(jointCoord1.rotation));
|
||||
}
|
||||
|
||||
virtual Link* resetLink() { RBXASSERT(!"Not Implemented"); return 0; }
|
||||
|
||||
static bool FacesOverlapped( const Primitive* p0, size_t face0Id, const Primitive* p1, size_t face1Id, float adjustPartTolerance = 1.0 );
|
||||
static bool FaceVerticesOverlapped( const Primitive* p0, size_t face0Id, const Primitive* p1, size_t face1Id, float adjustPartTolerance );
|
||||
static bool FaceEdgesOverlapped( const Primitive* p0, size_t face0Id, const Primitive* p1, size_t face1Id, float adjustPartTolerance );
|
||||
static bool findTouchingSurfacesConvex( const Primitive& p0, size_t& face0Id, const Primitive& p1, size_t& face1Id );
|
||||
static bool compatibleForGlueAutoJoint( const Primitive& p0, size_t& face0Id, const Primitive& p1, size_t& face1Id );
|
||||
static bool compatibleForWeldAutoJoint( const Primitive& p0, size_t& face0Id, const Primitive& p1, size_t& face1Id );
|
||||
static bool compatibleForHingeAutoJoint( const Primitive& p0, size_t& face0Id, const Primitive& p1, size_t& face1Id );
|
||||
static bool compatibleForStudAutoJoint( const Primitive& p0, size_t& face0Id, const Primitive& p1, size_t& face1Id );
|
||||
static bool inCompatibleForAnyJoint( const Primitive& p0, size_t& face0Id, const Primitive& p1, size_t& face1Id );
|
||||
static bool positionedForStudAutoJoint( const Primitive& p0, size_t& face0Id, const Primitive& p1, size_t& face1Id );
|
||||
static SurfaceType getSurfaceTypeFromNormal( const Primitive& primitive, const NormalId& normalId ); // helper function for correct "isCompatible" function behavior
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// SpanningEdge
|
||||
private:
|
||||
/*override*/ bool isHeavierThan(const SpanningEdge* other) const;
|
||||
/*override*/ SpanningNode* otherNode(SpanningNode* n);
|
||||
/*override*/ const SpanningNode* otherConstNode(const SpanningNode* n) const;
|
||||
/*override*/ SpanningNode* getNode(int i);
|
||||
/*override*/ const SpanningNode* getConstNode(int i) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class AnchorJoint : public Joint
|
||||
{
|
||||
private:
|
||||
/*override*/ virtual JointType getJointType() const {return Joint::ANCHOR_JOINT;}
|
||||
|
||||
public:
|
||||
AnchorJoint(Primitive* prim) : Joint(prim, NULL, CoordinateFrame(), CoordinateFrame())
|
||||
{}
|
||||
|
||||
static bool isAnchorJoint(const Joint* j) {
|
||||
return (j->getJointType() == Joint::ANCHOR_JOINT);
|
||||
}
|
||||
};
|
||||
|
||||
class FreeJoint : public Joint
|
||||
{
|
||||
private:
|
||||
/*override*/ virtual JointType getJointType() const {return Joint::FREE_JOINT;}
|
||||
|
||||
public:
|
||||
FreeJoint(Primitive* prim) : Joint(prim, NULL, CoordinateFrame(), CoordinateFrame())
|
||||
{}
|
||||
|
||||
static bool isFreeJoint(const Joint* j) {
|
||||
return (j->getJointType() == Joint::FREE_JOINT);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
// #include "V8World/Joint.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Joint;
|
||||
class Primitive;
|
||||
|
||||
class JointBuilder
|
||||
{
|
||||
public:
|
||||
// static Joint* makeJoint(Primitive* p0, Primitive* p1, const CoordinateFrame& c0, const CoordinateFrame& c1, Joint::JointType jointType);
|
||||
|
||||
static Joint* canJoin(Primitive* p0, Primitive* p1);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/IWorldStage.h"
|
||||
#include "Util/ConcurrencyValidator.h"
|
||||
#include "Util/BiMultiMap.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Edge;
|
||||
class Joint;
|
||||
|
||||
class JointStage : public IWorldStage {
|
||||
private:
|
||||
ConcurrencyValidator concurrencyValidator;
|
||||
class GroundStage* getGroundStage();
|
||||
|
||||
typedef RBX::BiMultiMap<Primitive*, Joint*> JointMap; // find incomplete Joints by primitive
|
||||
JointMap jointMap; // is identical to the primitive fields stored in the fields
|
||||
std::set<Joint*> incompleteJoints;
|
||||
std::set<Primitive*> primitivesHere;
|
||||
// of all joints in the incompleteJoints list
|
||||
void moveEdgeToDownstream(Edge* e);
|
||||
void removeEdgeFromDownstream(Edge* e);
|
||||
|
||||
void moveJointToDownstream(Joint* j);
|
||||
void removeJointFromDownstream(Joint* j);
|
||||
|
||||
void putJointHere(Joint* j);
|
||||
void removeJointFromHere(Joint* j);
|
||||
|
||||
bool edgeHasPrimitiveHere(Edge *e, Primitive* p);
|
||||
bool edgeHasPrimitivesHere(Edge *e);
|
||||
void visitAddedPrimitive(Primitive* p, Joint* j, std::vector<Joint*>& jointsToPush);
|
||||
|
||||
public:
|
||||
///////////////////////////////////////////
|
||||
// IStage
|
||||
JointStage(IStage* upstream, World* world);
|
||||
|
||||
~JointStage();
|
||||
|
||||
/*override*/ IStage::StageType getStageType() const {return IStage::JOINT_STAGE;}
|
||||
|
||||
/*override*/ void onEdgeAdded(Edge* e);
|
||||
/*override*/ void onEdgeRemoving(Edge* e);
|
||||
|
||||
void onPrimitiveAdded(Primitive* p);
|
||||
void onPrimitiveRemoving(Primitive* p);
|
||||
};
|
||||
} // namespace
|
||||
@@ -0,0 +1,82 @@
|
||||
#pragma once
|
||||
|
||||
#include "util/G3DCore.h"
|
||||
|
||||
class btTriangleCallback;
|
||||
|
||||
namespace RBX {
|
||||
|
||||
union KDNode
|
||||
{
|
||||
struct
|
||||
{
|
||||
// left child contents is to the left of splits[0] along axis
|
||||
// right child contents is to the right of splits[1] along axis
|
||||
float splits[2];
|
||||
|
||||
// axis index; must be 0/1/2 (X/Y/Z)
|
||||
unsigned int axis: 2;
|
||||
|
||||
// left child is at childIndex; right child is at childIndex+1
|
||||
unsigned int childIndex: 30;
|
||||
} branch;
|
||||
|
||||
struct
|
||||
{
|
||||
unsigned int triangles[2];
|
||||
|
||||
// axis index; must be 3 so that isLeaf() can distinguish nodes
|
||||
unsigned int axis: 2;
|
||||
|
||||
unsigned int triangleCount: 30;
|
||||
} leaf;
|
||||
|
||||
bool isLeaf() const
|
||||
{
|
||||
return branch.axis == 3;
|
||||
}
|
||||
};
|
||||
|
||||
struct KDTree
|
||||
{
|
||||
const Vector3* vertexPositions;
|
||||
const unsigned char* vertexMaterials;
|
||||
const unsigned int* indices;
|
||||
|
||||
std::vector<KDNode> nodes;
|
||||
size_t depth;
|
||||
Vector3 extentsMin;
|
||||
Vector3 extentsMax;
|
||||
|
||||
struct RayResult
|
||||
{
|
||||
float fraction;
|
||||
const KDTree* tree;
|
||||
unsigned int triangle;
|
||||
|
||||
RayResult(): fraction(1), tree(NULL), triangle(0)
|
||||
{
|
||||
}
|
||||
|
||||
RayResult(float fraction, const KDTree* tree, unsigned int triangle): fraction(fraction), tree(tree), triangle(triangle)
|
||||
{
|
||||
}
|
||||
|
||||
bool hasHit() const
|
||||
{
|
||||
return tree != 0;
|
||||
}
|
||||
};
|
||||
|
||||
KDTree();
|
||||
|
||||
void build(const Vector3* vertexPositions, const unsigned char* vertexMaterials, size_t vertexCount, const unsigned int* indices, size_t triangleCount);
|
||||
|
||||
void queryAABB(btTriangleCallback* callback, const Vector3& aabbMin, const Vector3& aabbMax) const;
|
||||
void queryRay(RayResult& result, const Vector3& raySource, const Vector3& rayTarget) const;
|
||||
|
||||
Vector3 getTriangleNormal(unsigned int triangle) const;
|
||||
unsigned char getMaterial(unsigned int triangle, const Vector3& position) const;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include "V8World/Joint.h"
|
||||
#include "V8Kernel/Connector.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class KernelJoint
|
||||
: public Joint
|
||||
, public Connector // Implements "computeForce"
|
||||
{
|
||||
private:
|
||||
typedef Joint Super;
|
||||
// IPipelined
|
||||
protected:
|
||||
/*override*/ void putInKernel(Kernel* kernel);
|
||||
/*override*/ void removeFromKernel();
|
||||
private:
|
||||
// Joint
|
||||
/*override*/ JointType getJointType() const {return Joint::KERNEL_JOINT;}
|
||||
|
||||
// Connector
|
||||
/*override*/ Body* getBody(BodyIndex id) {
|
||||
RBXASSERT(inKernel());
|
||||
if (id == body0) {
|
||||
return getEngineBody();
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
/*implement*/ virtual Body* getEngineBody() = 0;
|
||||
/*override*/ KernelType getConnectorKernelType() const {return Connector::KERNEL_JOINT;}
|
||||
|
||||
public:
|
||||
KernelJoint() {}
|
||||
~KernelJoint() {}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
#include "util/PartMaterial.h"
|
||||
|
||||
|
||||
DYNAMIC_FASTFLAG(MaterialPropertiesEnabled)
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class PhysicalProperties;
|
||||
class ContactParams;
|
||||
class Primitive;
|
||||
|
||||
class MaterialProperties
|
||||
{
|
||||
private:
|
||||
// Helpers
|
||||
static float calculateUsingWeightedAverage(float weightA, float coeffA, float weightB, float coeffB);
|
||||
// Used on PartInstance initialization and property setting
|
||||
static float getDefaultMaterialFriction(PartMaterial material);
|
||||
static float getDefaultMaterialFrictionWeight(PartMaterial material);
|
||||
static float getDefaultMaterialElasticity(PartMaterial material);
|
||||
static float getDefaultMaterialElasticityWeight(PartMaterial material);
|
||||
static float getDefaultMaterialDensity(PartMaterial material);
|
||||
public:
|
||||
// Physical Behavior functions
|
||||
// Update Contact Parameters between two primitives, and Primitive to Terrain
|
||||
static void updateContactParamsPrims(ContactParams& params, Primitive* prim0, Primitive* prim1);
|
||||
static void updateContactParamsPrimMaterial(ContactParams& params, Primitive* prim, Primitive* otherPrim, PartMaterial otherMaterial);
|
||||
|
||||
static float getDensity(Primitive* prim);
|
||||
|
||||
// For humanoid Behavior
|
||||
static float frictionBetweenMaterials(PartMaterial materialA, PartMaterial materialB);
|
||||
static float frictionBetweenPrimAndMaterial(Primitive* primA, PartMaterial materialB);
|
||||
|
||||
// Property defaults helper
|
||||
static PhysicalProperties generatePhysicalMaterialFromPartMaterial(PartMaterial material);
|
||||
static PhysicalProperties getPrimitivePhysicalProperties(Primitive* prim);
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // NAMESPACE RBX
|
||||
@@ -0,0 +1,33 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/IWorldStage.h"
|
||||
|
||||
namespace RBX {
|
||||
class Assembly;
|
||||
class Mechanism;
|
||||
class AssemblyStage;
|
||||
|
||||
class MechToAssemblyStage : public IWorldStage
|
||||
{
|
||||
private:
|
||||
AssemblyStage* getAssemblyStage();
|
||||
|
||||
public:
|
||||
MechToAssemblyStage(IStage* upstream, World* world);
|
||||
|
||||
~MechToAssemblyStage();
|
||||
|
||||
/*override*/ IStage::StageType getStageType() const {return IStage::MECH_TO_ASSEMBLY_STAGE;}
|
||||
|
||||
void onFixedAssemblyAdded(Assembly* a);
|
||||
void onFixedAssemblyRemoving(Assembly* a);
|
||||
|
||||
void onSimulateAssemblyRootAdded(Assembly* a);
|
||||
void onSimulateAssemblyRootRemoving(Assembly* a);
|
||||
|
||||
void onNoSimulateAssemblyRootAdded(Assembly* a);
|
||||
void onNoSimulateAssemblyRootRemoving(Assembly* a);
|
||||
};
|
||||
} // namespace
|
||||
@@ -0,0 +1,73 @@
|
||||
/* Copyright 2003-2006 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/IPipelined.h"
|
||||
#include "Util/IndexedMesh.h"
|
||||
#include "boost/utility.hpp"
|
||||
#include "Assembly.h"
|
||||
|
||||
namespace RBX {
|
||||
class Primitive;
|
||||
|
||||
class Mechanism
|
||||
: public IPipelined
|
||||
, public boost::noncopyable
|
||||
, public IndexedMesh
|
||||
{
|
||||
private:
|
||||
static bool assemblyHasMovingParent(const Assembly* a);
|
||||
|
||||
public:
|
||||
Mechanism();
|
||||
|
||||
~Mechanism();
|
||||
|
||||
Primitive* getMechanismPrimitive();
|
||||
const Primitive* getConstMechanismPrimitive() const;
|
||||
|
||||
Assembly* getRootAssembly();
|
||||
const Assembly* getConstRootAssembly() const;
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Primitive Stuff
|
||||
|
||||
static bool isMechanismRootPrimitive(const Primitive* p);
|
||||
|
||||
static Mechanism* getPrimitiveMechanism(Primitive* p);
|
||||
static const Mechanism* getConstPrimitiveMechanism(const Primitive* p);
|
||||
|
||||
static Primitive* getRootMovingPrimitive(Primitive* p);
|
||||
static const Primitive* getConstRootMovingPrimitive(const Primitive* p);
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Assembly stuff
|
||||
|
||||
static bool isMovingAssemblyRoot(const Assembly* a);
|
||||
|
||||
static bool isComplexMovingMechanism(const Assembly* a); // i.e. - the assembly has children, connected by spring joints - complex networking issues
|
||||
|
||||
static Assembly* getMovingAssemblyRoot(Assembly* a);
|
||||
static const Assembly* getConstMovingAssemblyRoot(const Assembly* a);
|
||||
|
||||
private:
|
||||
template<class Func>
|
||||
inline void visitPrimitivesImpl(Func func, Assembly* a) {
|
||||
a->visitPrimitives(func);
|
||||
for (int i = 0; i < a->numChildren(); ++i) {
|
||||
Assembly* child = a->getTypedChild<Assembly>(i);
|
||||
visitPrimitivesImpl(func, child);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
// Primitive Visiting Functions
|
||||
template<class Func>
|
||||
inline void visitPrimitives(Func func) {
|
||||
Assembly *root = getRootAssembly();
|
||||
RBXASSERT(root);
|
||||
visitPrimitivesImpl(func, root);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
Utility class - holds MegaCluster dummy Meshes of same size for use by Geometry Pool.
|
||||
*/
|
||||
|
||||
#include "Util/Memory.h"
|
||||
#include "V8World/Mesh.h"
|
||||
|
||||
|
||||
namespace RBX {
|
||||
|
||||
namespace POLY {
|
||||
|
||||
class MegaClusterMesh : public Allocator<MegaClusterMesh>
|
||||
{
|
||||
private:
|
||||
Mesh mesh;
|
||||
Vector3 LocalCofM;
|
||||
|
||||
public:
|
||||
MegaClusterMesh(const Vector3& size)
|
||||
{
|
||||
mesh.makeBlock(size);
|
||||
}
|
||||
const Mesh* getMesh() const {return &mesh;}
|
||||
Vector3 GetLocalCofMFromMesh( void ) { return LocalCofM; }
|
||||
};
|
||||
|
||||
} // namespace POLY
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,86 @@
|
||||
#pragma once
|
||||
|
||||
#include "V8World/Poly.h"
|
||||
#include "V8World/GeometryPool.h"
|
||||
#include "V8World/MegaClusterMesh.h"
|
||||
#include "V8World/Primitive.h"
|
||||
#include "V8World/TerrainPartition.h"
|
||||
|
||||
class btConvexHullShape;
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class MegaClusterInstance;
|
||||
namespace Voxel {
|
||||
class Grid;
|
||||
}
|
||||
|
||||
const float MC_SEARCH_RAY_MAX = 2048.0f; // was 500.0f, but normal mouse has range coded to be 2048.0f
|
||||
const float MC_RAY_ZERO_SLOPE_TOLERANCE = .0005f;
|
||||
const float MC_HUGE_VAL = 9999999;
|
||||
|
||||
class MegaClusterPoly : public Poly
|
||||
{
|
||||
public:
|
||||
MegaClusterPoly(Primitive* p);
|
||||
~MegaClusterPoly();
|
||||
|
||||
typedef GeometryPool<Vector3, POLY::MegaClusterMesh, Vector3Comparer> MegaClusterMeshPool;
|
||||
typedef Poly Super;
|
||||
|
||||
/*override*/ virtual const G3D::Vector3& getSize() const {return Super::getSize();}
|
||||
/*override*/ bool setUpBulletCollisionData(void) { return false; }
|
||||
|
||||
private:
|
||||
MegaClusterMeshPool::Token aMegaClusterMesh;
|
||||
Primitive *myPrim;
|
||||
|
||||
scoped_ptr<TerrainPartitionMega> myTerrainPartition;
|
||||
|
||||
/*override*/ bool isGeometryOrthogonal( void ) const { return false; }
|
||||
|
||||
std::vector<btConvexHullShape*> bulletCellShapes;
|
||||
|
||||
void createBulletCellShapes(void);
|
||||
void createBulletCubeCell(void);
|
||||
void createBulletVerticalWedgeCell(void);
|
||||
void createBulletHorizontalWedgeCell(void);
|
||||
void createBulletCornerWedgeCell(void);
|
||||
void createBulletInverseCornerWedgeCell(void);
|
||||
|
||||
bool hitLocationOnBlockCell(const RbxRay& rayInMe, const Vector3int16& testCell, Vector3& localHitPoint, Vector3& surfaceNormal, int& surfId, CoordinateFrame& surfaceCf) const;
|
||||
bool hitLocationOnVerticalWedgeCell(const RbxRay& rayInMe, const Vector3int16& testCell, const int& orientation, Vector3& localHitPoint, Vector3& surfaceNormal, CoordinateFrame& surfaceCf) const;
|
||||
bool hitLocationOnHorizontalWedgeCell(const RbxRay& rayInMe, const Vector3int16& testCell, const int& orientation, Vector3& localHitPoint, Vector3& surfaceNormal, CoordinateFrame& surfaceCf) const;
|
||||
bool hitLocationOnCornerWedgeCell(const RbxRay& rayInMe, const Vector3int16& testCell, const int& orientation, Vector3& localHitPoint, Vector3& surfaceNormal, CoordinateFrame& surfaceCf) const;
|
||||
bool hitLocationOnInverseCornerWedgeCell(const RbxRay& rayInMe, const Vector3int16& testCell, const int& orientation, Vector3& localHitPoint, Vector3& surfaceNormal, CoordinateFrame& surfaceCf) const;
|
||||
|
||||
bool hitTestMC(const RbxRay& rayInMe, Vector3& localHitPoint, Vector3& surfaceNormal, int& surfId, CoordinateFrame& surfaceCf, float searchRayMax = MC_SEARCH_RAY_MAX, bool treatCellsAsBlocks = false, bool ignoreWater = false);
|
||||
|
||||
protected:
|
||||
// Geometry Overrides
|
||||
/*override*/ virtual GeometryType getGeometryType() const {return GEOMETRY_MEGACLUSTER;}
|
||||
/*override*/ Matrix3 getMoment(float mass) const { return Matrix3::identity(); }
|
||||
/*override*/ Vector3 getCofmOffset() const { return Vector3::zero(); }
|
||||
/*override*/ CoordinateFrame getSurfaceCoordInBody( const size_t surfaceId ) const;
|
||||
/*override*/ size_t getFaceFromLegacyNormalId( const NormalId nId ) const;
|
||||
|
||||
// Poly Overrides
|
||||
/*override*/ void buildMesh();
|
||||
public:
|
||||
/*override*/ bool hitTest(const RbxRay& rayInMe, Vector3& localHitPoint, Vector3& surfaceNormal, float searchRayMax = MC_SEARCH_RAY_MAX, bool treatCellsAsBlocks = false, bool ignoreWater = false);
|
||||
/*override*/ bool findTouchingSurfacesConvex( const CoordinateFrame& myCf, size_t& myFaceId, const Geometry& otherGeom, const CoordinateFrame& otherCf, size_t& otherFaceId ) const;
|
||||
|
||||
virtual bool hitTestTerrain(const RbxRay& rayInMe, Vector3& localHitPoint, int& surfId, CoordinateFrame& surfCf);
|
||||
|
||||
void findCellsTouchingGeometry( const CoordinateFrame& myCf, const Geometry& otherGeom, const CoordinateFrame& otherCf, std::vector<Vector3int16>* found ) const;
|
||||
void findCellsTouchingGeometryWithBuffer( const float& buffer, const CoordinateFrame& myCf, const Geometry& otherGeom, const CoordinateFrame& otherCf, std::vector<Vector3int16>* found ) const;
|
||||
bool findPlanarTouchesWithGeom( const CoordinateFrame& myCf, const Geometry& otherGeom, const CoordinateFrame& otherCf, std::vector<Vector3int16>* found ) const;
|
||||
|
||||
std::vector<Vector3> findCellIntersectionWithGeom( const Vector3int16& cell, const CoordinateFrame& myCf, const Geometry& otherGeom, const CoordinateFrame& otherCf, size_t & otherFaceId ) const;
|
||||
bool hasPlanarTouchWithGeom( const Vector3int16& cellIndex, const CoordinateFrame& myCf, const Geometry& otherGeom, const CoordinateFrame& otherCf ) const;
|
||||
bool cellsInBoundingBox(const Vector3& min, const Vector3& max);
|
||||
|
||||
btConvexHullShape* getBulletCellShape(Voxel::CellBlock shape);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,280 @@
|
||||
#pragma once
|
||||
|
||||
#include "Util/G3DCore.h"
|
||||
#include "rbx/Debug.h"
|
||||
#include "V8World/GeometryPool.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
|
||||
namespace POLY {
|
||||
class Edge;
|
||||
class Face;
|
||||
|
||||
/*
|
||||
V - E - V
|
||||
| | |
|
||||
E - F - E
|
||||
| | |
|
||||
V - E - V
|
||||
*/
|
||||
|
||||
class Vertex {
|
||||
private:
|
||||
size_t id;
|
||||
Vector3 offset;
|
||||
std::vector<Edge*> edges;
|
||||
|
||||
public:
|
||||
Vertex() {}
|
||||
|
||||
Vertex(size_t id, const Vector3& offset) : id(id), offset(offset)
|
||||
{}
|
||||
|
||||
const Vector3& getOffset() const {return offset;}
|
||||
|
||||
int getId() const {return id;}
|
||||
|
||||
void addEdge(Edge* value) {
|
||||
RBXASSERT(std::find(edges.begin(), edges.end(), value) == edges.end());
|
||||
edges.push_back(value);
|
||||
}
|
||||
|
||||
Edge* findEdge(const Vertex* other);
|
||||
|
||||
size_t numEdges() const {return edges.size();}
|
||||
size_t numFaces() const {return edges.size();}
|
||||
|
||||
Edge* getEdge(size_t i) const {
|
||||
return edges[i];
|
||||
}
|
||||
|
||||
static const Edge* recoverEdge(const Vertex* v0, const Vertex* v1);
|
||||
|
||||
const Face* getFace(size_t i) const;
|
||||
};
|
||||
|
||||
class Edge {
|
||||
private:
|
||||
size_t id;
|
||||
const Vertex* vertex[2];
|
||||
const Face* forward;
|
||||
const Face* backward;
|
||||
|
||||
public:
|
||||
Edge(size_t id, const Vertex* v0, const Vertex* v1)
|
||||
: id(id)
|
||||
, forward(NULL)
|
||||
, backward(NULL)
|
||||
{
|
||||
vertex[0] = v0;
|
||||
vertex[1] = v1;
|
||||
}
|
||||
|
||||
const Face* getForward() {return forward;}
|
||||
const Face* getBackward() {return backward;}
|
||||
|
||||
const Face* otherFace(const Face* test) const {
|
||||
if (test == forward) {
|
||||
return backward;
|
||||
}
|
||||
else {
|
||||
RBXASSERT(test == backward);
|
||||
return forward;
|
||||
}
|
||||
}
|
||||
|
||||
bool contains(const Vertex* v) const {
|
||||
return ((vertex[0] == v) || (vertex[1] == v));
|
||||
}
|
||||
|
||||
void addFace(const Face* face) {
|
||||
if (!forward) {
|
||||
forward = face;
|
||||
}
|
||||
else {
|
||||
RBXASSERT(face != forward);
|
||||
RBXASSERT(!backward);
|
||||
backward = face;
|
||||
}
|
||||
}
|
||||
|
||||
const Vertex* getVertex(const Face* face, size_t id) const {
|
||||
if (!face || (face == forward)) {
|
||||
RBXASSERT(vertex[id]);
|
||||
return vertex[id];
|
||||
}
|
||||
else {
|
||||
RBXASSERT(face == backward);
|
||||
RBXASSERT(vertex[(id+1)%2]);
|
||||
return vertex[(id+1)%2];
|
||||
}
|
||||
}
|
||||
|
||||
const Vector3& getVertexOffset(const Face* face, size_t id) const {
|
||||
return getVertex(face, id)->getOffset();
|
||||
}
|
||||
|
||||
const Face* getVertexFace(const Vertex* v) const {
|
||||
if (v == vertex[0]) {
|
||||
return forward;
|
||||
}
|
||||
else {
|
||||
RBXASSERT(v == vertex[1]);
|
||||
return backward;
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 computeNormal(const Face* face) const {
|
||||
return (getVertexOffset(face, 1) - getVertexOffset(face, 0)).direction();
|
||||
}
|
||||
|
||||
Line computeLine() const {
|
||||
return Line::fromTwoPoints(vertex[0]->getOffset(), vertex[1]->getOffset());
|
||||
}
|
||||
|
||||
size_t getId() const {return id;}
|
||||
|
||||
bool pointInVaronoi(const Vector3& point) const;
|
||||
};
|
||||
|
||||
class Face {
|
||||
private:
|
||||
size_t id; // id of face
|
||||
std::vector<Edge*> edges;
|
||||
Plane outwardPlane;
|
||||
|
||||
bool lineCrossesExtrusionSide(const Vector3& p0, const Vector3& p1, size_t edgeId) const;
|
||||
bool lineCrossesExtrusionSideBelow(const Vector3& p0, const Vector3& p1, size_t edgeId) const;
|
||||
|
||||
bool pointInExtrusionSide(const Vector3& pointOnSide, const Plane& sidePlane, size_t edgeId) const;
|
||||
|
||||
bool pointInInternalExtrusion(const Vector3& point) const {
|
||||
return ((plane().distance(point) <= 0.0f) && pointInExtrusion(point));
|
||||
}
|
||||
|
||||
public:
|
||||
Face(size_t id, Edge* e0, Edge* e1, Edge* e2);
|
||||
Face(size_t id, Edge* e0, Edge* e1, Edge* e2, Edge* e3);
|
||||
Face( size_t id, std::vector<Edge*>& edgeList );
|
||||
void initPlane();
|
||||
|
||||
const Vertex* getVertex(int id) const {
|
||||
return edges[id]->getVertex(this, 0);
|
||||
}
|
||||
|
||||
const Vector3& getVertexOffset(int id) const {
|
||||
return getVertex(id)->getOffset();
|
||||
}
|
||||
|
||||
const Vector3& normal() const {
|
||||
return outwardPlane.normal();
|
||||
}
|
||||
|
||||
size_t numEdges() const {return edges.size();}
|
||||
size_t numVertices() const {return edges.size();}
|
||||
|
||||
Edge* getEdge(size_t i) const {
|
||||
return edges[i];
|
||||
}
|
||||
|
||||
bool pointInExtrusion(const Vector3& point) const {
|
||||
Vector3 pointOnPlane = plane().closestPoint(point);
|
||||
return pointInFaceBorders(pointOnPlane);
|
||||
}
|
||||
|
||||
bool pointInFaceBorders(const Vector3& point) const; // point must be on face plane
|
||||
|
||||
const Plane& plane() const {
|
||||
RBXASSERT(edges.size() >= 3);
|
||||
//RBXASSERT(!(outwardPlane == Plane()));
|
||||
return outwardPlane;
|
||||
}
|
||||
|
||||
const Plane getSidePlane(size_t edgeId) const {
|
||||
Edge* edge = getEdge(edgeId);
|
||||
Vector3 sideVector = edge->computeNormal(this).cross(plane().normal());
|
||||
return Plane(sideVector, edge->getVertexOffset(this, 0));
|
||||
}
|
||||
|
||||
int getInternalExtrusionIntersection(const Vector3& pBelowInside, const Vector3& pBelowOutside) const;
|
||||
int findInternalExtrusionIntersection(const Vector3& p0, const Vector3& p1) const;
|
||||
void findInternalExtrusionIntersections(const Vector3& p0, const Vector3& p1, int& side0, int& side1) const;
|
||||
|
||||
size_t getId() const {return id;}
|
||||
|
||||
Vector3 getCentroid( void ) const;
|
||||
void getOrientedBoundingBox( const Vector3& xDir, const Vector3& yDir, Vector3& boxMin, Vector3& boxMax, Vector3& boxCenter ) const;
|
||||
|
||||
};
|
||||
|
||||
class Mesh {
|
||||
private:
|
||||
std::vector<Vertex> vertices;
|
||||
std::vector<Edge> edges;
|
||||
std::vector<Face> faces;
|
||||
|
||||
void clear();
|
||||
|
||||
void addVertex(float x, float y, float z);
|
||||
void addFace(size_t i, size_t j, size_t k);
|
||||
void addFace(size_t i, size_t j, size_t k, size_t l);
|
||||
void addFace( int numVerts, int vertIndexList[], bool reverseOrder );
|
||||
|
||||
Edge* findOrMakeEdge(size_t v0, size_t v1);
|
||||
Edge* addEdge(Vertex* vert0, Vertex* vert1);
|
||||
|
||||
bool lineIntersectsFace(const Line& line, const Face* face) const;
|
||||
bool rayIntersectsFace(const RbxRay& ray, const Face* face, Vector3& intersection) const;
|
||||
|
||||
public:
|
||||
Mesh() {}
|
||||
|
||||
size_t numFaces() const {return faces.size();}
|
||||
const POLY::Face* getFace(int i) const {return &faces[i];}
|
||||
|
||||
size_t numVertices() const {return vertices.size();}
|
||||
const POLY::Vertex* getVertex(int i) const {return &vertices[i];}
|
||||
|
||||
size_t numEdges() const {return edges.size();}
|
||||
const POLY::Edge* getEdge(int i) const {return &edges[i];}
|
||||
|
||||
bool containsFace(const Face* face) const {
|
||||
for (size_t i = 0; i < numFaces(); ++i) {
|
||||
if (face == getFace(i)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const POLY::Face* findFace(size_t i0, size_t i1, size_t i2);
|
||||
|
||||
const Vertex* farthestVertex(const Vector3& direction) const;
|
||||
|
||||
bool pointInMesh(const Vector3& point) const;
|
||||
|
||||
const Face* findFaceIntersection(const Vector3& inside, const Vector3& outside) const;
|
||||
|
||||
void findFaceIntersections(const Vector3& p0, const Vector3& p1, const Face* &f0, const Face* &f1) const;
|
||||
|
||||
bool hitTest(const RbxRay& ray, Vector3& hitPoint, Vector3& surfaceNormal) const;
|
||||
|
||||
void makeWedge(const Vector3& size);
|
||||
|
||||
void makePrism(const Vector3_2Ints& params, Vector3& cofm);
|
||||
void makePyramid(const Vector3_2Ints& params, Vector3& cofm);
|
||||
void makeParallelRamp(const Vector3& size, Vector3& cofm);
|
||||
void makeRightAngleRamp(const Vector3& size, Vector3& cofm);
|
||||
void makeCornerWedge(const Vector3& size, Vector3& cofm);
|
||||
|
||||
|
||||
void makeBlock(const Vector3& size);
|
||||
void makeCell(const Vector3& size, const Vector3& offset);
|
||||
void makeVerticalWedgeCell(const Vector3& size, const Vector3& offset, const int& orient);
|
||||
void makeHorizontalWedgeCell(const Vector3& size, const Vector3& offset, const int& orient);
|
||||
void makeCornerWedgeCell(const Vector3& size, const Vector3& offset, const int& orient);
|
||||
void makeInverseCornerWedgeCell(const Vector3& size, const Vector3& offset, const int& orient);
|
||||
};
|
||||
} // namespace POLY
|
||||
} // namespace
|
||||
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#include "V8World/Joint.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class D6Link;
|
||||
|
||||
class Motor6DJoint : public Joint
|
||||
{
|
||||
private:
|
||||
D6Link* link;
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// Joint
|
||||
/*override*/ JointType getJointType() const {return Joint::MOTOR_6D_JOINT;}
|
||||
/*override*/ bool isBroken() const {return false;}
|
||||
/*override*/ bool isAligned();
|
||||
|
||||
Vector3 poseOffsetDelta;
|
||||
Vector3 poseAxisAngleDelta;
|
||||
float poseMaskWeight;
|
||||
int poseFreshness;
|
||||
Vector3 currentOffset;
|
||||
Vector3 currentAxisAngle;
|
||||
|
||||
int getParentId() const;
|
||||
|
||||
void setJointOffsetCFrame(const Vector3 offset, const Vector3 axisAngle);
|
||||
|
||||
public:
|
||||
float maxZAngleVelocity; // for support of legacy animate scripts
|
||||
float desiredZAngle; //
|
||||
float getCurrentZAngle() const;//
|
||||
void setCurrentZAngle(float value);
|
||||
Vector3 getCurrentOffset() const {return currentOffset;}
|
||||
Vector3 getCurrentAngle() const {return currentAxisAngle;}
|
||||
bool setCurrentOffsetAngle(const Vector3 offset, const Vector3 axisAngle);
|
||||
void applyPose(const Vector3& poseOffset, const Vector3& poseAxisAngle, float poseWeight, float maskWeight);
|
||||
|
||||
CoordinateFrame getMeInOther(Primitive* me);
|
||||
|
||||
/*override*/ bool canStepUi() const {return true;}
|
||||
/*override*/ bool stepUi(double distributedGameTime);
|
||||
|
||||
Motor6DJoint();
|
||||
|
||||
~Motor6DJoint();
|
||||
|
||||
size_t hashCode() const;
|
||||
|
||||
/*override*/ Link* resetLink();
|
||||
|
||||
static bool isMotor6DJoint(const Edge* e) {
|
||||
return ( isJoint(e)
|
||||
&& rbx_static_cast<const Joint*>(e)->getJointType() == Joint::MOTOR_6D_JOINT);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include "V8World/Joint.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class RevoluteLink;
|
||||
|
||||
class MotorJoint : public Joint
|
||||
{
|
||||
private:
|
||||
RevoluteLink* link;
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// Joint
|
||||
/*override*/ JointType getJointType() const {return Joint::MOTOR_1D_JOINT;}
|
||||
/*override*/ bool isBroken() const {return false;}
|
||||
/*override*/ bool isAligned();
|
||||
|
||||
float currentAngle;
|
||||
float poseAngleDelta;
|
||||
float poseMaskWeight;
|
||||
int poseFreshness;
|
||||
|
||||
int getParentId() const;
|
||||
|
||||
void setJointAngle(float value);
|
||||
|
||||
public:
|
||||
// tweak this to adjust how long a pose stays applied in the absence of a fresh call to applyPose()
|
||||
static const int poseDuration = 32;
|
||||
|
||||
float maxVelocity;
|
||||
float desiredAngle;
|
||||
float getCurrentAngle() const {return currentAngle;}
|
||||
bool setCurrentAngle(float value);
|
||||
void applyPose(float poseAngle, float poseWeight, float maskWeight);
|
||||
|
||||
CoordinateFrame getMeInOther(Primitive* me);
|
||||
|
||||
/*override*/ bool canStepUi() const {return true;}
|
||||
/*override*/ bool stepUi(double distributedGameTime);
|
||||
|
||||
MotorJoint();
|
||||
|
||||
~MotorJoint();
|
||||
|
||||
size_t hashCode() const;
|
||||
|
||||
/*override*/ Link* resetLink();
|
||||
|
||||
static bool isMotorJoint(const Edge* e) {
|
||||
return ( isJoint(e)
|
||||
&& rbx_static_cast<const Joint*>(e)->getJointType() == Joint::MOTOR_1D_JOINT);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/IWorldStage.h"
|
||||
#include "V8World/Joint.h"
|
||||
#include "v8world/Assembly.h"
|
||||
|
||||
|
||||
namespace RBX {
|
||||
class Assembly;
|
||||
|
||||
class MovingAssemblyStage : public IWorldStage
|
||||
{
|
||||
private:
|
||||
///////////////////////////////////////
|
||||
typedef boost::intrusive::list<Joint, boost::intrusive::base_hook<MovingAssemblyStageHook> > Joints;
|
||||
Joints uiStepJoints;
|
||||
|
||||
boost::unordered_set<Joint*> animatedJoints;
|
||||
|
||||
typedef std::set<Assembly*> Assemblies;
|
||||
Assemblies movingGroundedAssemblies;
|
||||
Assemblies movingAnimatedAssemblies;
|
||||
|
||||
void addJoint(Joint* j);
|
||||
void removeJoint(Joint* j);
|
||||
|
||||
void jointsStepUiInternal(double distributedGameTime, Joint* j, bool fromAnimation);
|
||||
|
||||
public:
|
||||
MovingAssemblyStage(IStage* upstream, World* world);
|
||||
|
||||
~MovingAssemblyStage();
|
||||
|
||||
/*override*/ IStage::StageType getStageType() const {return IStage::MOVING_ASSEMBLY_STAGE;}
|
||||
|
||||
/*override*/ void onEdgeAdded(Edge* e);
|
||||
/*override*/ void onEdgeRemoving(Edge* e);
|
||||
|
||||
void addAnimatedJoint(Joint* j);
|
||||
void removeAnimatedJoint(Joint* j);
|
||||
|
||||
void jointsStepUi(double distributedGameTime);
|
||||
|
||||
void onSimulateAssemblyAdded(Assembly* a);
|
||||
void onSimulateAssemblyRemoving(Assembly* a);
|
||||
|
||||
void addMovingGroundedAssembly(Assembly* a);
|
||||
void removeMovingGroundedAssembly(Assembly* a);
|
||||
|
||||
void addMovingAnimatedAssembly(Assembly* a);
|
||||
void removeMovingAnimatedAssembly(Assembly *a);
|
||||
|
||||
int getMovingGroundedAssembliesSize() { return movingGroundedAssemblies.size(); }
|
||||
|
||||
Assemblies::iterator getMovingGroundedAssembliesBegin() {
|
||||
return movingGroundedAssemblies.begin();
|
||||
}
|
||||
Assemblies::iterator getMovingGroundedAssembliesEnd() {
|
||||
return movingGroundedAssemblies.end();
|
||||
}
|
||||
const Assemblies& getMovingGroundedAssemblies() {
|
||||
return movingGroundedAssemblies;
|
||||
}
|
||||
|
||||
const Assemblies& getMovingAnimatedAssemblies() {
|
||||
return movingAnimatedAssemblies;
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
@@ -0,0 +1,34 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/IWorldStage.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Mechanism;
|
||||
class Assembly;
|
||||
|
||||
class MovingStage : public IWorldStage
|
||||
{
|
||||
private:
|
||||
class SpatialFilter* getSpatialFilter();
|
||||
|
||||
public:
|
||||
///////////////////////////////////////////
|
||||
// IStage
|
||||
MovingStage(IStage* upstream, World* world);
|
||||
|
||||
~MovingStage();
|
||||
|
||||
/*override*/ IStage::StageType getStageType() const {return IStage::MOVING_STAGE;}
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// From the Joint Stage
|
||||
//
|
||||
void onMechanismAdded(Mechanism* a);
|
||||
void onMechanismRemoving(Mechanism* a);
|
||||
};
|
||||
} // namespace
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/Joint.h"
|
||||
#include "Util/Extents.h"
|
||||
#include "Util/Face.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Kernel;
|
||||
class Channel;
|
||||
class Connector;
|
||||
class Point;
|
||||
class Primitive;
|
||||
|
||||
class MultiJoint : public Joint
|
||||
{
|
||||
private:
|
||||
typedef Joint Super;
|
||||
int numConnector;
|
||||
Point* point[8];
|
||||
|
||||
bool pointsAligned() const;
|
||||
void init(int numBreaking);
|
||||
int numBreakingConnectors;
|
||||
|
||||
bool validateMultiJoint();
|
||||
|
||||
protected:
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Edge
|
||||
/*override*/ void putInKernel(Kernel* kernel);
|
||||
/*override*/ void removeFromKernel();
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Joint
|
||||
/*override*/ bool isBroken() const;
|
||||
|
||||
Connector* connector[4]; // NormalBreakConnector
|
||||
|
||||
void addToMultiJoint(Point* point0, Point* point1, Connector* _connector);
|
||||
Point* getPoint(int id);
|
||||
Connector* getConnector(int id);
|
||||
|
||||
float getJointK();
|
||||
|
||||
MultiJoint(int numBreaking);
|
||||
|
||||
MultiJoint(
|
||||
Primitive* p0,
|
||||
Primitive* p1,
|
||||
const CoordinateFrame& jointCoord0,
|
||||
const CoordinateFrame& jointCoord1,
|
||||
int numBreaking);
|
||||
|
||||
~MultiJoint();
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
Utility class - holds ParallelRamp Meshes of same size for use by Geometry Pool.
|
||||
*/
|
||||
|
||||
#include "Util/Memory.h"
|
||||
#include "V8World/Mesh.h"
|
||||
|
||||
|
||||
namespace RBX {
|
||||
|
||||
namespace POLY {
|
||||
|
||||
class ParallelRampMesh : public Allocator<ParallelRampMesh>
|
||||
{
|
||||
private:
|
||||
Mesh mesh;
|
||||
Vector3 LocalCofM;
|
||||
|
||||
public:
|
||||
ParallelRampMesh(const Vector3& size)
|
||||
{
|
||||
mesh.makeParallelRamp(size, LocalCofM);
|
||||
}
|
||||
const Mesh* getMesh() const {return &mesh;}
|
||||
const Vector3& GetLocalCofMFromMesh() const { return LocalCofM; }
|
||||
};
|
||||
|
||||
} // namespace POLY
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include "V8World/Poly.h"
|
||||
#include "V8World/GeometryPool.h"
|
||||
#include "V8World/ParallelRampMesh.h"
|
||||
#include "V8World/BlockMesh.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class ParallelRampPoly : public Poly {
|
||||
public:
|
||||
typedef GeometryPool<Vector3, POLY::ParallelRampMesh, Vector3Comparer> ParallelRampMeshPool;
|
||||
|
||||
/*override*/ Matrix3 getMoment(float mass) const;
|
||||
/*override*/ Vector3 getCofmOffset() const;
|
||||
/*override*/ bool isGeometryOrthogonal( void ) const { return false; }
|
||||
/*override*/ bool setUpBulletCollisionData(void) { return false; }
|
||||
|
||||
private:
|
||||
ParallelRampMeshPool::Token aParallelRampMesh;
|
||||
|
||||
protected:
|
||||
// Geometry Overrides
|
||||
/*override*/ virtual GeometryType getGeometryType() const {return GEOMETRY_PARALLELRAMP;}
|
||||
|
||||
// Poly Overrides
|
||||
/*override*/ void buildMesh();
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
|
||||
#include "V8World/Geometry.h"
|
||||
#include "V8World/Mesh.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
namespace POLY {
|
||||
class Mesh;
|
||||
}
|
||||
|
||||
|
||||
class Poly : public Geometry {
|
||||
private:
|
||||
typedef Geometry Super;
|
||||
float centerToCornerDistance;
|
||||
|
||||
protected:
|
||||
const POLY::Mesh* mesh;
|
||||
|
||||
/*override*/ void setSize(const G3D::Vector3& _size);
|
||||
|
||||
float getCenterToCornerDistance() const {return centerToCornerDistance;}
|
||||
|
||||
Vector3 getCenterToCornerWorst() const {return Vector3(centerToCornerDistance, centerToCornerDistance, centerToCornerDistance);}
|
||||
|
||||
/*implement*/ virtual void buildMesh() = 0;
|
||||
|
||||
public:
|
||||
Poly() : mesh(NULL) {}
|
||||
~Poly() {}
|
||||
|
||||
// Geometry Overrides
|
||||
/*override*/ virtual CollideType getCollideType() const {return COLLIDE_POLY;}
|
||||
|
||||
/*override*/ virtual bool hitTest(const RbxRay& rayInMe, Vector3& localHitPoint, Vector3& surfaceNormal);
|
||||
|
||||
/*override*/ float getRadius() const {return centerToCornerDistance;}
|
||||
|
||||
/*override*/ Vector3 getCenterToCorner(const Matrix3& rotation) const {return getCenterToCornerWorst();}
|
||||
|
||||
/*override*/ Vector3 getCofmOffset() const;
|
||||
|
||||
/*override*/ Matrix3 getMoment(float mass) const;
|
||||
|
||||
/*override*/ bool collidesWithGroundPlane(const CoordinateFrame& c, float yHeight) const;
|
||||
|
||||
const POLY::Mesh* getMesh() const {return mesh;}
|
||||
|
||||
// Dragger/joiner support
|
||||
size_t closestSurfaceToPoint( const Vector3& pointInBody ) const;
|
||||
Plane getPlaneFromSurface( const size_t surfaceId ) const;
|
||||
virtual CoordinateFrame getSurfaceCoordInBody( const size_t surfaceId ) const;
|
||||
Vector3 getSurfaceNormalInBody( const size_t surfaceId ) const;
|
||||
size_t getMostAlignedSurface( const Vector3& vecInWorld, const G3D::Matrix3& objectR ) const;
|
||||
int getNumSurfaces( void ) const { return mesh->numFaces(); }
|
||||
Vector3 getSurfaceVertInBody( const size_t surfaceId, const int vertId ) const;
|
||||
int getNumVertsInSurface( const size_t surfaceId ) const;
|
||||
bool vertOverlapsFace( const Vector3& pointInBody, const size_t surfaceId ) const;
|
||||
|
||||
/*override*/virtual bool findTouchingSurfacesConvex( const CoordinateFrame& myCf, size_t& myFaceId, const Geometry& otherGeom, const CoordinateFrame& otherCf, size_t& otherFaceId ) const;
|
||||
/*override*/virtual bool FacesOverlapped( const CoordinateFrame& myCf, size_t& myFaceId, const Geometry& otherGeom, const CoordinateFrame& otherCf, size_t& otherFaceId, float tol ) const;
|
||||
/*override*/virtual bool FaceVerticesOverlapped( const CoordinateFrame& myCf, size_t& myFaceId, const Geometry& otherGeom, const CoordinateFrame& otherCf, size_t& otherFaceId, float tol ) const;
|
||||
/*override*/virtual bool FaceEdgesOverlapped( const CoordinateFrame& myCf, size_t& myFaceId, const Geometry& otherGeom, const CoordinateFrame& otherCf, size_t& otherFaceId, float tol ) const;
|
||||
|
||||
|
||||
/*override*/ std::vector<Vector3> polygonIntersectionWithFace( const std::vector<Vector3>& polygonInBody, const size_t surfaceId ) const;
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,158 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/CellContact.h"
|
||||
#include "V8World/PolyPolyContact.h"
|
||||
#include "V8Kernel/ContactParams.h"
|
||||
#include "V8World/Mesh.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Poly;
|
||||
class PolyCellContact;
|
||||
class FaceVertexConnector;
|
||||
class FaceEdgeConnector;
|
||||
class EdgeEdgeConnector;
|
||||
|
||||
namespace POLY {
|
||||
class Face;
|
||||
class Edge;
|
||||
class Vertex;
|
||||
class Mesh;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
class PolyCellPair
|
||||
{
|
||||
protected:
|
||||
Primitive* primitive[2];
|
||||
ContactParams contactParams;
|
||||
bool swapPrims;
|
||||
|
||||
PolyCellContact* myPCContact;
|
||||
|
||||
const Poly* poly0() const;
|
||||
const Poly* poly1() const;
|
||||
|
||||
const Poly* poly(size_t i) {
|
||||
return (i == 0) ? poly0() : poly1();
|
||||
}
|
||||
|
||||
/*implement*/ virtual bool isFaceFace() const = 0;
|
||||
/*override*/ virtual bool pairIsValid() { return true; }
|
||||
|
||||
public:
|
||||
PolyCellPair(Primitive* p0, Primitive* p1, const ContactParams& contactParams, PolyCellContact* aPCContact, bool swap)
|
||||
: contactParams(contactParams)
|
||||
{
|
||||
primitive[0] = p0;
|
||||
primitive[1] = p1;
|
||||
myPCContact = aPCContact;
|
||||
swapPrims = swap;
|
||||
}
|
||||
virtual ~PolyCellPair() {}
|
||||
|
||||
/*implement*/ virtual PolyCellPair* allocateClone() = 0;
|
||||
/*implement*/ virtual float test() = 0;
|
||||
/*implement*/ virtual void loadConnectors(ConnectorArray& newConnectors) = 0;
|
||||
|
||||
bool match(const PolyCellPair* other) const {
|
||||
return ( (isFaceFace() == other->isFaceFace())
|
||||
&& (primitive[0] == other->primitive[0]) );
|
||||
}
|
||||
};
|
||||
|
||||
class CellFaceFacePair : public PolyCellPair
|
||||
{
|
||||
private:
|
||||
const POLY::Face* mainFace;
|
||||
const POLY::Face* otherFace;
|
||||
|
||||
const POLY::Face* face(size_t i) {
|
||||
return (i == 0) ? mainFace : otherFace;
|
||||
}
|
||||
|
||||
const Poly* facePoly() const {return poly0();}
|
||||
const Poly* otherPoly() const {return poly1();}
|
||||
|
||||
typedef enum {ABOVE_INSIDE, ABOVE_OUTSIDE, BELOW_INSIDE, BELOW_OUTSIDE} VertexStatus;
|
||||
|
||||
//void computeVertices(FixedArray<Vector3, 8>& verticesInObject, const CoordinateFrame& otherInMe);
|
||||
void computeVertices(FixedArray<Vector3, CONTACT_ARRAY_SIZE>& verticesInObject, const CoordinateFrame& otherInMe);
|
||||
//float closestVertex(const POLY::Face* face, const FixedArray<Vector3, 8>& verticesInObject, const POLY::Vertex* &closestVertex);
|
||||
float closestVertex(const POLY::Face* face, const FixedArray<Vector3, CONTACT_ARRAY_SIZE>& verticesInObject, const POLY::Vertex* &closestVertex);
|
||||
|
||||
const POLY::Face* findOtherFace(const POLY::Vertex* closeVertex);
|
||||
|
||||
//bool loadVertices(FixedArray<VertexStatus, 8>* vertexStatus, CoordinateFrame* vertexInFace, ConnectorArray& newConnectors);
|
||||
bool loadVertices(FixedArray<VertexStatus, CONTACT_ARRAY_SIZE>* vertexStatus, CoordinateFrame* vertexInFace, ConnectorArray& newConnectors);
|
||||
//bool testVerticesInside(size_t faceId, FixedArray<VertexStatus, 8>& vertexStatus, const CoordinateFrame& vertexInFace, ConnectorArray& newConnectors);
|
||||
bool testVerticesInside(size_t faceId, FixedArray<VertexStatus, CONTACT_ARRAY_SIZE>& vertexStatus, const CoordinateFrame& vertexInFace, ConnectorArray& newConnectors);
|
||||
VertexStatus vertexInPoly(const POLY::Face* planeFace, const POLY::Mesh* planeMesh, const POLY::Vertex* vertex, const CoordinateFrame& otherInMe);
|
||||
|
||||
void vertexInside(
|
||||
Primitive* pFace,
|
||||
Primitive* pVertex,
|
||||
const POLY::Vertex* inside,
|
||||
const POLY::Face* planeFace,
|
||||
ConnectorArray& newConnectors);
|
||||
|
||||
void checkOneSideIntersection(const POLY::Vertex* v0, const POLY::Vertex* v1, const CoordinateFrame& otherInMe, ConnectorArray& newConnectors);
|
||||
void validateOneSideIntersection(const POLY::Vertex* belowInside, const POLY::Vertex* belowOutside, const CoordinateFrame& otherInMe, ConnectorArray& newConnectors);
|
||||
void checkTwoSideIntersections(const POLY::Vertex* v0, const POLY::Vertex* v1, const CoordinateFrame& otherInMe, ConnectorArray& newConnectors);
|
||||
|
||||
FaceEdgeConnector* newFaceEdgeConnector(size_t mainFaceEdgeId, const POLY::Vertex* v0, const POLY::Vertex* v1);
|
||||
|
||||
/*override*/ bool isFaceFace() const {return true;}
|
||||
/*override*/ PolyCellPair* allocateClone();
|
||||
/*override*/ float test();
|
||||
/*override*/ void loadConnectors(ConnectorArray& newConnectors);
|
||||
|
||||
public:
|
||||
CellFaceFacePair(Primitive* p0, Primitive* p1, const ContactParams& contactParams, PolyCellContact* aPCContact, bool swap);
|
||||
bool pairIsValid(void);
|
||||
|
||||
};
|
||||
|
||||
class CellEdgeEdgePair : public PolyCellPair
|
||||
{
|
||||
private:
|
||||
const POLY::Edge* bestEdge0;
|
||||
const POLY::Edge* bestEdge1;
|
||||
|
||||
void computeMinMax(const Plane& planeInMesh, const POLY::Mesh* mesh, float& min, float& max);
|
||||
|
||||
EdgeEdgeConnector* newEdgeEdgeConnector();
|
||||
|
||||
/*override*/ bool isFaceFace() const {return false;}
|
||||
/*override*/ PolyCellPair* allocateClone();
|
||||
/*override*/ float test();
|
||||
/*override*/ void loadConnectors(ConnectorArray& newConnectors);
|
||||
|
||||
public:
|
||||
CellEdgeEdgePair(Primitive* p0, Primitive* p1, const ContactParams& contactParams, PolyCellContact* aPCContact, bool swap);
|
||||
};
|
||||
|
||||
class PolyCellContact
|
||||
: public CellMeshContact
|
||||
, public Allocator<PolyCellContact>
|
||||
{
|
||||
private:
|
||||
PolyCellPair* bestPair;
|
||||
|
||||
void findBestPair();
|
||||
void resetBestPair(PolyCellPair* pairOnStack);
|
||||
|
||||
/*override*/ void findClosestFeatures(ConnectorArray& newConnectors);
|
||||
|
||||
public:
|
||||
PolyCellContact(Primitive* p0, Primitive* p1, const Vector3int16& cell);
|
||||
~PolyCellContact();
|
||||
|
||||
static float epsilonDistance(); // distance to switch
|
||||
void generateDataForMovingAssemblyStage(void); /*override*/
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,47 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/Contact.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class PolyConnector;
|
||||
|
||||
//typedef RBX::FixedArray<PolyConnector*, 12> ConnectorArray; // TODO - should only ever need 8
|
||||
typedef RBX::FixedArray<PolyConnector*, CONTACT_ARRAY_SIZE> ConnectorArray; // TODO - should only ever need 8
|
||||
|
||||
class PolyContact : public Contact
|
||||
{
|
||||
private:
|
||||
ConnectorArray polyConnectors;
|
||||
|
||||
void removeAllConnectorsFromKernel();
|
||||
void putAllConnectorsInKernel();
|
||||
void updateClosestFeatures();
|
||||
float worstFeatureOverlap();
|
||||
void deleteConnectors(ConnectorArray& deleteConnectors);
|
||||
void matchClosestFeatures(ConnectorArray& newConnectors);
|
||||
PolyConnector* matchClosestFeature(PolyConnector* newConnector);
|
||||
void updateContactPoints();
|
||||
|
||||
// Contact
|
||||
/*override*/ void deleteAllConnectors();
|
||||
/*override*/ int numConnectors() const {return polyConnectors.size();}
|
||||
/*override*/ ContactConnector* getConnector(int i);
|
||||
/*override*/ bool computeIsColliding(float overlapIgnored);
|
||||
/*override*/ bool stepContact();
|
||||
|
||||
/*implement*/ virtual void findClosestFeatures(ConnectorArray& newConnectors) = 0;
|
||||
|
||||
public:
|
||||
PolyContact(Primitive* p0, Primitive* p1)
|
||||
: Contact(p0, p1)
|
||||
{}
|
||||
|
||||
~PolyContact();
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,157 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/PolyContact.h"
|
||||
#include "V8Kernel/ContactParams.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Poly;
|
||||
class PolyPolyContact;
|
||||
class FaceVertexConnector;
|
||||
class FaceEdgeConnector;
|
||||
class EdgeEdgeConnector;
|
||||
|
||||
namespace POLY {
|
||||
class Face;
|
||||
class Edge;
|
||||
class Vertex;
|
||||
class Mesh;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class PolyPair
|
||||
{
|
||||
protected:
|
||||
Primitive* primitive[2];
|
||||
ContactParams contactParams;
|
||||
|
||||
const Poly* poly0() const;
|
||||
const Poly* poly1() const;
|
||||
|
||||
const Poly* poly(size_t i) {
|
||||
return (i == 0) ? poly0() : poly1();
|
||||
}
|
||||
|
||||
/*implement*/ virtual bool isFaceFace() const = 0;
|
||||
|
||||
public:
|
||||
PolyPair(Primitive* p0, Primitive* p1, const ContactParams& contactParams)
|
||||
: contactParams(contactParams)
|
||||
{
|
||||
primitive[0] = p0;
|
||||
primitive[1] = p1;
|
||||
}
|
||||
virtual ~PolyPair() {}
|
||||
|
||||
/*implement*/ virtual PolyPair* allocateClone() = 0;
|
||||
/*implement*/ virtual float test() = 0;
|
||||
/*implement*/ virtual void loadConnectors(ConnectorArray& newConnectors) = 0;
|
||||
|
||||
bool match(const PolyPair* other) const {
|
||||
return ( (isFaceFace() == other->isFaceFace())
|
||||
&& (primitive[0] == other->primitive[0]) );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class FaceFacePair : public PolyPair
|
||||
{
|
||||
private:
|
||||
const POLY::Face* mainFace;
|
||||
const POLY::Face* otherFace;
|
||||
const POLY::Face* nextBestOtherFace;
|
||||
|
||||
const POLY::Face* face(size_t i) {
|
||||
return (i == 0) ? mainFace : otherFace;
|
||||
}
|
||||
|
||||
const Poly* facePoly() const {return poly0();}
|
||||
const Poly* otherPoly() const {return poly1();}
|
||||
|
||||
typedef enum {ABOVE_INSIDE, ABOVE_OUTSIDE, BELOW_INSIDE, BELOW_OUTSIDE} VertexStatus;
|
||||
|
||||
//void computeVertices(FixedArray<Vector3, 8>& verticesInObject, const CoordinateFrame& otherInMe);
|
||||
void computeVertices(FixedArray<Vector3, CONTACT_ARRAY_SIZE>& verticesInObject, const CoordinateFrame& otherInMe);
|
||||
//float closestVertex(const POLY::Face* face, const FixedArray<Vector3, 8>& verticesInObject, const POLY::Vertex* &closestVertex);
|
||||
float closestVertex(const POLY::Face* face, const FixedArray<Vector3, CONTACT_ARRAY_SIZE>& verticesInObject, const POLY::Vertex* &closestVertex);
|
||||
|
||||
const POLY::Face* findOtherFace(const POLY::Vertex* closeVertex);
|
||||
|
||||
//bool loadVertices(FixedArray<VertexStatus, 8>* vertexStatus, CoordinateFrame* vertexInFace, ConnectorArray& newConnectors);
|
||||
bool loadVertices(FixedArray<VertexStatus, CONTACT_ARRAY_SIZE>* vertexStatus, CoordinateFrame* vertexInFace, ConnectorArray& newConnectors);
|
||||
//bool testVerticesInside(size_t faceId, FixedArray<VertexStatus, 8>& vertexStatus, const CoordinateFrame& vertexInFace, ConnectorArray& newConnectors);
|
||||
bool testVerticesInside(size_t faceId, FixedArray<VertexStatus, CONTACT_ARRAY_SIZE>& vertexStatus, const CoordinateFrame& vertexInFace, ConnectorArray& newConnectors);
|
||||
VertexStatus vertexInPoly(const POLY::Face* planeFace, const POLY::Mesh* planeMesh, const POLY::Vertex* vertex, const CoordinateFrame& otherInMe);
|
||||
|
||||
void vertexInside(
|
||||
Primitive* pFace,
|
||||
Primitive* pVertex,
|
||||
const POLY::Vertex* inside,
|
||||
const POLY::Face* planeFace,
|
||||
ConnectorArray& newConnectors);
|
||||
|
||||
void checkOneSideIntersection(const POLY::Vertex* v0, const POLY::Vertex* v1, const CoordinateFrame& otherInMe, ConnectorArray& newConnectors);
|
||||
void validateOneSideIntersection(const POLY::Vertex* belowInside, const POLY::Vertex* belowOutside, const CoordinateFrame& otherInMe, ConnectorArray& newConnectors);
|
||||
void checkTwoSideIntersections(const POLY::Vertex* v0, const POLY::Vertex* v1, const CoordinateFrame& otherInMe, ConnectorArray& newConnectors);
|
||||
|
||||
FaceEdgeConnector* newFaceEdgeConnector(size_t mainFaceEdgeId, const POLY::Vertex* v0, const POLY::Vertex* v1);
|
||||
|
||||
/*override*/ bool isFaceFace() const {return true;}
|
||||
/*override*/ PolyPair* allocateClone();
|
||||
/*override*/ float test();
|
||||
/*override*/ void loadConnectors(ConnectorArray& newConnectors);
|
||||
|
||||
public:
|
||||
FaceFacePair(Primitive* p0, Primitive* p1, const ContactParams& contactParams);
|
||||
void setOtherFace(const POLY::Face* aFace) { otherFace = aFace; }
|
||||
const POLY::Face* getNextBestOtherFace(void) { return nextBestOtherFace; }
|
||||
};
|
||||
|
||||
class EdgeEdgePair : public PolyPair
|
||||
{
|
||||
private:
|
||||
const POLY::Edge* bestEdge0;
|
||||
const POLY::Edge* bestEdge1;
|
||||
|
||||
void computeMinMax(const Plane& planeInMesh, const POLY::Mesh* mesh, float& min, float& max);
|
||||
|
||||
EdgeEdgeConnector* newEdgeEdgeConnector();
|
||||
|
||||
/*override*/ bool isFaceFace() const {return false;}
|
||||
/*override*/ PolyPair* allocateClone();
|
||||
/*override*/ float test();
|
||||
/*override*/ void loadConnectors(ConnectorArray& newConnectors);
|
||||
|
||||
public:
|
||||
EdgeEdgePair(Primitive* p0, Primitive* p1, const ContactParams& contactParams);
|
||||
};
|
||||
|
||||
|
||||
|
||||
class PolyPolyContact
|
||||
: public PolyContact
|
||||
, public Allocator<PolyPolyContact>
|
||||
{
|
||||
private:
|
||||
PolyPair* bestPair;
|
||||
|
||||
void findBestPair();
|
||||
void resetBestPair(PolyPair* pairOnStack);
|
||||
|
||||
/*override*/ void findClosestFeatures(ConnectorArray& newConnectors);
|
||||
public:
|
||||
PolyPolyContact(Primitive* p0, Primitive* p1);
|
||||
~PolyPolyContact();
|
||||
|
||||
static float epsilonDistance(); // distance to switch
|
||||
|
||||
void generateDataForMovingAssemblyStage(void); /*override*/
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,430 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8Kernel/BodyPvSetter.h"
|
||||
#include "V8World/Geometry.h"
|
||||
#include "V8World/Edge.h"
|
||||
#include "V8World/SurfaceData.h"
|
||||
#include "V8World/IMoving.h"
|
||||
#include "V8World/BasicSpatialHashPrimitive.h"
|
||||
#include "Util/SurfaceType.h"
|
||||
#include "Util/Extents.h"
|
||||
#include "Util/Face.h"
|
||||
#include "Util/NormalId.h"
|
||||
#include "Util/ComputeProp.h"
|
||||
#include "Util/G3DCore.h"
|
||||
#include "Util/Guid.h"
|
||||
#include "Util/IndexArray.h"
|
||||
#include "Util/SpanningNode.h"
|
||||
#include "Util/SystemAddress.h"
|
||||
#include "Util/CompactEnum.h"
|
||||
#include "util/PhysicalProperties.h"
|
||||
#include "util/PartMaterial.h"
|
||||
#include <string>
|
||||
#include <boost/flyweight.hpp>
|
||||
|
||||
namespace RBX {
|
||||
enum NetworkOwnership
|
||||
{
|
||||
NetworkOwnership_Auto = 0,
|
||||
NetworkOwnership_Manual = 1
|
||||
};
|
||||
|
||||
class Body;
|
||||
class Clump;
|
||||
class Assembly;
|
||||
class Mechanism;
|
||||
class World;
|
||||
template<class P, class C, class CM, int M> class SpatialHash;
|
||||
class Contact;
|
||||
class Joint;
|
||||
struct RootPrimitiveOwnershipData;
|
||||
|
||||
class EdgeList
|
||||
{
|
||||
private:
|
||||
struct Entry
|
||||
{
|
||||
Edge* edge;
|
||||
Primitive* other;
|
||||
};
|
||||
|
||||
Primitive* owner;
|
||||
std::vector<Entry> list;
|
||||
|
||||
public:
|
||||
EdgeList(Primitive* owner) : owner(owner)
|
||||
{}
|
||||
|
||||
~EdgeList() {
|
||||
RBXASSERT(list.size() == 0);
|
||||
}
|
||||
|
||||
int size() const {return list.size();}
|
||||
|
||||
Edge* getEdge(int i) const
|
||||
{
|
||||
RBXASSERT_VERY_FAST(unsigned(i) < list.size());
|
||||
RBXASSERT_VERY_FAST(list[i].edge->otherPrimitive(owner) == list[i].other);
|
||||
return list[i].edge;
|
||||
}
|
||||
|
||||
Primitive* getOther(int i) const
|
||||
{
|
||||
RBXASSERT_VERY_FAST(unsigned(i) < list.size());
|
||||
RBXASSERT_VERY_FAST(list[i].edge->otherPrimitive(owner) == list[i].other);
|
||||
return list[i].other;
|
||||
}
|
||||
|
||||
Edge* getFirst() const {return (list.size() > 0) ? list[0].edge : NULL;}
|
||||
|
||||
Edge* getNext(const Primitive* p, Edge* e) const;
|
||||
|
||||
void insertEdge(Edge* e);
|
||||
void removeEdge(Edge* e);
|
||||
};
|
||||
|
||||
class Primitive : public IPipelined
|
||||
, public SpanningNode
|
||||
, public BodyPvSetter
|
||||
, public BasicSpatialHashPrimitive
|
||||
{
|
||||
template<class P, class C, class CM, int M> friend class SpatialHash;
|
||||
|
||||
|
||||
public:
|
||||
static bool allowSleep;
|
||||
|
||||
typedef enum {DYNAMICS_ENGINE, HUMANOID_ENGINE} EngineType;
|
||||
typedef enum {DEFAULT_SIZE, TORSO_SIZE, ROOT_SIZE, SEAT_SIZE} SizeMultiplier; // overweights torsos and seats to make them roots of the spanning tree
|
||||
|
||||
// bullet related
|
||||
void updateBulletCollisionObject(void);
|
||||
|
||||
// Moved to public for CSG
|
||||
Vector3 clipToSafeSize(const Vector3& newSize);
|
||||
|
||||
// WORLD access here
|
||||
public:
|
||||
int& worldIndexFunc() {return worldIndex;}
|
||||
|
||||
private:
|
||||
void onChangedInKernel();
|
||||
|
||||
// For fuzzyExtents - when updated
|
||||
static int fuzzyExtentsReset() {return -2;} // out of synch with body -1;
|
||||
|
||||
Extents computeFuzzyExtents();
|
||||
void setFixed(bool newAnchoredProperty, bool newDragging);
|
||||
|
||||
float computeJointK();
|
||||
|
||||
Geometry* newGeometry(Geometry::GeometryType geometryType);
|
||||
|
||||
public:
|
||||
Primitive(Geometry::GeometryType geometryType);
|
||||
virtual ~Primitive();
|
||||
|
||||
const Guid& getGuid() const;
|
||||
void setGuid(const Guid& value);
|
||||
|
||||
unsigned int getSizeMultiplier() const;
|
||||
void setSizeMultiplier(SizeMultiplier value);
|
||||
|
||||
void calculateSortSize();
|
||||
unsigned int getSortSize();
|
||||
|
||||
World* getWorld() const {return world;}
|
||||
void setWorld(World* _world) {world = _world;}
|
||||
|
||||
// Clump
|
||||
Clump* getClump();
|
||||
const Clump* getConstClump() const;
|
||||
Assembly* getAssembly();
|
||||
const Assembly* getConstAssembly() const;
|
||||
Mechanism* getMechanism();
|
||||
const Mechanism* getConstMechanism() const;
|
||||
|
||||
// Geometry
|
||||
Geometry* getGeometry() {return geometry;}
|
||||
const Geometry* getConstGeometry() const {return geometry;}
|
||||
|
||||
void resetGeometryType(Geometry::GeometryType geometryType);
|
||||
void setGeometryType(Geometry::GeometryType geometryType);
|
||||
Geometry::GeometryType getGeometryType() const;
|
||||
Geometry::CollideType getCollideType() const;
|
||||
|
||||
// Body
|
||||
Body* getBody() {return body;}
|
||||
const Body* getConstBody() const {return body;}
|
||||
|
||||
// Class PartInstance
|
||||
void setOwner(IMoving* set);
|
||||
IMoving* getOwner() const {return myOwner;}
|
||||
|
||||
// Access Mechanism Root
|
||||
Primitive* getMechRoot();
|
||||
|
||||
// Access Root Moving Primitive
|
||||
Primitive* getRootMovingPrimitive();
|
||||
|
||||
// Find if current primitive is Ancestor of Primitive
|
||||
bool isAncestorOf(Primitive* prim);
|
||||
|
||||
// Network
|
||||
const RBX::SystemAddress getNetworkOwner() const {return networkOwner;}
|
||||
void setNetworkOwner(const RBX::SystemAddress value) {networkOwner = value;}
|
||||
|
||||
const NetworkOwnership getNetworkOwnershipRuleInternal() const { return networkOwnershipRule; }
|
||||
void setNetworkOwnershipRuleInternal(NetworkOwnership value) { networkOwnershipRule = value; }
|
||||
|
||||
bool getNetworkIsSleeping() const {return networkIsSleeping;}
|
||||
void setNetworkIsSleeping(bool value, Time wakeupNow);
|
||||
|
||||
///////////////////////////////////////////////
|
||||
//
|
||||
static void onNewOverlap(Primitive* p0, Primitive* p1);
|
||||
static void onStopOverlap(Primitive* p0, Primitive* p1);
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// Properties
|
||||
//
|
||||
// Position
|
||||
const PV& getPV() const;
|
||||
const CoordinateFrame& getCoordinateFrame() const;
|
||||
const CoordinateFrame& getCoordinateFrameUnsafe(); // Faster: Thread must hold writer lock.
|
||||
|
||||
void setCoordinateFrame(const CoordinateFrame& cFrame);
|
||||
void setPV(const PV& newPv);
|
||||
|
||||
// Velocity
|
||||
void setVelocity(const Velocity& vel);
|
||||
void zeroVelocity(); // doesn't tickle primitive
|
||||
|
||||
// Mass
|
||||
void setMassInertia(float mass);
|
||||
|
||||
// Density/Specific Gravity
|
||||
void setSpecificGravity(float value);
|
||||
float getSpecificGravity() const { return specificGravity; }
|
||||
|
||||
// Dragging
|
||||
void setDragging(bool value);
|
||||
bool getDragging() const {return dragging;}
|
||||
|
||||
// Anchored
|
||||
void setAnchoredProperty(bool value);
|
||||
bool getAnchoredProperty() const {return anchoredProperty;}
|
||||
|
||||
void updateMassValues(bool physicalPropertiesEnabled);
|
||||
float getCalculateMass(bool physicalPropertiesEnabled);
|
||||
|
||||
// EngineType
|
||||
void setEngineType(EngineType value);
|
||||
EngineType getEngineType() const {return engineType;}
|
||||
|
||||
// Fixed
|
||||
bool requestFixed() const {return (dragging || anchoredProperty);}
|
||||
|
||||
// Collide
|
||||
void setPreventCollide(bool _preventCollide);
|
||||
bool getPreventCollide() const {return preventCollide;}
|
||||
|
||||
bool getCanCollide() const {return !dragging && !preventCollide;}
|
||||
|
||||
// CanThrottle
|
||||
void setCanThrottle(bool value);
|
||||
bool getCanThrottle() const;
|
||||
|
||||
// PartMaterial
|
||||
void setPartMaterial(PartMaterial _material);
|
||||
PartMaterial getPartMaterial() const { return material; }
|
||||
|
||||
// Friction
|
||||
void setFriction(float _friction);
|
||||
float getFriction() const {return friction;}
|
||||
|
||||
// Elasticity
|
||||
void setElasticity(float elasticity);
|
||||
float getElasticity() const {return elasticity;}
|
||||
|
||||
void setPhysicalProperties(const PhysicalProperties& _physProp);
|
||||
const PhysicalProperties& getPhysicalProperties() const { return customPhysicalProperties; }
|
||||
|
||||
// Buouyancy
|
||||
void onBuoyancyChanged( bool value );
|
||||
|
||||
// Parameters
|
||||
void setGeometryParameter(const std::string& parameter, int value);
|
||||
int getGeometryParameter(const std::string& parameter) const;
|
||||
|
||||
// Size and Extents - local
|
||||
void setSize(const G3D::Vector3& size);
|
||||
const Vector3& getSize() const {return geometry->getSize();}
|
||||
|
||||
virtual float getRadius() const {return geometry->getRadius();}
|
||||
|
||||
float getPlanarSize() const {return Math::planarSize(getSize());}
|
||||
|
||||
Extents getExtentsLocal() const {
|
||||
Vector3 halfSize = geometry->getSize() * 0.5;
|
||||
return Extents(-halfSize, halfSize);
|
||||
}
|
||||
|
||||
// World
|
||||
Extents getExtentsWorld() const {
|
||||
Extents local = getExtentsLocal();
|
||||
return local.toWorldSpace(getCoordinateFrame());
|
||||
}
|
||||
|
||||
const Extents& getFastFuzzyExtentsNoCompute() {
|
||||
RBXASSERT_VERY_FAST(computeFuzzyExtents() == fuzzyExtents);
|
||||
return fuzzyExtents;
|
||||
}
|
||||
|
||||
const Extents& getFastFuzzyExtents();
|
||||
|
||||
static float squaredDistance(const Primitive& p0, const Primitive& p1)
|
||||
{
|
||||
return (p0.getCoordinateFrame().translation - p1.getCoordinateFrame().translation).squaredMagnitude();
|
||||
}
|
||||
|
||||
static bool aaBoxCollide(Primitive& p0, Primitive& p1)
|
||||
{
|
||||
return ( Extents::overlapsOrTouches( p0.getFastFuzzyExtents(),
|
||||
p1.getFastFuzzyExtents()) );
|
||||
}
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
||||
bool hitTest(const RbxRay& worldRay, Vector3& worldHitPoint, Vector3& surfaceNormal);
|
||||
|
||||
Face getFaceInObject(NormalId objectFace) const;
|
||||
Face getFaceInWorld(NormalId objectFace);
|
||||
|
||||
CoordinateFrame getFaceCoordInObject(NormalId objectFace) const;
|
||||
|
||||
void setSurfaceType(NormalId id, SurfaceType newSurfaceType);
|
||||
SurfaceType getSurfaceType(NormalId id) const {return surfaceType[id];}
|
||||
|
||||
void setSurfaceData(NormalId id, const SurfaceData& newSurfaceData);
|
||||
SurfaceData getSurfaceData(NormalId id) {
|
||||
return surfaceData ? surfaceData[id] : SurfaceData::empty();
|
||||
}
|
||||
const SurfaceData& getConstSurfaceData(NormalId id) const {
|
||||
return surfaceData ? surfaceData[id] : SurfaceData::empty();
|
||||
}
|
||||
|
||||
bool isGeometryOrthogonal( void ) const;
|
||||
|
||||
bool computeIsGrounded( void ) const;
|
||||
|
||||
|
||||
// JointK and Friction and Elasticity
|
||||
float getJointK();
|
||||
|
||||
/////////////////////////////////////
|
||||
// Global Primitive Stuff
|
||||
static float defaultElasticity() {return 0.75;}
|
||||
static float defaultFriction() {return 0.0;}
|
||||
|
||||
private:
|
||||
class RigidJoint* getFirstRigidAt(Joint* start);
|
||||
|
||||
public:
|
||||
///////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Creating and breaking joints
|
||||
|
||||
static void insertEdge(Edge* e);
|
||||
static void removeEdge(Edge* e);
|
||||
|
||||
bool hasAutoJoints() const;
|
||||
|
||||
bool hasEdge() {return ((joints.size() >0) || (contacts.size() > 0));}
|
||||
int getNumEdges() const {return joints.size() + contacts.size();}
|
||||
Edge* getFirstEdge() const;
|
||||
Edge* getNextEdge(Edge* e) const;
|
||||
|
||||
int getNumJoints() const {return joints.size();}
|
||||
Joint* getFirstJoint();
|
||||
Joint* getNextJoint(Joint* prev);
|
||||
const Joint* getConstFirstJoint() const;
|
||||
const Joint* getConstNextJoint(const Joint* prev) const;
|
||||
Joint* getJoint(int id);
|
||||
const Joint* getConstJoint(int id) const;
|
||||
Primitive* getJointOther(int id) {return joints.getOther(id);}
|
||||
|
||||
int getNumContacts() const {return contacts.size();}
|
||||
|
||||
Contact* getFirstContact();
|
||||
static const bool hasGetFirstContact = true; // this is to simulate __if_exists(getFirstContact) EL
|
||||
|
||||
Contact* getNextContact(Contact* prev);
|
||||
Contact* getContact(int id);
|
||||
Primitive* getContactOther(int id) {return contacts.getOther(id);}
|
||||
|
||||
RigidJoint* getFirstRigid();
|
||||
RigidJoint* getNextRigid(RigidJoint* prev);
|
||||
|
||||
static Joint* getJoint(Primitive* p0, Primitive* p1, int index = 0);
|
||||
static Contact* getContact(Primitive* p0, Primitive* p1);
|
||||
|
||||
static Primitive* downstreamPrimitive(Joint* j);
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// SpanningNode
|
||||
private:
|
||||
SpanningEdge* nextSpanningEdgeFromJoint(Joint* j);
|
||||
|
||||
/*override*/ SpanningEdge* getFirstSpanningEdge();
|
||||
/*override*/ SpanningEdge* getNextSpanningEdge(SpanningEdge* edge);
|
||||
|
||||
private:
|
||||
World* world;
|
||||
Geometry* geometry;
|
||||
Body* body;
|
||||
IMoving* myOwner; // forward declared outside of engine
|
||||
|
||||
EdgeList contacts;
|
||||
EdgeList joints;
|
||||
|
||||
SystemAddress networkOwner;
|
||||
|
||||
Guid guid; // used for tree stuff
|
||||
|
||||
unsigned int sortSize; // cached size value used for joint sorting
|
||||
|
||||
int worldIndex; // For fast removal from the world primitives list
|
||||
|
||||
Extents fuzzyExtents;
|
||||
unsigned int fuzzyExtentsStateId;
|
||||
|
||||
float specificGravity;
|
||||
float jointK;
|
||||
|
||||
float friction;
|
||||
float elasticity;
|
||||
|
||||
boost::flyweight<PhysicalProperties> customPhysicalProperties;
|
||||
|
||||
CompactEnum<PartMaterial, uint16_t> material;
|
||||
|
||||
// FIXED == (anchored || dragging);
|
||||
bool dragging; // replicated
|
||||
bool anchoredProperty; // replicated
|
||||
bool preventCollide; // if dragging -> no collide
|
||||
|
||||
bool networkIsSleeping;
|
||||
bool jointKDirty;
|
||||
|
||||
CompactEnum<NetworkOwnership, uint8_t> networkOwnershipRule;
|
||||
|
||||
CompactEnum<EngineType, uint8_t> engineType;
|
||||
CompactEnum<SizeMultiplier, uint8_t> sizeMultiplier; // tree stuff - overrides size/guid
|
||||
|
||||
CompactEnum<SurfaceType, uint8_t> surfaceType[6]; // for joints....
|
||||
SurfaceData* surfaceData;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
Utility class - holds Prism Meshes of same size, and parametric shape for use by Geometry Pool.
|
||||
*/
|
||||
|
||||
#include "Util/Memory.h"
|
||||
#include "V8World/Mesh.h"
|
||||
|
||||
|
||||
namespace RBX {
|
||||
|
||||
namespace POLY {
|
||||
|
||||
class PrismMesh : public Allocator<PrismMesh>
|
||||
{
|
||||
private:
|
||||
Mesh mesh;
|
||||
int NumSides;
|
||||
int NumSlices;
|
||||
Vector3 LocalCofM;
|
||||
|
||||
public:
|
||||
PrismMesh(const Vector3_2Ints& params)
|
||||
{
|
||||
// the zero sides and slices will cause immediate bail out of mesh builder for speed.
|
||||
LocalCofM = Vector3::zero();
|
||||
mesh.makePrism(params, LocalCofM);
|
||||
}
|
||||
const Mesh* getMesh() const {return &mesh;}
|
||||
void SetNumSides( int num ) {NumSides = num;}
|
||||
void SetNumSlices( int num ) {NumSlices = num;}
|
||||
const Vector3& GetLocalCofMFromMesh() const { return LocalCofM; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace POLY
|
||||
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include "V8World/Poly.h"
|
||||
#include "V8World/GeometryPool.h"
|
||||
#include "V8World/PrismMesh.h"
|
||||
#include "V8World/BlockMesh.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class PrismPoly : public Poly {
|
||||
private:
|
||||
typedef GeometryPool<Vector3_2Ints, POLY::PrismMesh, Vector3_2IntsComparer> PrismMeshPool;
|
||||
PrismMeshPool::Token prismMesh;
|
||||
|
||||
int numSides;
|
||||
int numSlices;
|
||||
|
||||
void setNumSides( int num );
|
||||
void setNumSlices( int num );
|
||||
/*override*/ bool isGeometryOrthogonal( void ) const { return false; }
|
||||
|
||||
protected:
|
||||
// Geometry Overrides
|
||||
/*override*/ virtual GeometryType getGeometryType() const {return GEOMETRY_PRISM;}
|
||||
/*override*/ void setGeometryParameter(const std::string& parameter, int value);
|
||||
/*override*/ int getGeometryParameter(const std::string& parameter) const;
|
||||
|
||||
/*override*/ Matrix3 getMoment(float mass) const;
|
||||
/*override*/ Vector3 getCofmOffset() const;
|
||||
/*override*/ CoordinateFrame getSurfaceCoordInBody( const size_t surfaceId ) const;
|
||||
/*override*/ size_t getFaceFromLegacyNormalId( const NormalId nId ) const;
|
||||
|
||||
// Poly Overrides
|
||||
/*override*/ void buildMesh();
|
||||
|
||||
public:
|
||||
PrismPoly() : numSides(0), numSlices(0)
|
||||
{}
|
||||
|
||||
/*override*/ bool setUpBulletCollisionData(void) { return false; }
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
Utility class - holds Pyramid Meshes of same size, and parametric shape for use by Geometry Pool.
|
||||
*/
|
||||
|
||||
#include "Util/Memory.h"
|
||||
#include "V8World/Mesh.h"
|
||||
|
||||
|
||||
namespace RBX {
|
||||
|
||||
namespace POLY {
|
||||
|
||||
class PyramidMesh : public Allocator<PyramidMesh>
|
||||
{
|
||||
private:
|
||||
Mesh mesh;
|
||||
int NumSides;
|
||||
int NumSlices;
|
||||
Vector3 LocalCofM;
|
||||
|
||||
public:
|
||||
PyramidMesh(const Vector3_2Ints& params)
|
||||
{
|
||||
// the zero sides and slices will cause immediate bail out of mesh builder for speed.
|
||||
LocalCofM = Vector3::zero();
|
||||
mesh.makePyramid(params, LocalCofM);
|
||||
}
|
||||
const Mesh* getMesh() const {return &mesh;}
|
||||
void SetNumSides( int num ) {NumSides = num;}
|
||||
void SetNumSlices( int num ) {NumSlices = num;}
|
||||
const Vector3& GetLocalCofMFromMesh() const { return LocalCofM; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace POLY
|
||||
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include "V8World/Poly.h"
|
||||
#include "V8World/GeometryPool.h"
|
||||
#include "V8World/PyramidMesh.h"
|
||||
#include "V8World/BlockMesh.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class PyramidPoly : public Poly {
|
||||
private:
|
||||
typedef GeometryPool<Vector3_2Ints, POLY::PyramidMesh, Vector3_2IntsComparer> PyramidMeshPool;
|
||||
PyramidMeshPool::Token pyramidMesh;
|
||||
|
||||
int numSides;
|
||||
int numSlices;
|
||||
|
||||
void setNumSides( int num );
|
||||
void setNumSlices( int num );
|
||||
/*override*/ bool isGeometryOrthogonal( void ) const { return false; }
|
||||
|
||||
protected:
|
||||
// Geometry Overrides
|
||||
/*override*/ GeometryType getGeometryType() const {return GEOMETRY_PYRAMID;}
|
||||
/*override*/ void setGeometryParameter(const std::string& parameter, int value);
|
||||
/*override*/ int getGeometryParameter(const std::string& parameter) const;
|
||||
|
||||
/*override*/ Matrix3 getMoment(float mass) const;
|
||||
/*override*/ Vector3 getCofmOffset() const;
|
||||
/*override*/ CoordinateFrame getSurfaceCoordInBody( const size_t surfaceId ) const;
|
||||
size_t getFaceFromLegacyNormalId( const NormalId nId ) const;
|
||||
|
||||
// Poly Overrides
|
||||
/*override*/ void buildMesh();
|
||||
|
||||
public:
|
||||
PyramidPoly() : numSides(0), numSlices(0)
|
||||
{}
|
||||
|
||||
/*override*/ bool setUpBulletCollisionData(void) { return false; }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
Utility class - holds RightAngleRamp Meshes of same size for use by Geometry Pool.
|
||||
*/
|
||||
|
||||
#include "Util/Memory.h"
|
||||
#include "V8World/Mesh.h"
|
||||
|
||||
|
||||
namespace RBX {
|
||||
|
||||
namespace POLY {
|
||||
|
||||
class RightAngleRampMesh : public Allocator<RightAngleRampMesh>
|
||||
{
|
||||
private:
|
||||
Mesh mesh;
|
||||
Vector3 LocalCofM;
|
||||
|
||||
public:
|
||||
RightAngleRampMesh(const Vector3& size)
|
||||
{
|
||||
mesh.makeRightAngleRamp(size, LocalCofM);
|
||||
}
|
||||
const Mesh* getMesh() const {return &mesh;}
|
||||
const Vector3& GetLocalCofMFromMesh() const { return LocalCofM; }
|
||||
};
|
||||
|
||||
} // namespace POLY
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include "V8World/Poly.h"
|
||||
#include "V8World/GeometryPool.h"
|
||||
#include "V8World/RightAngleRampMesh.h"
|
||||
#include "V8World/BlockMesh.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class RightAngleRampPoly : public Poly {
|
||||
public:
|
||||
typedef GeometryPool<Vector3, POLY::RightAngleRampMesh, Vector3Comparer> RightAngleRampMeshPool;
|
||||
|
||||
/*override*/ Matrix3 getMoment(float mass) const;
|
||||
/*override*/ Vector3 getCofmOffset() const;
|
||||
/*override*/ bool isGeometryOrthogonal( void ) const { return false; }
|
||||
/*override*/ bool setUpBulletCollisionData(void) { return false; }
|
||||
|
||||
private:
|
||||
RightAngleRampMeshPool::Token aRightAngleRampMesh;
|
||||
|
||||
protected:
|
||||
// Geometry Overrides
|
||||
/*override*/ virtual GeometryType getGeometryType() const {return GEOMETRY_RIGHTANGLERAMP;}
|
||||
|
||||
// Poly Overrides
|
||||
/*override*/ void buildMesh();
|
||||
/*override*/ size_t getFaceFromLegacyNormalId( const NormalId nId ) const;
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include "V8World/Joint.h"
|
||||
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class RigidJoint : public Joint
|
||||
{
|
||||
private:
|
||||
///////////////////////////////////////////////////
|
||||
// Joint
|
||||
/*override*/ virtual JointType getJointType() const {RBXASSERT(0); return Joint::NO_JOINT;}
|
||||
/*override*/ virtual bool isBroken() const {return false;}
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// KinematicJoint
|
||||
// TODO: This assumes two function (one virtual) calls are way better than a dynamic cast?...
|
||||
static bool jointIsRigid(Joint* j) {
|
||||
JointType jt = j->getJointType();
|
||||
return ((jt == Joint::WELD_JOINT) || (jt == Joint::SNAP_JOINT) || (jt == Joint::MANUAL_WELD_JOINT));
|
||||
}
|
||||
|
||||
protected:
|
||||
static void faceIdToCoords(
|
||||
Primitive* p0,
|
||||
Primitive* p1,
|
||||
NormalId nId0,
|
||||
NormalId nId1,
|
||||
CoordinateFrame& c0,
|
||||
CoordinateFrame& c1);
|
||||
|
||||
public:
|
||||
RigidJoint()
|
||||
{}
|
||||
|
||||
RigidJoint(
|
||||
Primitive* prim0,
|
||||
Primitive* prim1,
|
||||
const CoordinateFrame& c0,
|
||||
const CoordinateFrame &c1)
|
||||
: Joint(prim0, prim1, c0, c1)
|
||||
{}
|
||||
|
||||
~RigidJoint() {}
|
||||
|
||||
/*override*/ bool isAligned();
|
||||
|
||||
/*override*/ CoordinateFrame align(Primitive* pMove, Primitive* pStay);
|
||||
|
||||
CoordinateFrame getChildInParent(Primitive* parent, Primitive* child);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/MultiJoint.h"
|
||||
#include "Util/NormalId.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class RotateConnector;
|
||||
class ConstraintAlign2Axes;
|
||||
class ConstraintBallInSocket;
|
||||
class ConstraintAngularVelocity;
|
||||
class Constraint;
|
||||
|
||||
class RotateJoint : public MultiJoint
|
||||
{
|
||||
private:
|
||||
typedef MultiJoint Super;
|
||||
static RotateJoint* surfaceTypeToJoint(
|
||||
SurfaceType surfaceType,
|
||||
Primitive* axlePrim,
|
||||
Primitive* holePrim,
|
||||
const CoordinateFrame& c0,
|
||||
const CoordinateFrame& c1);
|
||||
|
||||
|
||||
void update();
|
||||
|
||||
protected:
|
||||
typedef enum {AXLE_ID = 0, HOLE_ID} AxleHoleId;
|
||||
|
||||
// Edge
|
||||
/*override*/ void putInKernel(Kernel* kernel);
|
||||
/*override*/ void removeFromKernel();
|
||||
/*override*/ JointType getJointType() const {return Joint::ROTATE_JOINT;}
|
||||
|
||||
void getPrimitivesTorqueArmLength(float& axleArmLength, float& holeArmLength);
|
||||
|
||||
ConstraintAlign2Axes* align2Axes;
|
||||
ConstraintBallInSocket* ballInSocket;
|
||||
|
||||
public:
|
||||
RotateJoint();
|
||||
|
||||
RotateJoint(
|
||||
Primitive* axlePrim,
|
||||
Primitive* holePrim,
|
||||
const CoordinateFrame& c0,
|
||||
const CoordinateFrame& c1);
|
||||
|
||||
virtual ~RotateJoint();
|
||||
|
||||
static RotateJoint* canBuildJoint(
|
||||
Primitive* p0,
|
||||
Primitive* p1,
|
||||
NormalId nId0,
|
||||
NormalId nId1);
|
||||
|
||||
Primitive* getAxlePrim() {return getPrimitive(AXLE_ID);}
|
||||
Primitive* getHolePrim() {return getPrimitive(HOLE_ID);}
|
||||
|
||||
NormalId getAxleId() {return getNormalId(AXLE_ID);}
|
||||
NormalId getHoleId() {return getNormalId(HOLE_ID);}
|
||||
|
||||
Vector3 getAxleWorldDirection();
|
||||
|
||||
float getAxleVelocity();
|
||||
};
|
||||
|
||||
class DynamicRotateJoint : public RotateJoint
|
||||
{
|
||||
private:
|
||||
typedef RotateJoint Super;
|
||||
/*override*/ bool canStepWorld() const {return true;}
|
||||
/*override*/ bool canStepUi() const {return true;}
|
||||
|
||||
/*override*/ bool stepUi(double distributedGameTime);
|
||||
/*override*/ void setPhysics(); // occurs after networking read;
|
||||
|
||||
|
||||
float getChannelValue(double distributedGameTime);
|
||||
|
||||
protected:
|
||||
// Edge
|
||||
/*override*/ void putInKernel(Kernel* kernel);
|
||||
/*override*/ void removeFromKernel();
|
||||
|
||||
float baseAngle; // what is the initial assembled rotation angle
|
||||
RotateConnector* rotateConnector; // here when in kernel
|
||||
float uiValue;
|
||||
|
||||
public:
|
||||
DynamicRotateJoint() : uiValue(0.0f), rotateConnector(NULL)
|
||||
{}
|
||||
|
||||
DynamicRotateJoint(
|
||||
Primitive* axlePrim,
|
||||
Primitive* holePrim,
|
||||
const CoordinateFrame& c0,
|
||||
const CoordinateFrame& c1,
|
||||
float baseAngle);
|
||||
|
||||
~DynamicRotateJoint();
|
||||
|
||||
float getBaseAngle() const {
|
||||
return baseAngle;
|
||||
}
|
||||
|
||||
float getTorqueArmLength();
|
||||
|
||||
void setBaseAngle(float value);
|
||||
};
|
||||
|
||||
class RotatePJoint : public DynamicRotateJoint
|
||||
{
|
||||
private:
|
||||
// Joint
|
||||
/*override*/ JointType getJointType() const {return Joint::ROTATE_P_JOINT;}
|
||||
|
||||
/*override*/ void stepWorld();
|
||||
|
||||
/*override*/ void putInKernel(Kernel* kernel);
|
||||
/*override*/ void removeFromKernel();
|
||||
|
||||
float currentAngle;
|
||||
ConstraintAlign2Axes* alignmentConstraint;
|
||||
public:
|
||||
RotatePJoint(): currentAngle( 0.0f ), alignmentConstraint(NULL)
|
||||
{}
|
||||
|
||||
RotatePJoint(
|
||||
Primitive* axlePrim,
|
||||
Primitive* holePrim,
|
||||
const CoordinateFrame& c0,
|
||||
const CoordinateFrame& c1,
|
||||
float baseAngle)
|
||||
: DynamicRotateJoint(axlePrim, holePrim, c0, c1, baseAngle), currentAngle( 0.0f ), alignmentConstraint(NULL)
|
||||
{}
|
||||
|
||||
~RotatePJoint();
|
||||
};
|
||||
|
||||
class RotateVJoint : public DynamicRotateJoint
|
||||
{
|
||||
private:
|
||||
// Joint
|
||||
/*override*/ JointType getJointType() const {return Joint::ROTATE_V_JOINT;}
|
||||
|
||||
/*override*/ void stepWorld();
|
||||
|
||||
/*override*/ void putInKernel(Kernel* kernel);
|
||||
/*override*/ void removeFromKernel();
|
||||
|
||||
ConstraintAngularVelocity* angularVelocityConstraint;
|
||||
|
||||
public:
|
||||
RotateVJoint(): angularVelocityConstraint( NULL )
|
||||
{}
|
||||
|
||||
RotateVJoint(
|
||||
Primitive* axlePrim,
|
||||
Primitive* holePrim,
|
||||
const CoordinateFrame& c0,
|
||||
const CoordinateFrame& c1,
|
||||
float baseAngle);
|
||||
|
||||
~RotateVJoint();
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,97 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/IWorldStage.h"
|
||||
#include "V8World/SimJob.h"
|
||||
#include "rbx/signal.h"
|
||||
#include "Util/ConcurrencyValidator.h"
|
||||
#include "rbx/threadsafe.h"
|
||||
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Edge;
|
||||
class Kernel;
|
||||
class Assembly;
|
||||
|
||||
class SendPhysics
|
||||
{
|
||||
private:
|
||||
SimJobList simJobs;
|
||||
|
||||
ConcurrencyValidator concurrencyValidator;
|
||||
|
||||
void buildSimJob(SimJob* job);
|
||||
void destroySimJob(SimJob* job);
|
||||
mutable rbx::spin_mutex changeTrackerMutex;
|
||||
|
||||
void setTrackerSimJob(SimJobTracker& tracker, SimJob* simJob) const
|
||||
{
|
||||
rbx::spin_mutex::scoped_lock lock(changeTrackerMutex);
|
||||
tracker.setSimJob(simJob);
|
||||
}
|
||||
|
||||
public:
|
||||
rbx::signal<void(Primitive*)> assemblyPhysicsOnSignal;
|
||||
rbx::signal<void(Primitive*)> assemblyPhysicsOffSignal;
|
||||
|
||||
SimJob* nextSimJob(SimJob* current)
|
||||
{
|
||||
RBXASSERT(!simJobs.empty());
|
||||
SimJobList::iterator iter = simJobs.iterator_to(*current);
|
||||
++iter;
|
||||
return (iter == simJobs.end()) ? &simJobs.front() : &*iter;
|
||||
}
|
||||
|
||||
template<class Callback>
|
||||
int reportSimJobs(Callback& callback, SimJobTracker& tracker, const SimJob* ignore, int numToReport = -1)
|
||||
{
|
||||
int reported = 0;
|
||||
|
||||
ReadOnlyValidator readOnlyValidator(concurrencyValidator);
|
||||
{
|
||||
if (simJobs.empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!tracker.tracking()) {
|
||||
setTrackerSimJob(tracker, &simJobs.front());
|
||||
}
|
||||
|
||||
SimJob* simJob = tracker.getSimJob();
|
||||
int num = numToReport;
|
||||
if (num == -1)
|
||||
num = simJobs.size();
|
||||
|
||||
while (reported < num)
|
||||
{
|
||||
SimJob* current = simJob;
|
||||
++reported;
|
||||
simJob = nextSimJob(simJob);
|
||||
|
||||
if (current != ignore)
|
||||
{
|
||||
if (!callback(*current)) // returns true if wants another sample (m is always used)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
setTrackerSimJob(tracker, simJob);
|
||||
}
|
||||
|
||||
return reported;
|
||||
}
|
||||
|
||||
SendPhysics();
|
||||
|
||||
~SendPhysics();
|
||||
|
||||
int getNumSimJobs() { return simJobs.size(); };
|
||||
|
||||
void onMovingAssemblyRootAdded(Assembly* assembly);
|
||||
void onMovingAssemblyRootRemoving(Assembly* assembly);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,67 @@
|
||||
/* Copyright 2003-2006 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "boost/utility.hpp"
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include "boost/intrusive/list.hpp"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Primitive;
|
||||
class Assembly;
|
||||
class SimJob;
|
||||
|
||||
typedef boost::intrusive::list_base_hook< boost::intrusive::tag<SimJob> > SimJobHook;
|
||||
typedef boost::intrusive::list<SimJob, boost::intrusive::base_hook<SimJobHook> > SimJobList;
|
||||
|
||||
class SimJobTracker
|
||||
{
|
||||
private:
|
||||
SimJob* simJob;
|
||||
|
||||
bool containedBy(SimJob* s);
|
||||
void stopTracking();
|
||||
public:
|
||||
SimJobTracker() : simJob(NULL) {}
|
||||
|
||||
~SimJobTracker() {
|
||||
stopTracking();
|
||||
}
|
||||
|
||||
bool tracking();
|
||||
|
||||
void setSimJob(SimJob* s);
|
||||
|
||||
SimJob* getSimJob();
|
||||
|
||||
static void transferTrackers(SimJob* from, SimJob* to);
|
||||
};
|
||||
|
||||
class SimJob
|
||||
: public boost::noncopyable
|
||||
, public SimJobHook
|
||||
{
|
||||
friend class SimJobTracker;
|
||||
|
||||
private:
|
||||
std::vector<SimJobTracker*> trackers; // this will usually be empty, or have one tracker
|
||||
Assembly* assembly;
|
||||
|
||||
public:
|
||||
int useCount;
|
||||
|
||||
SimJob(Assembly* _assembly);
|
||||
|
||||
~SimJob();
|
||||
|
||||
Assembly* getAssembly() {return assembly;}
|
||||
const Assembly* getConstAssembly() const {return assembly;}
|
||||
|
||||
static SimJob* getSimJobFromPrimitive(Primitive* primitive);
|
||||
static const SimJob* getConstSimJobFromPrimitive(const Primitive* primitive);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,63 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
// Note - used to be called "SimJobStage.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/IWorldStage.h"
|
||||
#include "V8World/Assembly.h"
|
||||
#include <map>
|
||||
#include "boost/intrusive/list.hpp"
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class SimulateStage : public IWorldStage
|
||||
{
|
||||
public:
|
||||
typedef boost::intrusive::list<Assembly, boost::intrusive::base_hook<SimulateStageHook> > Assemblies;
|
||||
|
||||
private:
|
||||
#if 0
|
||||
typedef boost::unordered_map<Assembly*, int> AssemblyMap;
|
||||
#else
|
||||
typedef std::map<Assembly*, int> AssemblyMap;
|
||||
#endif
|
||||
AssemblyMap movingAssemblyRoots;
|
||||
|
||||
Assemblies movingDynamicAssemblies;
|
||||
Assemblies realTimeAssemblies;
|
||||
|
||||
bool validateEdge(Edge* e);
|
||||
|
||||
void putFirstMovingRootInSendPhysics(Assembly* a);
|
||||
void removeLastMovingRootFromSendPhysics(Assembly* a);
|
||||
bool removeFromSendPhysics(Assembly* a);
|
||||
|
||||
public:
|
||||
SimulateStage(IStage* upstream, World* world);
|
||||
|
||||
~SimulateStage();
|
||||
|
||||
/*override*/ IStage::StageType getStageType() const {return IStage::SIMULATE_STAGE;}
|
||||
|
||||
/*override*/ void onEdgeAdded(Edge* e);
|
||||
/*override*/ void onEdgeRemoving(Edge* e);
|
||||
|
||||
void onAssemblyAdded(Assembly* assembly);
|
||||
void onAssemblyRemoving(Assembly* assembly);
|
||||
|
||||
int getMovingDynamicAssembliesSize() { return movingDynamicAssemblies.size(); }
|
||||
Assemblies::iterator getMovingDynamicAssembliesBegin() {
|
||||
return movingDynamicAssemblies.begin();
|
||||
}
|
||||
Assemblies::iterator getMovingDynamicAssembliesEnd() {
|
||||
return movingDynamicAssemblies.end();
|
||||
}
|
||||
Assemblies::iterator getRealTimeAssembliesBegin() {
|
||||
return realTimeAssemblies.begin();
|
||||
}
|
||||
Assemblies::iterator getRealtimeAssembliesEnd() {
|
||||
return realTimeAssemblies.end();
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
@@ -0,0 +1,169 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/IWorldStage.h"
|
||||
#include "V8World/Enum.h"
|
||||
#include "V8World/Contact.h"
|
||||
#include "Util/IndexArray.h"
|
||||
#include "Util/G3DCore.h"
|
||||
#include "boost/scoped_ptr.hpp"
|
||||
#include "Util/RunningAverage.h"
|
||||
#include <set>
|
||||
#include <deque>
|
||||
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Assembly;
|
||||
class Edge;
|
||||
class Joint;
|
||||
class Contact;
|
||||
class Kernel;
|
||||
class SleepStage;
|
||||
|
||||
namespace Profiling
|
||||
{
|
||||
class CodeProfiler;
|
||||
}
|
||||
|
||||
|
||||
class SleepStage : public IWorldStage {
|
||||
public:
|
||||
typedef std::set<Assembly*> AssemblySet;
|
||||
typedef std::set<Joint*> JointSet;
|
||||
private:
|
||||
typedef IWorldStage Super;
|
||||
// utility - prevent extra allocs on resize
|
||||
std::vector<Assembly*> toDeep;
|
||||
std::vector<Assembly*> toWake;
|
||||
std::vector<Assembly*> toSleepingChecking;
|
||||
std::vector<Contact*> toSleeping;
|
||||
std::vector<Contact*> toStepping;
|
||||
std::vector<Contact*> toContacting;
|
||||
std::vector<Contact*> toContactingSleeping;
|
||||
std::vector<Joint*> toSleepingJoint;
|
||||
|
||||
int numContactsInStage;
|
||||
int numContactsInKernel;
|
||||
bool throttling;
|
||||
bool debugReentrant;
|
||||
int longStepId;
|
||||
|
||||
typedef AssemblySet::iterator AssemblySetIt;
|
||||
typedef AssemblySet::const_iterator CAssemblySetIt;
|
||||
typedef IndexArray<Contact, &Contact::steppingIndexFunc> ContactList;
|
||||
typedef ContactList ContactLists[Sim::NUM_THROTTLE_TYPE];
|
||||
|
||||
// defining objects
|
||||
|
||||
AssemblySet recursiveWakePending; // only on impact...
|
||||
AssemblySet wakePending;
|
||||
AssemblySet awake;
|
||||
AssemblySet sleepingChecking; // Edges that are awake
|
||||
AssemblySet sleepingDeeply; // no Edges that are awake
|
||||
AssemblySet removing;
|
||||
ContactLists steppingContacts;
|
||||
ContactLists touchingContacts;
|
||||
JointSet steppingJoints;
|
||||
|
||||
// Main Stepping functions
|
||||
int recursivePassId;
|
||||
bool externalRecursiveWake;
|
||||
|
||||
void stepAssembliesRecursiveWakePending();
|
||||
|
||||
void stepAssembliesWakePending();
|
||||
|
||||
void doContacts(ContactLists& contactLists);
|
||||
|
||||
void stepContacts(ContactList& contactList);
|
||||
|
||||
void stepJoints();
|
||||
|
||||
void stepAssembliesAwake();
|
||||
void stepAssembliesSleepingChecking();
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
// Supporting Stepping functions
|
||||
//
|
||||
static float highVelocityContact();
|
||||
|
||||
void wakeAssemblies(AssemblySet& wakeSet, int maxDepth, Sim::AssemblyState checkState);
|
||||
void traverse(Assembly* assembly, std::deque<Assembly*>& aDeque, int maxDepth);
|
||||
|
||||
void wakeEdge(Edge* e);
|
||||
|
||||
Sim::EdgeState computeContactState(bool assembliesMoving, bool inContact, bool canCollide, bool wasTouching);
|
||||
|
||||
bool highVelocityNewTouch(Contact* c);
|
||||
|
||||
void wakeEvent(Edge* e);
|
||||
void recursiveWakeEvent(Contact* c);
|
||||
void wakeEvent(Assembly* a);
|
||||
void recursiveWakeEvent(Assembly* a);
|
||||
|
||||
void changeContactState(const std::vector<Contact*>& contacts, Sim::EdgeState newState);
|
||||
void changeJointState(const std::vector<Joint*>& joints, Sim::EdgeState newState);
|
||||
void changeAssemblyState(const std::vector<Assembly*>& assemblies, Sim::AssemblyState newState);
|
||||
|
||||
void changeContactState(Contact* c, Sim::EdgeState newState);
|
||||
void changeJointState(Joint* j, Sim::EdgeState newState);
|
||||
void changeAssemblyState(Assembly* a, Sim::AssemblyState newState);
|
||||
|
||||
AssemblySet& stateToSet(Sim::AssemblyState state);
|
||||
|
||||
bool edgeIsAwake(Edge* e);
|
||||
bool isAffecting(Edge* e);
|
||||
|
||||
bool atLeastOneAssemblyMoving(Assembly* a0, Assembly* a1);
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Assembly functions
|
||||
|
||||
bool shouldSleep(Assembly* a);
|
||||
bool preventNeighborSleep(Assembly* a);
|
||||
|
||||
Sim::AssemblyState computeStateFromNeighbors(Assembly* a);
|
||||
|
||||
bool forceNeighborAwake(Assembly* a);
|
||||
bool movingTooMuchToSleep(Assembly* a);
|
||||
|
||||
bool validate();
|
||||
bool validateJoints();
|
||||
public:
|
||||
SleepStage(IStage* upstream, World* world);
|
||||
|
||||
~SleepStage();
|
||||
|
||||
|
||||
///////////////////////////////////////////
|
||||
// IStage
|
||||
/*override*/ IStage::StageType getStageType() const {return IStage::SLEEP_STAGE;}
|
||||
|
||||
/*override*/ int getMetric(IWorldStage::MetricType metricType);
|
||||
|
||||
/*override*/ void onEdgeAdded(Edge* e);
|
||||
/*override*/ void onEdgeRemoving(Edge* e);
|
||||
|
||||
void stepSleepStage(int worldStepId, int uiStepId, bool _throttling);
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// From Upstream Collision Stage, World
|
||||
void onAssemblyAdded(Assembly* a);
|
||||
void onAssemblyRemoving(Assembly* a);
|
||||
void onExternalTickleAssembly(Assembly* a, bool recursive);
|
||||
|
||||
int numTouchingContacts();
|
||||
const AssemblySet& getAwakeAssemblies() const {return awake;}
|
||||
|
||||
///////////////////////////////////////////
|
||||
// Profiler
|
||||
boost::scoped_ptr<Profiling::CodeProfiler> profilingCollision;
|
||||
boost::scoped_ptr<Profiling::CodeProfiler> profilingJointSleep;
|
||||
boost::scoped_ptr<Profiling::CodeProfiler> profilingWake;
|
||||
boost::scoped_ptr<Profiling::CodeProfiler> profilingSleep;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
#pragma once
|
||||
|
||||
#include "V8World/Geometry.h"
|
||||
#include "V8World/Primitive.h"
|
||||
#include "V8World/TerrainPartition.h"
|
||||
#include "Util/PartMaterial.h"
|
||||
|
||||
class btConvexHullShape;
|
||||
struct btDbvt;
|
||||
|
||||
namespace RBX {
|
||||
|
||||
namespace Voxel2 { class Grid; }
|
||||
|
||||
class SmoothClusterGeometry: public Geometry
|
||||
{
|
||||
public:
|
||||
struct ChunkMesh;
|
||||
|
||||
SmoothClusterGeometry(Primitive* p);
|
||||
~SmoothClusterGeometry();
|
||||
|
||||
// Geometry overrides
|
||||
GeometryType getGeometryType() const override;
|
||||
CollideType getCollideType() const override;
|
||||
float getRadius() const override;
|
||||
size_t closestSurfaceToPoint(const Vector3& pointInBody) const override;
|
||||
Plane getPlaneFromSurface(const size_t surfaceId) const override;
|
||||
CoordinateFrame getSurfaceCoordInBody(const size_t surfaceId) const override;
|
||||
Vector3 getSurfaceNormalInBody(const size_t surfaceId) const override;
|
||||
size_t getMostAlignedSurface(const Vector3& vecInWorld, const G3D::Matrix3& objectR) const override;
|
||||
int getNumSurfaces() const override;
|
||||
Vector3 getSurfaceVertInBody(const size_t surfaceId, const int vertId) const override;
|
||||
int getNumVertsInSurface(const size_t surfaceId) const override;
|
||||
bool vertOverlapsFace(const Vector3& pointInBody, const size_t surfaceId) const override;
|
||||
bool findTouchingSurfacesConvex(const CoordinateFrame& myCf, size_t& myFaceId, const Geometry& otherGeom, const CoordinateFrame& otherCf, size_t& otherFaceId) const override;
|
||||
bool FacesOverlapped(const CoordinateFrame& myCf, size_t& myFaceId, const Geometry& otherGeom, const CoordinateFrame& otherCf, size_t& otherFaceId, float tol) const override;
|
||||
bool FaceVerticesOverlapped(const CoordinateFrame& myCf, size_t& myFaceId, const Geometry& otherGeom, const CoordinateFrame& otherCf, size_t& otherFaceId, float tol) const override;
|
||||
bool FaceEdgesOverlapped(const CoordinateFrame& myCf, size_t& myFaceId, const Geometry& otherGeom, const CoordinateFrame& otherCf, size_t& otherFaceId, float tol) const override;
|
||||
bool hitTest(const RbxRay& rayInMe, Vector3& localHitPoint, Vector3& surfaceNormal) override;
|
||||
bool collidesWithGroundPlane(const CoordinateFrame& c, float yHeight) const override;
|
||||
bool setUpBulletCollisionData() override;
|
||||
|
||||
bool hitTestTerrain(const RbxRay& rayInMe, Vector3& localHitPoint, int& surfId, CoordinateFrame& surfCf) override;
|
||||
|
||||
// Terrain specific API
|
||||
bool castRay(const RbxRay& rayInMe, Vector3& localHitPoint, Vector3& surfaceNormal, unsigned char& surfaceMaterial, float maxDistance, bool ignoreWater);
|
||||
bool findCellsInBoundingBox(const Vector3& min, const Vector3& max);
|
||||
|
||||
void updateChunk(const Vector3int32& id);
|
||||
void updateAllChunks();
|
||||
|
||||
void garbageCollectIncremental();
|
||||
|
||||
shared_ptr<btCollisionShape> getBulletChunkShape(const Vector3int32& id);
|
||||
TerrainPartitionSmooth* getTerrainPartition() { return partition.get(); }
|
||||
|
||||
static PartMaterial getTriangleMaterial(btCollisionShape* collisionShape, unsigned int triangleIndex, const Vector3& localHitPoint);
|
||||
|
||||
private:
|
||||
Primitive* myPrim;
|
||||
|
||||
Voxel2::Grid* grid;
|
||||
|
||||
scoped_ptr<TerrainPartitionSmooth> partition;
|
||||
|
||||
typedef boost::unordered_map<Vector3int32, ChunkMesh*> ChunkMap;
|
||||
ChunkMap bulletChunks;
|
||||
|
||||
Vector3int32 gcChunkKeyNext;
|
||||
size_t gcChunkCountLast;
|
||||
size_t gcUnusedMemory;
|
||||
size_t gcUnusedMemoryNext;
|
||||
|
||||
btDbvt* bulletChunksTree;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include "V8World/RigidJoint.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class SnapJoint : public RigidJoint
|
||||
{
|
||||
private:
|
||||
///////////////////////////////////////////////////
|
||||
// Joint
|
||||
/*override*/ virtual JointType getJointType() const {return SNAP_JOINT;}
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// WeldJoint
|
||||
static bool compatibleSurfaces(
|
||||
Primitive* p0,
|
||||
Primitive* p1,
|
||||
NormalId nId0,
|
||||
NormalId nId1);
|
||||
|
||||
public:
|
||||
SnapJoint() {}
|
||||
|
||||
SnapJoint(Primitive* prim0, Primitive* prim1, const CoordinateFrame& c0, const CoordinateFrame &c1)
|
||||
: RigidJoint(prim0, prim1, c0, c1)
|
||||
{}
|
||||
|
||||
~SnapJoint() {}
|
||||
|
||||
static SnapJoint* canBuildJoint(
|
||||
Primitive* p0,
|
||||
Primitive* p1,
|
||||
NormalId nId0,
|
||||
NormalId nId1);
|
||||
};
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/IWorldStage.h"
|
||||
#include "V8World/Assembly.h"
|
||||
#include "Util/SimSendFilter.h"
|
||||
#include "boost/scoped_ptr.hpp"
|
||||
#include <set>
|
||||
|
||||
namespace RBX {
|
||||
class Assembly;
|
||||
class Mechanism;
|
||||
class Joint;
|
||||
class Region2;
|
||||
|
||||
/*
|
||||
Simulate Physics Service (Send)
|
||||
Client NO --- doesn’t step --- NO --- doesn’t step --
|
||||
Server ALL If Sim
|
||||
Edit / Visit Solo ALL N0
|
||||
Dphysics Client: Region or Address If Sim
|
||||
Dphysics Server; Address Match (null) If Awake or Sim
|
||||
(region is empty)
|
||||
*/
|
||||
|
||||
class SpatialFilter : public IWorldStage {
|
||||
public:
|
||||
typedef std::set<Assembly*> AssemblySet;
|
||||
|
||||
bool inClientSimRegion(Assembly* a);
|
||||
bool addressMatch(Assembly* a);
|
||||
|
||||
static bool sendingPhase(Assembly::FilterPhase phase) {return (phase == Assembly::NoSim_Send) || (phase == Assembly::NoSim_Send_Anim);}
|
||||
static bool simulatingPhase(Assembly::FilterPhase phase) {return ((phase == Assembly::Sim_SendIfSim) || (phase == Assembly::Sim_BufferZone));}
|
||||
static bool noSimPhase(Assembly::FilterPhase phase) {return ((phase == Assembly::NoSim_Send) || (phase == Assembly::NoSim_Send_Anim) || (phase == Assembly::NoSim_SendIfSim) || (phase == Assembly::NoSim_SendIfSim_Anim));}
|
||||
static bool animationPhase(Assembly::FilterPhase phase) {return ((phase == Assembly::NoSim_Send_Anim) || (phase == Assembly::NoSim_SendIfSim_Anim)); }
|
||||
|
||||
private:
|
||||
|
||||
class MoveInstructions {
|
||||
public:
|
||||
Assembly* a;
|
||||
Assembly::FilterPhase from;
|
||||
Assembly::FilterPhase to;
|
||||
|
||||
MoveInstructions() : a(NULL), from(Assembly::NOT_ASSIGNED), to(Assembly::NOT_ASSIGNED)
|
||||
{}
|
||||
|
||||
MoveInstructions(Assembly* _a, Assembly::FilterPhase _from, Assembly::FilterPhase _to) : a(_a), from(_from), to(_to)
|
||||
{}
|
||||
|
||||
~MoveInstructions()
|
||||
{}
|
||||
};
|
||||
|
||||
SimSendFilter filter;
|
||||
|
||||
AssemblySet assemblies[Assembly::NUM_PHASES]; // no simulate assemblies and simulate assemblies
|
||||
|
||||
G3D::Array<MoveInstructions> toMove;
|
||||
|
||||
Assembly::FilterPhase filterAssembly(Assembly* a, bool simulating, Time wakeupNow); // when simulating, this can affect the datamodel
|
||||
|
||||
bool isNotClientAddress(Assembly* a);
|
||||
|
||||
void changePhase(MoveInstructions& mi);
|
||||
void moveInto(MoveInstructions& mi);
|
||||
void removeFromPhase(Assembly* a);
|
||||
void moveAll(Assembly::FilterPhase destination);
|
||||
|
||||
class MechToAssemblyStage* getMechToAssemblyStage();
|
||||
|
||||
void filterAssemblies();
|
||||
|
||||
void insertPrimitiveJoints(Primitive* p);
|
||||
void removePrimitiveJoints(Primitive* p);
|
||||
|
||||
public:
|
||||
///////////////////////////////////////////
|
||||
// IStage
|
||||
SpatialFilter(IStage* upstream, World* world);
|
||||
|
||||
~SpatialFilter();
|
||||
|
||||
/*override*/ IStage::StageType getStageType() const {return IStage::SPATIAL_FILTER;}
|
||||
|
||||
void filterStep();
|
||||
|
||||
void onMovingAssemblyRootAdded(Assembly* a, Time now);
|
||||
void onFixedAssemblyRootAdded(Assembly* a);
|
||||
|
||||
void onAssemblyRootRemoving(Assembly* a);
|
||||
|
||||
SimSendFilter& getSimSendFilter() {return filter;}
|
||||
|
||||
const AssemblySet& getAssemblies(Assembly::FilterPhase phase) {
|
||||
RBXASSERT(phase < Assembly::NUM_PHASES);
|
||||
return assemblies[phase];
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
@@ -0,0 +1,435 @@
|
||||
#pragma once
|
||||
|
||||
#include "V8World/BasicSpatialHashPrimitive.h"
|
||||
#include "Util/G3DCore.h"
|
||||
#include "Util/Memory.h"
|
||||
#include "Util/ConcurrencyValidator.h"
|
||||
#include "rbx/Debug.h"
|
||||
#include "rbx/object_pool.h"
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/pool/pool.hpp>
|
||||
|
||||
namespace RBX {
|
||||
|
||||
|
||||
|
||||
class World;
|
||||
class Extents;
|
||||
|
||||
class NodeBase
|
||||
{
|
||||
public:
|
||||
NodeBase(short level, int hashId, const Vector3int32& gridId)
|
||||
: level(level)
|
||||
, hashId(hashId)
|
||||
, gridId(gridId)
|
||||
{};
|
||||
NodeBase()
|
||||
: level(-1)
|
||||
, hashId(-1)
|
||||
{};
|
||||
|
||||
~NodeBase() {
|
||||
level = -2;
|
||||
hashId = -2;
|
||||
}
|
||||
|
||||
short level;
|
||||
int hashId;
|
||||
Vector3int32 gridId;
|
||||
|
||||
int getLevel() {
|
||||
RBXASSERT(level >= -1);
|
||||
return level;
|
||||
}
|
||||
};
|
||||
|
||||
enum enumAction
|
||||
{
|
||||
aRecurseTreeNode,
|
||||
aVisitSingleSpatialNode,
|
||||
aVisitAllSiblingsSpatialNodes
|
||||
};
|
||||
|
||||
struct NodeInfo
|
||||
{
|
||||
|
||||
NodeInfo(NodeBase* node, enumAction action, IntersectResult intersectResult, float distance)
|
||||
: node(node)
|
||||
, action(action)
|
||||
, intersectResult(intersectResult)
|
||||
, distance(distance)
|
||||
{};
|
||||
NodeBase* node;
|
||||
enumAction action;
|
||||
IntersectResult intersectResult;
|
||||
float distance;
|
||||
|
||||
// transform distance into priority (lower distance, higher priority == invert sign)
|
||||
bool operator < (const NodeInfo& r) const
|
||||
{
|
||||
return distance > r.distance;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class SpatialHashStatic {
|
||||
public:
|
||||
// in SpatialHashMultiRes.inl
|
||||
static const int cellMinSize;
|
||||
static const int maxLevelForAnchored;
|
||||
inline static float hashGridSize(int level);
|
||||
inline static float hashGridRecip(int level);
|
||||
inline static size_t numBuckets(int level);
|
||||
inline static Extents hashGridToRealExtents(int level, const Vector3int32& hashGrid);
|
||||
inline static ExtentsInt32 scaleExtents(int smallLevel, int bigLevel, const ExtentsInt32& smallExtents);
|
||||
inline static Vector3int32 realToHashGrid(int level, const Vector3& realPoint);
|
||||
inline static Vector3 hashGridToReal(int level, const Vector3int32& hashGrid);
|
||||
|
||||
// in SpatialHashMultiRes.cpp
|
||||
static int getHash(int level, const Vector3int32& grid);
|
||||
static void computeMinMax(const int level, const Extents& extents, Vector3int32& min, Vector3int32& max);
|
||||
static void makeVisitOrder(int* offsets, const Vector3& visitDir);
|
||||
|
||||
static const Extents safeExtents(const Extents& e) {
|
||||
RBXASSERT(Extents(e.min(), e.max()) == e);
|
||||
if (e.isNanInf()) {
|
||||
RBXASSERT(0);
|
||||
return Extents::zero();
|
||||
}
|
||||
else {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<class Primitive, class Contact, class ContactManager, int MAX_LEVELS>
|
||||
class SpatialHash {
|
||||
public:
|
||||
struct SpaceFilter
|
||||
{
|
||||
virtual IntersectResult Intersects(const Extents& extents) = 0;
|
||||
virtual float Distance(const Extents& extents) { return 0; };
|
||||
// return false to break iteration.
|
||||
virtual bool onPrimitive(Primitive* p, IntersectResult intersectResult, float distance) = 0;
|
||||
};
|
||||
|
||||
// Implement this pure virtual class in order to listen for coarse
|
||||
// movement events. See registerCoarseMovementCallback for more details.
|
||||
class CoarseMovementCallback {
|
||||
public:
|
||||
struct UpdateInfo {
|
||||
enum UpdateType {
|
||||
UPDATE_TYPE_Insert = 0,
|
||||
UPDATE_TYPE_Change,
|
||||
MAX_UPDATE_TYPES
|
||||
};
|
||||
|
||||
// for Insert update type, only new{Level,SpatialExtents} are valid
|
||||
// for Changed update type, both old and new info is valid
|
||||
UpdateType updateType;
|
||||
|
||||
int oldLevel;
|
||||
ExtentsInt32 oldSpatialExtents;
|
||||
int newLevel;
|
||||
ExtentsInt32 newSpatialExtents;
|
||||
};
|
||||
// This callback may be invoked when a part is altered from lua,
|
||||
// or other sensitive areas. Implementers of this method should
|
||||
// avoid modifying the parts of Primitive relating to its extents
|
||||
// and/or location to avoid re-entrant behavior and unexpected
|
||||
// interactions.
|
||||
virtual void coarsePrimitiveMovement(Primitive* p, const UpdateInfo& info) = 0;
|
||||
};
|
||||
|
||||
SpatialHash(World* world, ContactManager* contactManager, int maxCellsPerPrimitive);
|
||||
~SpatialHash();
|
||||
|
||||
// loosely sorted.
|
||||
void visitPrimitivesInSpace(SpaceFilter* filter, const Vector3& visitDir);
|
||||
// strict sorting of nodes according the the return value of filter->Distance().
|
||||
void visitPrimitivesInSpace(SpaceFilter* filter);
|
||||
|
||||
void fastClear();
|
||||
|
||||
void onPrimitiveAdded(Primitive* p, bool addContact = true);
|
||||
void onPrimitiveRemoved(Primitive* p);
|
||||
void onPrimitiveExtentsChanged(Primitive* p);
|
||||
void onPrimitiveAssembled(Primitive* p);
|
||||
|
||||
void getPrimitivesInGrid(const Vector3int32& grid, G3D::Array<Primitive*>& primitives);
|
||||
bool getNextGrid(Vector3int32& grid, const RbxRay& unitRay, float maxDistance);
|
||||
|
||||
// find all primitives that touch the same grids as touched by extents
|
||||
void getPrimitivesTouchingGrids(
|
||||
const Extents& extents,
|
||||
const Primitive* ingore,
|
||||
std::size_t maxCount,
|
||||
boost::unordered_set<Primitive*>& answer);
|
||||
|
||||
void getPrimitivesTouchingGrids(
|
||||
const Extents& extents,
|
||||
const boost::unordered_set<const Primitive*>& ignoreSet,
|
||||
std::size_t maxCount,
|
||||
boost::unordered_set<Primitive*>& answer);
|
||||
|
||||
// This function iteratively processes cells that overlap with extents, which is faster on small regions
|
||||
template <typename Set> void getPrimitivesOverlapping( const Extents& extents, Set& answer);
|
||||
|
||||
// This function recursively processes cells that overlap with extents, which is faster on large regions
|
||||
template <typename Set> void getPrimitivesOverlappingRec(const Extents& extents, Set& answer);
|
||||
|
||||
// inquiry
|
||||
int getNodesOut() const {return nodesOut;}
|
||||
int getMaxBucket() const {return maxBucket;}
|
||||
|
||||
void doStats() const;
|
||||
|
||||
// Callback mechanism that allows outside systems to be notified when
|
||||
// parts exibit significant movement (relative to their size). A
|
||||
// movement is considered significant if it causes the part to enter
|
||||
// or leave a region of space, where region size determined by
|
||||
// primitive size. The size of the coarsest region is
|
||||
// SpatialHashStatic::hashGridSize(MAXLEVELS - 1) so callers cannot
|
||||
// depend on this callback being fired for smaller region movements,
|
||||
// but in practice the majority of primitives use smaller regions.
|
||||
void registerCoarseMovementCallback(CoarseMovementCallback* callback);
|
||||
void unregisterCoarseMovementCallback(CoarseMovementCallback* callback);
|
||||
|
||||
private:
|
||||
class TreeNode;
|
||||
class SpatialNode;
|
||||
typedef std::pair<TreeNode*, IntersectResult> TreeNodePair;
|
||||
|
||||
// sort by the dot product of( the position of the offsets in space by the visitDir ).
|
||||
struct SortOffsetByVisitDir
|
||||
{
|
||||
SortOffsetByVisitDir(const Vector3& visitDir)
|
||||
: visitDir(visitDir) {};
|
||||
const Vector3& visitDir;
|
||||
|
||||
bool operator()(const TreeNodePair& a, const TreeNodePair& b)
|
||||
{
|
||||
Vector3 va((float)a.first->gridId.x, (float)a.first->gridId.y, (float)a.first->gridId.z);
|
||||
Vector3 vb((float)b.first->gridId.x, (float)b.first->gridId.y, (float)b.first->gridId.z);
|
||||
return va.dot(visitDir) < vb.dot(visitDir);
|
||||
}
|
||||
};
|
||||
|
||||
struct FastClearSpatialNode
|
||||
{
|
||||
SpatialHash<Primitive, Contact, ContactManager, MAX_LEVELS>* hash;
|
||||
FastClearSpatialNode(SpatialHash<Primitive, Contact, ContactManager, MAX_LEVELS>* h) : hash(h) {};
|
||||
void operator()(SpatialNode* node)
|
||||
{
|
||||
node->primitive->setOldSpatialExtents(ExtentsInt32::empty());
|
||||
hash->nodesOut--;
|
||||
}
|
||||
};
|
||||
|
||||
struct FastClearTreeNode
|
||||
{
|
||||
SpatialHash<Primitive, Contact, ContactManager, MAX_LEVELS>* hash;
|
||||
FastClearTreeNode(SpatialHash<Primitive, Contact, ContactManager, MAX_LEVELS>* h) : hash(h) {};
|
||||
void operator()(TreeNode* node)
|
||||
{
|
||||
node->refByPrimitives = 0;
|
||||
node->next = 0;
|
||||
hash->numTreeNodesTotal--;
|
||||
}
|
||||
};
|
||||
|
||||
class TreeNode : protected NodeBase, public Allocator<TreeNode> {
|
||||
protected:
|
||||
friend class SpatialHash;
|
||||
friend class SpatialNode;
|
||||
|
||||
unsigned short children[8];
|
||||
unsigned char childMask;
|
||||
int refByPrimitives;
|
||||
TreeNode *next;
|
||||
|
||||
void reset() {
|
||||
refByPrimitives = 0;
|
||||
this->level = -1;
|
||||
this->hashId = -1;
|
||||
next = NULL;
|
||||
childMask = 0;
|
||||
for (int i=0; i<8; i++)
|
||||
children[i] = 0xffff;
|
||||
}
|
||||
|
||||
void setChild(int i, unsigned int child) {
|
||||
childMask |= (1<<i);
|
||||
children[i] = child;
|
||||
}
|
||||
|
||||
void removeChild(int i) {
|
||||
childMask &= ~(1<<i);
|
||||
children[i] = 0xffff;
|
||||
}
|
||||
|
||||
public:
|
||||
TreeNode() {
|
||||
reset();
|
||||
}
|
||||
|
||||
~TreeNode() {
|
||||
RBXASSERT(refByPrimitives == 0);
|
||||
RBXASSERT(next == NULL);
|
||||
next = NULL;
|
||||
}
|
||||
|
||||
unsigned char hasChild(int i) {
|
||||
return childMask & (1<<i);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class SpatialNode : protected NodeBase, public Allocator<SpatialNode> {
|
||||
protected:
|
||||
friend class SpatialHash;
|
||||
friend class TreeNode;
|
||||
|
||||
Primitive* primitive; // primitive associated with this node
|
||||
SpatialNode* nextHashLink; // next node for this hash
|
||||
#ifdef _RBX_DEBUGGING_SPATIAL_HASH
|
||||
SpatialNode* nextPrimitiveLink; // next node for this primitive
|
||||
SpatialNode* prevPrimitiveLink; // prior node for this primitive
|
||||
#endif
|
||||
TreeNode *treeNode;
|
||||
|
||||
public:
|
||||
SpatialNode(int l, int hashId, const Vector3int32& gridId)
|
||||
: NodeBase(l, hashId, gridId)
|
||||
, nextHashLink(0)
|
||||
, primitive(NULL)
|
||||
, treeNode(NULL)
|
||||
#ifdef _RBX_DEBUGGING_SPATIAL_HASH
|
||||
, nextPrimitiveLink(0)
|
||||
, prevPrimitiveLink(0)
|
||||
#endif
|
||||
{}
|
||||
|
||||
~SpatialNode()
|
||||
{
|
||||
treeNode = NULL;
|
||||
primitive = NULL;
|
||||
nextHashLink = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
class SpatialHashTableEntry {
|
||||
public:
|
||||
SpatialNode *nodes;
|
||||
TreeNode *treeNodes;
|
||||
};
|
||||
|
||||
protected: // default settings override on construction
|
||||
static const int rootLevel;
|
||||
|
||||
private:
|
||||
ConcurrencyValidator concurrencyValidator;
|
||||
|
||||
const int maxCellsPerPrimitive;
|
||||
|
||||
int numTreeNodesTotal;
|
||||
|
||||
World* world;
|
||||
ContactManager* contactManager;
|
||||
std::vector<SpatialHashTableEntry> hashTables[MAX_LEVELS];
|
||||
int nodesOut;
|
||||
int maxBucket;
|
||||
G3D::Array<Primitive*> outOfContact; // temp buffer
|
||||
std::vector<CoarseMovementCallback*> coarseMovementCallbacks;
|
||||
|
||||
SpatialNode* newNode(int level, int hash, const Vector3int32& grid);
|
||||
void returnNode(SpatialNode* node);
|
||||
|
||||
TreeNode * findTreeNode(
|
||||
int level, int hash, const Vector3int32 &gridCoord);
|
||||
TreeNode * createTreeNode(
|
||||
int level, int hash, const Vector3int32 &gridCoord);
|
||||
void _retireTreeNode(TreeNode* tn);
|
||||
void retireTreeNode(TreeNode* tn);
|
||||
void removeTreeNodeChild(int childLevel, Vector3int32 &childGridCoord);
|
||||
|
||||
bool findOtherNodesInLevel0Cell(SpatialNode* destroy);
|
||||
|
||||
void checkAndReleaseContacts(Primitive *p);
|
||||
|
||||
void addContactFromChildren(TreeNode *tn, Primitive *p);
|
||||
|
||||
int computeLevel(const Primitive* p, const Extents& extents);
|
||||
|
||||
inline bool oldExtentsOverlap(Primitive* p0, Primitive* p1);
|
||||
|
||||
bool hashHasPrimitive(int level, Primitive* p, int hash, const Vector3int32& grid);
|
||||
|
||||
SpatialNode* findNode(Primitive* p, const Vector3int32& grid);
|
||||
void removeNodeFromHash(SpatialNode* remove);
|
||||
|
||||
void insertNodeToPrimitive(SpatialNode* node, Primitive* p, const Vector3int32& grid, int hash);
|
||||
|
||||
void addNode(Primitive* p, const Vector3int32& grid, bool addContact = true);
|
||||
void destroyNode(SpatialNode* destroy);
|
||||
|
||||
void changeMinMax( Primitive* p,
|
||||
const ExtentsInt32* change,
|
||||
const ExtentsInt32* oldBox,
|
||||
const ExtentsInt32* newBox,
|
||||
bool addContact = true);
|
||||
void primitiveAdded(Primitive* p, bool addContact);
|
||||
void primitiveRemoved(Primitive* p);
|
||||
void primitiveExtentsChanged(Primitive* p, const Extents& extents);
|
||||
|
||||
// remove these once we can confirm "boost::pool" objects work
|
||||
object_pool<TreeNode, roblox_allocator> treeNodeAllocator;
|
||||
object_pool<SpatialNode, roblox_allocator> spatialNodeAllocator;
|
||||
//
|
||||
|
||||
inline Vector3int32 getChildGrid(const Vector3int32& grid, int offset)
|
||||
{
|
||||
return Vector3int32(
|
||||
(grid.x << 1) + (offset & 1), // bit 0 of offset is x coord.
|
||||
(grid.y << 1) + ((offset & 2) >> 1), // bit 1 of offset is y coord.
|
||||
(grid.z << 1) + ((offset & 4) >> 2) // bit 2 of offset is z coord.
|
||||
);
|
||||
}
|
||||
|
||||
static const Extents calcNewExtents(Primitive* p);
|
||||
|
||||
void visitPrimitivesInSpaceWorker(TreeNode* tn, int level, int hashId, const RBX::Vector3int32& gridId, int* visitOrder, IntersectResult intersectResult, SpaceFilter* filter, const Vector3& visitDir);
|
||||
|
||||
template <typename Set> void getPrimitivesOverlappingRec(const Extents* extents, Set& answer, int level, int hash, const Vector3int32& gridCoord);
|
||||
|
||||
private:
|
||||
void setup();
|
||||
void cleanup();
|
||||
|
||||
void getPrimitivesInGrid(int level, const Vector3int32& grid, G3D::Array<Primitive*>& primitives);
|
||||
|
||||
// octree interface
|
||||
TreeNode* getFirstRoot();
|
||||
TreeNode* getNextRoot(TreeNode* prevRoot);
|
||||
|
||||
TreeNode* getChild(TreeNode* parent, int octant);
|
||||
void getPrimitivesInTreeNode(TreeNode* treenode, G3D::Array<Primitive*>& primitives);
|
||||
|
||||
public: // for unit testing
|
||||
|
||||
// DEBUGGING only
|
||||
bool validateInsertNodeToPrimitive(SpatialNode* node, Primitive* p, const Vector3int32& grid, int hash);
|
||||
bool validateRemoveNodeFromPrimitive(SpatialNode* node);
|
||||
bool validateNodesOverlap(Primitive* p0, Primitive* p1);
|
||||
bool validateTallyTreeNodes();
|
||||
bool validateTreeNodeNotHere(TreeNode* tn, int level, int hash);
|
||||
bool validateContacts(Primitive* p); // debug only
|
||||
bool validateNoNodesOut();
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#include "v8World/SpatialHashMultiRes.inl"
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,45 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/IWorldStage.h"
|
||||
#include "V8World/Joint.h"
|
||||
#include "boost/scoped_ptr.hpp"
|
||||
#include "boost/intrusive/list.hpp"
|
||||
|
||||
namespace RBX {
|
||||
class Assembly;
|
||||
|
||||
namespace Profiling
|
||||
{
|
||||
class CodeProfiler;
|
||||
}
|
||||
|
||||
class StepJointsStage : public IWorldStage {
|
||||
private:
|
||||
typedef boost::intrusive::list<Joint, boost::intrusive::base_hook<StepJointsStageHook> > Joints;
|
||||
Joints worldStepJoints;
|
||||
|
||||
void addJoint(Joint* j);
|
||||
void removeJoint(Joint* j);
|
||||
|
||||
public:
|
||||
///////////////////////////////////////////
|
||||
// IStage
|
||||
StepJointsStage(IStage* upstream, World* world);
|
||||
|
||||
~StepJointsStage();
|
||||
|
||||
/*override*/ IStage::StageType getStageType() const {return IStage::STEP_JOINTS_STAGE;}
|
||||
|
||||
/*override*/ void onEdgeAdded(Edge* e);
|
||||
/*override*/ void onEdgeRemoving(Edge* e);
|
||||
|
||||
void onSimulateAssemblyAdded(Assembly* a);
|
||||
void onSimulateAssemblyRemoving(Assembly* a);
|
||||
|
||||
void jointsStepWorld();
|
||||
|
||||
boost::scoped_ptr<Profiling::CodeProfiler> profilingJointUpdate;
|
||||
};
|
||||
} // namespace
|
||||
@@ -0,0 +1,32 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#include "V8World/Controller.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class SurfaceData {
|
||||
public:
|
||||
LegacyController::InputType inputType;
|
||||
float paramA;
|
||||
float paramB;
|
||||
|
||||
SurfaceData()
|
||||
: inputType(LegacyController::NO_INPUT)
|
||||
, paramA(-0.5)
|
||||
, paramB(0.5)
|
||||
{}
|
||||
|
||||
bool operator== (const SurfaceData& other) const {
|
||||
return ( inputType == other.inputType
|
||||
&& paramA == other.paramA
|
||||
&& paramB == other.paramB );
|
||||
}
|
||||
|
||||
static const SurfaceData& empty() {static SurfaceData s; return s;}
|
||||
|
||||
bool isEmpty() const {return *this == empty();}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,101 @@
|
||||
#pragma once
|
||||
/* Copyright 2003-2011 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#include <vector>
|
||||
#include "Util/G3DCore.h"
|
||||
#include "V8World/Primitive.h"
|
||||
#include "Voxel/Util.h"
|
||||
#include "Voxel/CellChangeListener.h"
|
||||
#include "Voxel/ChunkMap.h"
|
||||
#include "Voxel2/GridListener.h"
|
||||
|
||||
namespace RBX {
|
||||
namespace Voxel {
|
||||
class Grid;
|
||||
}
|
||||
|
||||
namespace Voxel2 {
|
||||
class Grid;
|
||||
}
|
||||
|
||||
class TerrainPartitionMega:
|
||||
public Voxel::CellChangeListener
|
||||
{
|
||||
public:
|
||||
TerrainPartitionMega(Voxel::Grid* voxelGrid);
|
||||
~TerrainPartitionMega();
|
||||
|
||||
void findCellsTouchingExtents(const Extents& extents, std::vector<Vector3int16>* found) const;
|
||||
|
||||
private:
|
||||
struct ChunkData
|
||||
{
|
||||
// filled[y][z][x] represents a sub-chunk of 4x2x4 cells, where 1 cell = 1 bit
|
||||
unsigned int count;
|
||||
unsigned int filled[Voxel::kY_CHUNK_SIZE / 2][Voxel::kXZ_CHUNK_SIZE / 4][Voxel::kXZ_CHUNK_SIZE / 4];
|
||||
|
||||
ChunkData(): count(0)
|
||||
{
|
||||
memset(filled, 0, sizeof(filled));
|
||||
}
|
||||
};
|
||||
|
||||
Voxel::ChunkMap<ChunkData> chunks;
|
||||
Voxel::Grid* voxelGrid;
|
||||
|
||||
/*override*/ virtual void terrainCellChanged(const Voxel::CellChangeInfo& info);
|
||||
|
||||
void findCellsInRegion(const SpatialRegion::Id& region, const ChunkData& chunk, const Vector3int16& minOffset, const Vector3int16& maxOffset, std::vector<Vector3int16>* found) const;
|
||||
};
|
||||
|
||||
class TerrainPartitionSmooth
|
||||
{
|
||||
public:
|
||||
static const int kChunkSizeLog2 = 3;
|
||||
static const int kChunkSize = 1 << kChunkSizeLog2;
|
||||
|
||||
TerrainPartitionSmooth(Voxel2::Grid* grid);
|
||||
~TerrainPartitionSmooth();
|
||||
|
||||
struct ChunkResult
|
||||
{
|
||||
Vector3int32 id;
|
||||
bool touchesSolid;
|
||||
bool touchesWater;
|
||||
};
|
||||
|
||||
void findChunksTouchingExtents(const Extents& extents, std::vector<ChunkResult>* found) const;
|
||||
|
||||
void updateChunk(const Vector3int32& id);
|
||||
|
||||
private:
|
||||
struct ChunkSlice
|
||||
{
|
||||
// 8x8 bits for each slice
|
||||
uint64_t solid;
|
||||
uint64_t water;
|
||||
};
|
||||
|
||||
struct ChunkData
|
||||
{
|
||||
ChunkSlice slices[kChunkSize];
|
||||
|
||||
ChunkData()
|
||||
{
|
||||
memset(slices, 0, sizeof(slices));
|
||||
}
|
||||
};
|
||||
|
||||
typedef boost::unordered_map<Vector3int32, ChunkData> ChunkMap;
|
||||
|
||||
ChunkMap chunks;
|
||||
Voxel2::Grid* grid;
|
||||
|
||||
uint64_t masksHor[kChunkSize][kChunkSize];
|
||||
uint64_t masksVer[kChunkSize][kChunkSize];
|
||||
|
||||
void fillChunkIfTouchingExtents(const Vector3int32& chunkId, const ChunkData& chunkData, const Vector3int32& minPos, const Vector3int32& maxPos, std::vector<ChunkResult>* found) const;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "Util/G3DCore.h"
|
||||
#include "Util/Extents.h"
|
||||
#include "V8Kernel/ContactConnector.h"
|
||||
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Tolerance
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////
|
||||
//
|
||||
static const Extents& maxExtents() {
|
||||
// cds: this is the no-clip hack patch. 1777.7 is arbitrary.
|
||||
const float fuzzyMil = 1e6 + 1777.7 + (*((int*)(__DATE__ + 2)) % 1000);
|
||||
static Extents millionCube(Vector3(-fuzzyMil - (rand()%65536),
|
||||
-fuzzyMil - (rand()%65536),
|
||||
-fuzzyMil - (rand()%65536)),
|
||||
Vector3( fuzzyMil + (rand()%65536),
|
||||
fuzzyMil + (rand()%65536),
|
||||
fuzzyMil + (rand()%65536)));
|
||||
return millionCube;
|
||||
}
|
||||
|
||||
// Tolerance for joining
|
||||
static float mainGrid() {return 0.1f;}
|
||||
static float jointMaxUnaligned() {return 0.05f;}
|
||||
static float jointOverlapMin() {return 0.35f;} // plate thickness is 0.4
|
||||
static float jointOverlapMin2() {return 0.1f;}
|
||||
|
||||
static bool pointsUnaligned(const Vector3& p0, const Vector3& p1) {
|
||||
float magSqr = (p1-p0).squaredMagnitude();
|
||||
return (magSqr > (jointMaxUnaligned() * jointMaxUnaligned()));
|
||||
}
|
||||
|
||||
// Joint, Spawn: tight parameters, only achieved by a snap
|
||||
static float jointAngleMax() {return 0.01f;} // radians
|
||||
static float jointPlanarMax() {return 0.01f;}
|
||||
|
||||
// Rotate: loose parameters
|
||||
static float rotateAngleMax() {return jointMaxUnaligned() * 0.5f;} // length of the axle is always == 2
|
||||
static float rotatePlanarMax() {return jointMaxUnaligned();}
|
||||
|
||||
// Glue: loose parameters
|
||||
static float glueAngleMax() {return jointMaxUnaligned();} // radians
|
||||
static float gluePlanarMax() {return jointMaxUnaligned();}
|
||||
|
||||
// Tolerance for dragger and for primitive::fuzzyExtents
|
||||
// For now this is nasty - it equals the connector overlap tolerance
|
||||
static float maxOverlapOrGap() {return ContactConnector::overlapGoal();} // 0.01;
|
||||
|
||||
static float maxOverlapAllowedForResize() {return 3.0f * maxOverlapOrGap();} // 0.03;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/IWorldStage.h"
|
||||
#include "V8World/Enum.h"
|
||||
#include "Util/Utilities.h"
|
||||
#include "Util/SpanningTree.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Primitive;
|
||||
class Joint;
|
||||
class Mechanism;
|
||||
class Clump;
|
||||
class Edge;
|
||||
|
||||
class JointSort {
|
||||
public:
|
||||
static bool heavierJoint(const Joint* j0, const Joint* j1);
|
||||
};
|
||||
|
||||
class TreeStage : public IWorldStage
|
||||
, public SpanningTree
|
||||
{
|
||||
private:
|
||||
typedef SpanningTree Super;
|
||||
int maxTreeDepth;
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////
|
||||
//
|
||||
// Data storage
|
||||
std::set<Mechanism*> dirtyMechanisms;
|
||||
std::set<Mechanism*> downstreamMechanisms;
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// Traverse Utilities
|
||||
//
|
||||
void removeSpanningTreeJoint(Joint* j);
|
||||
void swapTree(Joint* deactivate, Joint* activate, Primitive* newParent);
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// Spanning Tree
|
||||
//
|
||||
/*override*/ void onSpanningEdgeAdding(SpanningEdge* edge, SpanningNode* child);
|
||||
/*override*/ void onSpanningEdgeAdded(SpanningEdge* edge);
|
||||
/*override*/ void onSpanningEdgeRemoving(SpanningEdge* edge);
|
||||
/*override*/ void onSpanningEdgeRemoved(SpanningEdge* edge, SpanningNode* child);
|
||||
/*override*/ bool validateTree(SpanningNode* root);
|
||||
|
||||
void removeFromPipeline(Mechanism* m);
|
||||
void dirtyMechanism(Mechanism* m);
|
||||
void cleanMechanism(Mechanism* m); // true if moved downstream
|
||||
|
||||
void destroyClump(Primitive* p);
|
||||
void destroyAssembly(Primitive* p);
|
||||
void destroyMechanism(Primitive* p);
|
||||
|
||||
public:
|
||||
///////////////////////////////////////////
|
||||
// IStage
|
||||
TreeStage(IStage* upstream, World* world);
|
||||
|
||||
~TreeStage();
|
||||
|
||||
/*override*/ IStage::StageType getStageType() const {return IStage::TREE_STAGE;}
|
||||
|
||||
/*override*/ void onEdgeAdded(Edge* e);
|
||||
/*override*/ void onEdgeRemoving(Edge* e);
|
||||
|
||||
/*override*/ int getMetric(IWorldStage::MetricType metricType);
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// From the Joint Stage
|
||||
//
|
||||
void onPrimitiveAdded(Primitive* p);
|
||||
void onPrimitiveRemoving(Primitive* p);
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// From the World
|
||||
//
|
||||
|
||||
void assemble(); // update everything;
|
||||
|
||||
bool isAssembled() const {return dirtyMechanisms.empty();}
|
||||
|
||||
// from internal and world
|
||||
void sendClumpChangedMessage(Primitive* childPrim);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
#pragma once
|
||||
|
||||
#include "V8World/Geometry.h"
|
||||
#include "V8World/Mesh.h"
|
||||
#include "V8World/Block.h"
|
||||
#include "V8World/BulletGeometryPoolObjects.h"
|
||||
#include "Extras/ConvexDecomposition/ConvexDecomposition.h"
|
||||
|
||||
#include "v8world/KDTree.h"
|
||||
|
||||
#define PHYSICS_SERIAL_VERSION 3
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
class CSGConvex;
|
||||
class ConvexPoly;
|
||||
class Block;
|
||||
|
||||
class KDTreeMeshWrapper: public Allocator<KDTreeMeshWrapper>
|
||||
{
|
||||
public:
|
||||
KDTreeMeshWrapper(const std::string& str);
|
||||
~KDTreeMeshWrapper();
|
||||
|
||||
const KDTree& getTree() const { return tree; }
|
||||
|
||||
private:
|
||||
std::vector<Vector3> vertices;
|
||||
std::vector<unsigned int> indices;
|
||||
KDTree tree;
|
||||
};
|
||||
|
||||
class TriangleMesh : public Geometry
|
||||
{
|
||||
public:
|
||||
typedef GeometryPool<std::string, BulletDecompWrapper, StringComparer> BulletDecompPool;
|
||||
typedef GeometryPool<std::string, KDTreeMeshWrapper, StringComparer> KDTreeMeshPool;
|
||||
|
||||
private:
|
||||
//decompData
|
||||
int version;
|
||||
BulletDecompPool::Token compound;
|
||||
|
||||
KDTreeMeshPool::Token kdTreeMesh;
|
||||
Vector3 kdTreeScale;
|
||||
|
||||
// Needed for basic Dragger functions
|
||||
Block* boundingBoxMesh;
|
||||
|
||||
typedef Geometry Super;
|
||||
float centerToCornerDistance;
|
||||
|
||||
Matrix3 getMomentHollow(float mass) const;
|
||||
|
||||
/*override*/ void setSize(const G3D::Vector3& _size);
|
||||
|
||||
public:
|
||||
TriangleMesh() : version(PHYSICS_SERIAL_VERSION), centerToCornerDistance(0.0), boundingBoxMesh(NULL)
|
||||
{
|
||||
boundingBoxMesh = new Block();
|
||||
bulletCollisionObject.reset(new btCollisionObject());
|
||||
}
|
||||
~TriangleMesh();
|
||||
|
||||
// Getters
|
||||
const BulletDecompWrapper* getCompound() const { return compound ? &*compound : NULL; }
|
||||
|
||||
int getVersion() { return version; }
|
||||
|
||||
static bool validateDataVersions(const std::string& data, int& version);
|
||||
static bool validateIsBlockData(const std::string& data);
|
||||
|
||||
// Physics Data Setters
|
||||
void setStaticMeshData(const std::string &key, const std::string& data, const btVector3& scale = btVector3(1.0f, 1.0f, 1.0f));
|
||||
bool setCompoundMeshData(const std::string &key, const std::string& data, const btVector3& scale = btVector3(1.0f, 1.0f, 1.0f));
|
||||
|
||||
// Updates Physics Data
|
||||
void updateObjectScale(const std::string& decompKey, const std::string &decompStr, const G3D::Vector3& scale, const G3D::Vector3& meshScale = Vector3(-1, -1, -1));
|
||||
|
||||
// Deserializations
|
||||
static std::string generateDecompositionData(int numTriangles, const unsigned int* triangleIndexBase, int numVertices, btScalar* vertexBase);
|
||||
static std::string generateConvexHullData(int numTriangles, const unsigned int* triangleIndexBase, int numVertices, const btVector3* vertexBase);
|
||||
static BulletDecompWrapper::ShapeType* retrieveDecomposition(const std::string& str);
|
||||
static std::string generateStaticMeshData(const std::vector<unsigned int>& indices, std::vector<btVector3>& vertices);
|
||||
static void readConvexHullData(std::vector<float> &vertices, unsigned int &numVertices, std::vector<unsigned int> &indices, unsigned int &numIndices, btTransform &trans, std::stringstream &stream);
|
||||
static void readPrefixData(btVector3 &scale, int ¤tVersion, std::stringstream &stream);
|
||||
|
||||
// HOUSEKEEPING
|
||||
static std::vector<CSGConvex> getDecompConvexes(const std::string& data, int& currentVersion, btVector3 &scale, bool dataHasScale = false);
|
||||
static void serializeConvexHullData(const btTransform& transform, const unsigned int numVertices, const float* verticesBase,
|
||||
const unsigned int numIndices, const unsigned int* indicesBase, std::stringstream &outstream);
|
||||
|
||||
// Creates decomposition data
|
||||
std::string generateDecompositionGeometry(const std::vector<btVector3> &vertices, const std::vector<unsigned int> &indices);
|
||||
|
||||
// UTIL
|
||||
static const std::string getPlaceholderData();
|
||||
static const std::string getBlockData();
|
||||
|
||||
// Primitive Overrides
|
||||
/*override*/ virtual bool hitTest(const RbxRay& rayInMe, Vector3& localHitPoint, Vector3& surfaceNormal);
|
||||
|
||||
/*override*/ virtual GeometryType getGeometryType() const {return GEOMETRY_TRI_MESH;}
|
||||
/*override*/ virtual CollideType getCollideType() const {return COLLIDE_BULLET;}
|
||||
|
||||
// Real Radius
|
||||
/*override*/ virtual float getRadius() const {return centerToCornerDistance;}
|
||||
|
||||
// Real Corner
|
||||
/*override*/ virtual Vector3 getCenterToCorner(const Matrix3& rotation) const
|
||||
{
|
||||
if (boundingBoxMesh)
|
||||
return boundingBoxMesh->getCenterToCorner(rotation);
|
||||
else
|
||||
return Vector3(centerToCornerDistance, centerToCornerDistance, centerToCornerDistance);
|
||||
}
|
||||
|
||||
// Moment
|
||||
/*override*/ virtual Matrix3 getMoment(float mass) const {
|
||||
return getMomentHollow(mass);
|
||||
}
|
||||
|
||||
// Dragger Functions
|
||||
size_t closestSurfaceToPoint( const Vector3& pointInBody ) const;
|
||||
Plane getPlaneFromSurface( const size_t surfaceId ) const;
|
||||
virtual CoordinateFrame getSurfaceCoordInBody( const size_t surfaceId ) const;
|
||||
Vector3 getSurfaceNormalInBody( const size_t surfaceId ) const;
|
||||
size_t getMostAlignedSurface( const Vector3& vecInWorld, const G3D::Matrix3& objectR ) const;
|
||||
int getNumSurfaces( void ) const { return boundingBoxMesh->getMesh()->numFaces(); }
|
||||
Vector3 getSurfaceVertInBody( const size_t surfaceId, const int vertId ) const;
|
||||
int getNumVertsInSurface( const size_t surfaceId ) const;
|
||||
bool vertOverlapsFace( const Vector3& pointInBody, const size_t surfaceId ) const;
|
||||
|
||||
/*override*/virtual bool findTouchingSurfacesConvex( const CoordinateFrame& myCf, size_t& myFaceId, const Geometry& otherGeom, const CoordinateFrame& otherCf, size_t& otherFaceId ) const;
|
||||
/*override*/virtual bool FacesOverlapped( const CoordinateFrame& myCf, size_t& myFaceId, const Geometry& otherGeom, const CoordinateFrame& otherCf, size_t& otherFaceId, float tol ) const;
|
||||
/*override*/virtual bool FaceVerticesOverlapped( const CoordinateFrame& myCf, size_t& myFaceId, const Geometry& otherGeom, const CoordinateFrame& otherCf, size_t& otherFaceId, float tol ) const;
|
||||
/*override*/virtual bool FaceEdgesOverlapped( const CoordinateFrame& myCf, size_t& myFaceId, const Geometry& otherGeom, const CoordinateFrame& otherCf, size_t& otherFaceId, float tol ) const;
|
||||
|
||||
/*override*/ bool setUpBulletCollisionData(void);
|
||||
|
||||
};
|
||||
|
||||
class CSGConvex
|
||||
{
|
||||
public:
|
||||
std::vector<btVector3> vertices;
|
||||
std::vector<unsigned int> indices;
|
||||
btTransform transform;
|
||||
};
|
||||
|
||||
class BulletConvexDecomposition : public ConvexDecomposition::ConvexDecompInterface
|
||||
{
|
||||
private:
|
||||
std::stringstream streamChildren; //binary string stream for vertex data
|
||||
|
||||
public:
|
||||
BulletConvexDecomposition() {}
|
||||
|
||||
virtual void ConvexDecompResult(ConvexDecomposition::ConvexResult &result);
|
||||
void addStreamChildren(std::stringstream &streamString);
|
||||
|
||||
};
|
||||
} // namespace
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
Utility class - holds Wedge Meshes of same size for use by Geometry Pool.
|
||||
*/
|
||||
|
||||
#include "Util/Memory.h"
|
||||
#include "V8World/Mesh.h"
|
||||
|
||||
|
||||
namespace RBX {
|
||||
|
||||
namespace POLY {
|
||||
|
||||
class WedgeMesh : public Allocator<WedgeMesh>
|
||||
{
|
||||
private:
|
||||
Mesh mesh;
|
||||
|
||||
public:
|
||||
WedgeMesh(const Vector3& size)
|
||||
{
|
||||
mesh.makeWedge(size);
|
||||
}
|
||||
const Mesh* getMesh() const {return &mesh;}
|
||||
};
|
||||
|
||||
} // namespace POLY
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include "V8World/Poly.h"
|
||||
#include "V8World/GeometryPool.h"
|
||||
#include "V8World/WedgeMesh.h"
|
||||
#include "V8World/BlockMesh.h"
|
||||
#include "V8World/BulletGeometryPoolObjects.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class WedgePoly : public Poly {
|
||||
public:
|
||||
typedef GeometryPool<Vector3, POLY::WedgeMesh, Vector3Comparer> WedgeMeshPool;
|
||||
typedef GeometryPool<Vector3, BulletWedgeShapeWrapper, Vector3Comparer> BulletWedgeShapePool;
|
||||
|
||||
/*override*/ Matrix3 getMoment(float mass) const;
|
||||
/*override*/ Vector3 getCofmOffset() const;
|
||||
/*override*/ CoordinateFrame getSurfaceCoordInBody( const size_t surfaceId ) const;
|
||||
/*override*/ size_t getFaceFromLegacyNormalId( const NormalId nId ) const;
|
||||
/*override*/ bool isGeometryOrthogonal( void ) const { return false; }
|
||||
/*override*/ bool setUpBulletCollisionData(void);
|
||||
/*override*/ void setSize(const G3D::Vector3& _size);
|
||||
|
||||
private:
|
||||
typedef Poly Super;
|
||||
|
||||
WedgeMeshPool::Token wedgeMesh;
|
||||
BulletWedgeShapePool::Token bulletWedgeShape;
|
||||
|
||||
/*override*/ virtual Vector3 getCenterToCorner(const Matrix3& rotation) const;
|
||||
|
||||
void updateBulletCollisionData();
|
||||
|
||||
protected:
|
||||
// Geometry Overrides
|
||||
/*override*/ virtual GeometryType getGeometryType() const {return GEOMETRY_WEDGE;}
|
||||
|
||||
// Poly Overrides
|
||||
/*override*/ void buildMesh();
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
|
||||
#include "V8World/RigidJoint.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class WeldJoint : public RigidJoint
|
||||
{
|
||||
private:
|
||||
///////////////////////////////////////////////////
|
||||
// Joint
|
||||
/*override*/ virtual JointType getJointType() const {return WELD_JOINT;}
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// WeldJoint
|
||||
static bool compatibleSurfaces(
|
||||
Primitive* p0,
|
||||
Primitive* p1,
|
||||
NormalId nId0,
|
||||
NormalId nId1);
|
||||
|
||||
public:
|
||||
WeldJoint() {}
|
||||
|
||||
WeldJoint(Primitive* prim0, Primitive* prim1, const CoordinateFrame& c0, const CoordinateFrame &c1)
|
||||
: RigidJoint(prim0, prim1, c0, c1)
|
||||
{}
|
||||
|
||||
virtual ~WeldJoint() {}
|
||||
|
||||
static WeldJoint* canBuildJoint(
|
||||
Primitive* p0,
|
||||
Primitive* p1,
|
||||
NormalId nId0,
|
||||
NormalId nId1);
|
||||
};
|
||||
|
||||
class ManualWeldJoint : public WeldJoint
|
||||
{
|
||||
private:
|
||||
size_t surface0; // surface from primitive 0
|
||||
size_t surface1; // surface from primitive 1
|
||||
|
||||
/*override*/ virtual JointType getJointType() const {return MANUAL_WELD_JOINT;}
|
||||
|
||||
public:
|
||||
ManualWeldJoint() {surface0 = (size_t)-1; surface1 = (size_t)-1;}
|
||||
ManualWeldJoint(size_t s0, size_t s1, Primitive* prim0, Primitive* prim1, const CoordinateFrame& c0, const CoordinateFrame &c1)
|
||||
: WeldJoint(prim0, prim1, c0, c1)
|
||||
{surface0 = s0; surface1 = s1;}
|
||||
|
||||
~ManualWeldJoint() {}
|
||||
|
||||
size_t getSurface0(void) const {return surface0;}
|
||||
size_t getSurface1(void) const {return surface1;}
|
||||
void setSurface0(size_t surfId) {surface0 = surfId;}
|
||||
void setSurface1(size_t surfId) {surface1 = surfId;}
|
||||
|
||||
Vector3int16 getCell() const;
|
||||
void setCell(const Vector3int16& pos);
|
||||
|
||||
static bool isTouchingTerrain(Primitive* terrain, Primitive* prim);
|
||||
};
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -0,0 +1,353 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8World/Primitive.h"
|
||||
#include "V8World/ContactManager.h"
|
||||
|
||||
#include "Util/IndexArray.h"
|
||||
#include "rbx/rbxTime.h"
|
||||
#include "rbx/signal.h"
|
||||
#include "Util/SpatialRegion.h"
|
||||
#include "Util/HeapValue.h"
|
||||
#include "util/PhysicalProperties.h"
|
||||
|
||||
class btCollisionDispatcher;
|
||||
class btCollisionWorld;
|
||||
class btDefaultCollisionConfiguration;
|
||||
namespace RBX {
|
||||
|
||||
class JointInstance;
|
||||
class Joint;
|
||||
class Primitive;
|
||||
class Clump;
|
||||
class Assembly;
|
||||
class Region2;
|
||||
class PartInstance;
|
||||
|
||||
namespace Profiling
|
||||
{
|
||||
class CodeProfiler;
|
||||
}
|
||||
|
||||
struct RootPrimitiveOwnershipData
|
||||
{
|
||||
RBX::SystemAddress ownerAddress;
|
||||
bool ownershipManual;
|
||||
Primitive* prim;
|
||||
};
|
||||
|
||||
class Edge;
|
||||
class Contact;
|
||||
class MotorJoint;
|
||||
|
||||
// In Assembly.cpp
|
||||
void notifyAssemblyPrimitiveMoved(Primitive* p, bool resetContacts);
|
||||
|
||||
class EThrottle {
|
||||
public:
|
||||
typedef enum { ThrottleDefaultAuto, ThrottleDisabled, ThrottleAlways, Skip2, Skip4, Skip8, Skip16} EThrottleType;
|
||||
|
||||
private:
|
||||
int requestedSkip;
|
||||
int usedSkip;
|
||||
static int const throttleSetting[];
|
||||
int throttleIndex;
|
||||
|
||||
public:
|
||||
static EThrottleType globalDebugEThrottle;
|
||||
|
||||
EThrottle();
|
||||
|
||||
bool computeThrottle(int step);
|
||||
|
||||
bool increaseLoad(bool increase);
|
||||
|
||||
float getEnvironmentSpeed() const;
|
||||
|
||||
int getThrottleIndex() const { return throttleIndex; }
|
||||
|
||||
void setThrottleIndex(int index) { throttleIndex = index; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
class World
|
||||
{
|
||||
friend class ContactManager;
|
||||
public:
|
||||
rbx::signal<void(Joint*, Primitive*, std::vector<Primitive*>&)> postInsertJointSignal;
|
||||
rbx::signal<void(Joint*, std::vector<Primitive*>&, std::vector<Primitive*>&)> postRemoveJointSignal;
|
||||
rbx::signal<void(Joint*)> autoJoinSignal;
|
||||
rbx::signal<void(Joint*)> autoDestroySignal;
|
||||
rbx::signal<void(std::pair<Primitive*, Primitive*>)> primitiveCollideSignal;
|
||||
|
||||
struct TouchInfo
|
||||
{
|
||||
Primitive* p1;
|
||||
Primitive* p2;
|
||||
shared_ptr<PartInstance> pi1;
|
||||
shared_ptr<PartInstance> pi2;
|
||||
typedef enum { Touch, Untouch } Type;
|
||||
Type type;
|
||||
};
|
||||
|
||||
struct OnPrimitiveMovingVisitor
|
||||
{
|
||||
ContactManager* ptr;
|
||||
OnPrimitiveMovingVisitor(ContactManager* p) : ptr(p) { }
|
||||
void operator()(Primitive* p) {
|
||||
notifyAssemblyPrimitiveMoved(p, true);
|
||||
ptr->onPrimitiveExtentsChanged(p);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
int frmThrottle;
|
||||
EThrottle eThrottle;
|
||||
|
||||
G3D::Array<TouchInfo> touchReporting;
|
||||
|
||||
bool inStepCode; // debugging
|
||||
Joint* inJointNotification;
|
||||
|
||||
int worldSteps;
|
||||
int worldStepId; // two years at 1/30 second dt
|
||||
float worldStepAccumulated; // Time unaccounted for in the last step
|
||||
|
||||
HeapValue<float> fallenPartDestroyHeight;
|
||||
|
||||
// defining objects
|
||||
IndexArray<Primitive, &Primitive::worldIndexFunc> primitives;
|
||||
Primitive* groundPrimitive; // for now, only used by kernel joints
|
||||
|
||||
btCollisionDispatcher* bulletDispatcher;
|
||||
btDefaultCollisionConfiguration* bulletCollisionConfiguration;
|
||||
|
||||
// Generates unique ids for objects registered with this World
|
||||
boost::uint64_t UIDGenerator;
|
||||
bool usingPGSSolver;
|
||||
bool physicsAnalyzerEnabled;
|
||||
|
||||
// Material Properties
|
||||
PhysicalPropertiesMode physicalMaterialsMode;
|
||||
|
||||
// Networked Interpolation Sync
|
||||
Time lastFrameTimeStamp; // Timestamp of current frame beginning
|
||||
Time lastSendTimeStamp; // Timestamp of the frame where we last sent physics
|
||||
int lastNumWorldSteps;
|
||||
double worldStepOffset;
|
||||
|
||||
public:
|
||||
float getUpdateExpectedStepDelta();
|
||||
|
||||
btCollisionDispatcher* getBulletCollisionDispatcher(void) { return bulletDispatcher; }
|
||||
|
||||
private:
|
||||
|
||||
// redundant data
|
||||
G3D::Array<Primitive*> movingPrimitives;
|
||||
std::set<Joint*> breakableJoints;
|
||||
int numJoints;
|
||||
int numContacts;
|
||||
int numLinkCalls;
|
||||
|
||||
// motion analytic
|
||||
double errorCount;
|
||||
double passCount;
|
||||
double frameinfosSize;
|
||||
double frameinfosTarget;
|
||||
double targetDelayTenths;
|
||||
double infosSizeTenths;
|
||||
double maxDelta;
|
||||
double frameinfosCount;
|
||||
|
||||
|
||||
// redundant data - performance - prevent allocation
|
||||
G3D::Array<Primitive*> tempPrimitives;
|
||||
G3D::Array<boost::shared_ptr<JointInstance> > tempJoints;
|
||||
|
||||
boost::unordered_map< boost::uint64_t, Primitive* > primitiveIndexation;
|
||||
|
||||
boost::scoped_ptr<Profiling::CodeProfiler> profilingBreak;
|
||||
boost::scoped_ptr<Profiling::CodeProfiler> profilingAssembly;
|
||||
boost::scoped_ptr<Profiling::CodeProfiler> profilingFilter;
|
||||
boost::scoped_ptr<Profiling::CodeProfiler> profilingWorldStep;
|
||||
boost::scoped_ptr<Profiling::CodeProfiler> profilingUiStep;
|
||||
|
||||
void createAutoJoints(Primitive* p, std::set<Primitive*>* ignoreGroup, std::set<Primitive*>* joinGroup); // if joinGroup, only connect with them
|
||||
void destroyAutoJoints(Primitive* p, std::set<Primitive*>* ignoreGroup, bool includeExplicit = true, bool includeAuto = true); // if group, then keep joints between group members
|
||||
|
||||
void destroyJoint(Joint* j);
|
||||
|
||||
void removeFromBreakable(Joint* j);
|
||||
|
||||
// these functions are in the main world->step() loop
|
||||
void doBreakJoints(); // goes through the breakableJoints, breaks if necessary;
|
||||
|
||||
void uiStep(bool longStep, double distributedGameTime);
|
||||
void doWorldStep(bool throttling, int uiStepId, int numThreads, boost::uint64_t debugTime);
|
||||
|
||||
void notifyMovingAssemblies();
|
||||
|
||||
ContactManager* contactManager;
|
||||
class SendPhysics* sendPhysics;
|
||||
class CleanStage* cleanStage;
|
||||
|
||||
class GroundStage* getGroundStage();
|
||||
class SleepStage* getSleepStage();
|
||||
class TreeStage* getTreeStage();
|
||||
const class SpatialFilter* getSpatialFilter() const;
|
||||
class AssemblyStage* getAssemblyStage();
|
||||
const AssemblyStage* getAssemblyStage() const;
|
||||
class MovingAssemblyStage* getMovingAssemblyStage();
|
||||
class StepJointsStage* getStepJointsStage();
|
||||
const StepJointsStage* getStepJointsStage() const;
|
||||
const class SleepStage* getSleepStage() const;
|
||||
class SimulateStage* getSimulateStage();
|
||||
|
||||
public:
|
||||
World();
|
||||
~World();
|
||||
|
||||
void assertNotInStep() { RBXASSERT(!inStepCode); }
|
||||
void assertInStep() { RBXASSERT(inStepCode); }
|
||||
|
||||
class SendPhysics* getSendPhysics();
|
||||
class SimSendFilter& getSimSendFilter();
|
||||
SpatialFilter* getSpatialFilter();
|
||||
ContactManager* getContactManager() {return contactManager;}
|
||||
const ContactManager* getContactManager() const {return contactManager;}
|
||||
class HumanoidStage* getHumanoidStage();
|
||||
class Kernel* getKernel();
|
||||
const Kernel* getKernel() const;
|
||||
|
||||
const G3D::Array<TouchInfo>& getTouchInfoFromLastStep() {return touchReporting;}
|
||||
void clearTouchInfoFromLastStep() {touchReporting.fastClear();}
|
||||
|
||||
void computeFallen(G3D::Array<Primitive*>& fallen) const;
|
||||
|
||||
const G3D::Array<Primitive*>& getPrimitives() const {return primitives.underlyingArray();}
|
||||
|
||||
// engine interface
|
||||
int updateStepsRequiredForCyclicExecutive(float desiredInterval);
|
||||
float step(bool longStep, double distributedGameTime, float desiredInterval, int numThreads); // 10-100 frames per second
|
||||
void assemble(); // on heartbeat, before collision detection
|
||||
bool isAssembled();
|
||||
void reset() {RBXASSERT(!inStepCode); worldStepId = 0;}
|
||||
int getWorldStepId() {return worldStepId;}
|
||||
float getWorldStepsAccumulated() { return worldStepAccumulated; }
|
||||
int getUiStepId();
|
||||
int getLongUiStepId();
|
||||
void sendClumpChangedMessage(Primitive* childPrim);
|
||||
|
||||
EThrottle& getEThrottle() {return eThrottle;}
|
||||
int getFRMThrottle() { return frmThrottle;}
|
||||
void setFRMThrottle(int value);
|
||||
|
||||
Primitive* getGroundPrimitive() {return groundPrimitive;}
|
||||
|
||||
// PRIMITIVE - Runtime geometry manipulation
|
||||
void insertPrimitive(Primitive* p);
|
||||
void removePrimitive(Primitive* p, bool isStreamingRemove);
|
||||
void ticklePrimitive(Primitive* p, bool recursive); // simulates a touch, wakes up
|
||||
Primitive* getPrimitiveFromBodyUID( boost::uint64_t uid ) const;
|
||||
|
||||
// Auto Joining / Unjoining functions
|
||||
void joinAll();
|
||||
|
||||
void createAutoJoints(Primitive* p);
|
||||
void createAutoJointsToWorld(const G3D::Array<Primitive*>& primitives); // ignores joints between them
|
||||
void createAutoJointsToPrimitives(const G3D::Array<Primitive*>& primitives); // only join each other in this group
|
||||
|
||||
void destroyAutoJoints(Primitive* p, bool includeExplicit = true);
|
||||
void destroyAutoJointsToWorld(const G3D::Array<Primitive*>& primitives); // ignores joints between them
|
||||
|
||||
void destroyTerrainWeldJointsWithEmptyCells(Primitive* megaClusterPrim, const SpatialRegion::Id& region, Primitive* touchingPrim);
|
||||
void destroyTerrainWeldJointsNoTouch(Primitive* megaClusterPrim, Primitive* touchingPrim);
|
||||
|
||||
// Joint based insert, remove
|
||||
void insertJoint(Joint* j);
|
||||
void removeJoint(Joint* j);
|
||||
void jointCoordsChanged(Joint* j);
|
||||
void notifyMoved(Primitive* p);
|
||||
|
||||
// Network Ownership API Data Gatherer
|
||||
void gatherMechDataPreJoin(Joint *j, Primitive*& unGroundedPrim, std::vector<Primitive*>& combiningRoots);
|
||||
void gatherMechDataPreSplit(Joint* j, std::vector<Primitive*>& prim0ChildRoots, std::vector<Primitive*>& prim1Roots);
|
||||
|
||||
// CONTACT MANAGER - Can only be called by the contact manager;
|
||||
void insertContact(Contact* c);
|
||||
void destroyContact(Contact* c);
|
||||
|
||||
// inquiry functions
|
||||
int getMetric(IWorldStage::MetricType metricType) const;
|
||||
int getNumBodies() const;
|
||||
int getNumPoints() const;
|
||||
int getNumConstraints() const;
|
||||
int getNumHashNodes() const;
|
||||
int getMaxBucketSize() const;
|
||||
int getNumLinkCalls() const {return numLinkCalls;}
|
||||
int getNumContacts() const {return numContacts;}
|
||||
int getNumJoints() const {return numJoints;}
|
||||
int getNumPrimitives() const {return getPrimitives().size();}
|
||||
float getEnvironmentSpeed() const {return eThrottle.getEnvironmentSpeed();}
|
||||
float getEnvironmentSpeedPercent() const {return getEnvironmentSpeed() * 100.0f;}
|
||||
|
||||
void setFallenPartDestroyHeight(float value) {fallenPartDestroyHeight = value;}
|
||||
float getFallenPartDestroyHeight() const {return fallenPartDestroyHeight;}
|
||||
|
||||
RBX::Profiling::CodeProfiler& getProfileWorldStep() { return *profilingWorldStep; }
|
||||
const RBX::Profiling::CodeProfiler& getProfileWorldStep() const { return *profilingWorldStep; }
|
||||
|
||||
void loadProfilers(std::vector<RBX::Profiling::CodeProfiler*>& worldProfilers) const;
|
||||
|
||||
// PRIMITIVE - notification on edits - only called by Primitive or Clump
|
||||
Assembly* onPrimitiveEngineChanging(Primitive* p);
|
||||
void onPrimitiveEngineChanged(Assembly* changing);
|
||||
|
||||
void onPrimitiveFixedChanging(Primitive* p);
|
||||
void onPrimitiveFixedChanged(Primitive* p);
|
||||
|
||||
void onPrimitivePreventCollideChanged(Primitive* p);
|
||||
void onPrimitiveExtentsChanged(Primitive* p);
|
||||
void onPrimitiveContactParametersChanged(Primitive* p);
|
||||
void onPrimitiveGeometryChanged(Primitive* p);
|
||||
void reportTouchInfo(const TouchInfo& info);
|
||||
void reportTouchInfo(Primitive* p0, Primitive* p1, World::TouchInfo::Type T);
|
||||
|
||||
void onPrimitiveCollided(Primitive* p0, Primitive* p1);
|
||||
|
||||
void onAssemblyPhysicsChanged(Assembly* a, bool physics) const;
|
||||
void onAssemblyInSimluationStage(Assembly* a);
|
||||
|
||||
// JOINT - notification on edits - only called by Joint
|
||||
void onJointPrimitiveNulling(Joint* j, Primitive* p);
|
||||
void onJointPrimitiveSet(Joint* j, Primitive* p);
|
||||
|
||||
void addAnimatedJointToMovingAssemblyStage(Joint* j);
|
||||
void removeAnimatedJointFromMovingAssemblyStage(Joint* j);
|
||||
|
||||
bool getUsingPGSSolver();
|
||||
void setUsingPGSSolver(bool usePGS);
|
||||
void setUserId( int id );
|
||||
|
||||
void setPhysicsAnalyzerEnabled(bool value) { physicsAnalyzerEnabled = value; }
|
||||
|
||||
bool getUsingNewPhysicalProperties() const;
|
||||
|
||||
PhysicalPropertiesMode getPhysicalPropertiesMode() const { return physicalMaterialsMode; }
|
||||
void setPhysicalPropertiesMode(PhysicalPropertiesMode mode);
|
||||
|
||||
// motion analytic
|
||||
void plusErrorCount(double ec) { errorCount += ec;}
|
||||
void plusPassCount(double pc) { passCount += pc; }
|
||||
double getPassCount() {return passCount; }
|
||||
void sendAnalytics(void);
|
||||
void addFrameinfosStat(double fis, double fit, double tdt, double ist, double md, double fic);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
Reference in New Issue
Block a user