mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-04 20:57:49 +00:00
235 lines
6.7 KiB
C++
235 lines
6.7 KiB
C++
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
|
#include "stdafx.h"
|
|
|
|
#include "V8World/GlueJoint.h"
|
|
#include "V8World/Primitive.h"
|
|
#include "V8World/Tolerance.h"
|
|
#include "V8Kernel/Kernel.h"
|
|
#include "V8Kernel/Constants.h"
|
|
#include "V8Kernel/Connector.h"
|
|
#include "V8Kernel/Body.h"
|
|
#include "v8kernel/Point.h"
|
|
#include "solver/Constraint.h"
|
|
|
|
FASTFLAGVARIABLE(PGSGlueJoint, false)
|
|
DYNAMIC_FASTFLAG(OrthonormalizeJointCoords)
|
|
|
|
namespace RBX {
|
|
|
|
GlueJoint::GlueJoint()
|
|
: MultiJoint(4)
|
|
{}
|
|
|
|
GlueJoint::GlueJoint(
|
|
Primitive* p0,
|
|
Primitive* p1,
|
|
const CoordinateFrame& jointCoord0,
|
|
const CoordinateFrame& jointCoord1,
|
|
const Face& faceInJointSpace)
|
|
: MultiJoint(p0, p1, jointCoord0, jointCoord1, 4)
|
|
, faceInJointSpace(faceInJointSpace)
|
|
{}
|
|
|
|
|
|
GlueJoint* GlueJoint::canBuildJoint(
|
|
Primitive* p0,
|
|
Primitive* p1,
|
|
NormalId nId0,
|
|
NormalId nId1)
|
|
{
|
|
// 1. Surfaces
|
|
if (!compatibleSurfaces(p0, p1, nId0, nId1)) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!Joint::canBuildJointLoose(p0, p1, nId0, nId1)) {
|
|
return NULL;
|
|
}
|
|
|
|
Face f0 = p0->getFaceInWorld(nId0);
|
|
Face f1 = p1->getFaceInWorld(nId1);
|
|
|
|
Face overlapOn0World = f0.projectOverlapOnMe(f1);
|
|
Face overlapOn1World = f1.projectOverlapOnMe(f0);
|
|
|
|
Face offsetInP0 = overlapOn0World.toObjectSpace(p0->getCoordinateFrame());
|
|
Face offsetInP1 = overlapOn1World.toObjectSpace(p1->getCoordinateFrame());
|
|
|
|
Face snappedOffsetInP0 = offsetInP0;
|
|
Face snappedOffsetInP1 = offsetInP1;
|
|
|
|
snappedOffsetInP0.snapToGrid(Tolerance::mainGrid());
|
|
snappedOffsetInP1.snapToGrid(Tolerance::mainGrid());
|
|
|
|
Face offset0World = snappedOffsetInP0.toWorldSpace(p0->getCoordinateFrame());
|
|
Face offset1World = snappedOffsetInP1.toWorldSpace(p1->getCoordinateFrame());
|
|
|
|
if (! Face::cornersAligned(offset0World, offset1World, Tolerance::jointMaxUnaligned()) ) {
|
|
// try once more, without rounding
|
|
offset0World = offsetInP0.toWorldSpace(p0->getCoordinateFrame());
|
|
offset1World = offsetInP1.toWorldSpace(p1->getCoordinateFrame());
|
|
|
|
if (! Face::cornersAligned(offset0World, offset1World, Tolerance::jointMaxUnaligned()) )
|
|
return NULL;
|
|
}
|
|
|
|
CoordinateFrame jointCoord0 = p0->getFaceCoordInObject(nId0);
|
|
if (DFFlag::OrthonormalizeJointCoords)
|
|
Math::orthonormalizeIfNecessary(jointCoord0.rotation);
|
|
CoordinateFrame jointCoord0InWorld = p0->getCoordinateFrame() * jointCoord0;
|
|
CoordinateFrame jc0InP1 = p1->getCoordinateFrame().toObjectSpace(jointCoord0InWorld);
|
|
CoordinateFrame jointCoord1 = Math::snapToGrid(jc0InP1, Tolerance::mainGrid());
|
|
if (DFFlag::OrthonormalizeJointCoords)
|
|
Math::orthonormalizeIfNecessary(jointCoord1.rotation);
|
|
|
|
Face faceInJointSpace = offsetInP0.toObjectSpace(jointCoord0);
|
|
|
|
return new GlueJoint(p0, p1, jointCoord0, jointCoord1, faceInJointSpace);
|
|
}
|
|
|
|
bool GlueJoint::compatibleSurfaces(
|
|
Primitive* p0,
|
|
Primitive* p1,
|
|
NormalId nId0,
|
|
NormalId nId1)
|
|
{
|
|
SurfaceType t0 = p0->getSurfaceType(nId0);
|
|
SurfaceType t1 = p1->getSurfaceType(nId1);
|
|
|
|
// Compatible surfaces
|
|
bool answer = ((t0 == GLUE) || (t1 == GLUE));
|
|
return answer;
|
|
}
|
|
|
|
|
|
float GlueJoint::getMaxForce()
|
|
{
|
|
Vector2 overlap = faceInJointSpace.size();
|
|
float maxKmsForce = Constants::getKmsMaxJointForce(overlap.x, overlap.y); // max force is for one row thick...
|
|
return Units::kmsForceToRbx(maxKmsForce);
|
|
}
|
|
|
|
void GlueJoint::putInKernel(Kernel* _kernel)
|
|
{
|
|
Super::putInKernel(_kernel);
|
|
|
|
Body* b0 = getPrimitive(0)->getBody();
|
|
Body* b1 = getPrimitive(1)->getBody();
|
|
|
|
NormalId nId0 = getNormalId(0);
|
|
|
|
Face overlapInP0 = faceInJointSpace.toWorldSpace(jointCoord0);
|
|
Face overlapInP1 = faceInJointSpace.toWorldSpace(jointCoord1); // moving from Joint1 space to P1 space (object to world space)
|
|
|
|
if( FFlag::PGSGlueJoint && _kernel->getUsingPGSSolver() )
|
|
{
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
ConstraintBallInSocket* ballInSocket = new ConstraintBallInSocket( b0, b1 );
|
|
ballInSocket->setPivotA( overlapInP0[i] );
|
|
ballInSocket->setPivotB( overlapInP1[i] );
|
|
_kernel->pgsSolver.addConstraint(ballInSocket);
|
|
constraints.push_back(ballInSocket);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
Point* point0 = getKernel()->newPointLocal(b0, overlapInP0[i]);
|
|
Point* point1 = getKernel()->newPointLocal(b1, overlapInP1[i]);
|
|
Connector* connector = new NormalBreakConnector(point0,
|
|
point1,
|
|
getJointK(),
|
|
getMaxForce(),
|
|
nId0);
|
|
addToMultiJoint(point0, point1, connector);
|
|
}
|
|
}
|
|
}
|
|
|
|
void GlueJoint::removeFromKernel()
|
|
{
|
|
if( FFlag::PGSGlueJoint && getKernel()->getUsingPGSSolver() )
|
|
{
|
|
for(Constraint* c : constraints)
|
|
{
|
|
getKernel()->pgsSolver.removeConstraint(c);
|
|
delete c;
|
|
}
|
|
constraints.clear();
|
|
}
|
|
|
|
Super::removeFromKernel();
|
|
}
|
|
|
|
bool GlueJoint::isBroken() const
|
|
{
|
|
if( FFlag::PGSGlueJoint && inKernel() && getKernel()->getUsingPGSSolver() )
|
|
{
|
|
for(Constraint* c : constraints)
|
|
{
|
|
if( c->isBroken() )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return Super::isBroken();
|
|
}
|
|
}
|
|
|
|
void ManualGlueJoint::putInKernel(Kernel* kernel)
|
|
{
|
|
computeIntersectingSurfacePoints();
|
|
Super::putInKernel(kernel);
|
|
}
|
|
|
|
void ManualGlueJoint::computeIntersectingSurfacePoints(void)
|
|
{
|
|
const Primitive* p0 = getPrimitive(0);
|
|
const Primitive* p1 = getPrimitive(1);
|
|
int s0 = getSurface0();
|
|
int s1 = getSurface1();
|
|
RBXASSERT(s0 != -1 && s1 != -1);
|
|
|
|
// Must have valid parts and surfaces
|
|
if(p0 && p1 && (s0 != -1) && (s1 != -1))
|
|
{
|
|
// Reset the joint coords
|
|
CoordinateFrame c0 = p0->getConstGeometry()->getSurfaceCoordInBody(s0);
|
|
CoordinateFrame worldC = p0->getCoordinateFrame() * c0;
|
|
CoordinateFrame c1 = p1->getCoordinateFrame().toObjectSpace(worldC);
|
|
setJointCoord(0, c0);
|
|
setJointCoord(1, c1);
|
|
|
|
// set the first 4 face points
|
|
// TO DO: this must be generalized to handle n-polygon faces
|
|
// currently the joint class that are inherited are limited to 4
|
|
std::vector<Vector3> polygon1;
|
|
for( int i = 0; i < p1->getConstGeometry()->getNumVertsInSurface(s1); i++ )
|
|
{
|
|
Vector3 p1VertInWorld = p1->getCoordinateFrame().pointToWorldSpace(p1->getConstGeometry()->getSurfaceVertInBody(s1, i));
|
|
polygon1.push_back(p0->getCoordinateFrame().pointToObjectSpace(p1VertInWorld));
|
|
}
|
|
|
|
std::vector<Vector3> intersectPolyInP0 = p0->getConstGeometry()->polygonIntersectionWithFace(polygon1, s0);
|
|
|
|
int intersections = intersectPolyInP0.size();
|
|
int numFacePoints = std::min(intersections, 4);
|
|
const CoordinateFrame jCoord0 = getJointCoord(0);
|
|
for( int i = 0; i < numFacePoints; i++ )
|
|
{
|
|
Vector3 facePointInC0 = jCoord0.pointToObjectSpace(intersectPolyInP0[i]);
|
|
setFacePoint(i, facePointInC0);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|