Files
2025-09-18 17:55:52 -04:00

328 lines
8.4 KiB
C++

/* 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