This commit is contained in:
watrabi
2025-09-18 17:55:52 -04:00
commit 977f1ff4b8
15030 changed files with 17324420 additions and 0 deletions
+220
View File
@@ -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
+44
View File
@@ -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
+37
View File
@@ -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
+70
View File
@@ -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
+46
View File
@@ -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
+44
View File
@@ -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
+139
View File
@@ -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
+41
View File
@@ -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
+25
View File
@@ -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
+83
View File
@@ -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
+55
View File
@@ -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
+181
View File
@@ -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; }
};
}
+88
View File
@@ -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
+49
View File
@@ -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
+63
View File
@@ -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
+327
View File
@@ -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
+209
View File
@@ -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);
};
}
+30
View File
@@ -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
+29
View File
@@ -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
+31
View File
@@ -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
+43
View File
@@ -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
+58
View File
@@ -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
+17
View File
@@ -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
};
}
}
+122
View File
@@ -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
+46
View File
@@ -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
+32
View File
@@ -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
+54
View File
@@ -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
+58
View File
@@ -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
+129
View File
@@ -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
+231
View File
@@ -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
+89
View File
@@ -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
+53
View File
@@ -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
+35
View File
@@ -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
+97
View File
@@ -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
+88
View File
@@ -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
+48
View File
@@ -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
+243
View File
@@ -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
+19
View File
@@ -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
+52
View File
@@ -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
+82
View File
@@ -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;
};
}
+43
View File
@@ -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
+43
View File
@@ -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
+33
View File
@@ -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
+73
View File
@@ -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
+31
View File
@@ -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
+86
View File
@@ -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
+280
View File
@@ -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
+61
View File
@@ -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
+59
View File
@@ -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
+71
View File
@@ -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
+34
View File
@@ -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
+63
View File
@@ -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
+31
View File
@@ -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
+30
View File
@@ -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
+71
View File
@@ -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
+158
View File
@@ -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
+47
View File
@@ -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
+157
View File
@@ -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
+430
View File
@@ -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;
};
}
+40
View File
@@ -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
+44
View File
@@ -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
+40
View File
@@ -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
+43
View File
@@ -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
+31
View File
@@ -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
+32
View File
@@ -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
+55
View File
@@ -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
+173
View File
@@ -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
+97
View File
@@ -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
+67
View File
@@ -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
+63
View File
@@ -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
+169
View File
@@ -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
+40
View File
@@ -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
+102
View File
@@ -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 --- doesnt step --- NO --- doesnt 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
+435
View File
@@ -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
+45
View File
@@ -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
+32
View File
@@ -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
+101
View File
@@ -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
+59
View File
@@ -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
+94
View File
@@ -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
+163
View File
@@ -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 &currentVersion, 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
+29
View File
@@ -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
+42
View File
@@ -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
+67
View File
@@ -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
+353
View File
@@ -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