/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */ #include "stdafx.h" #include "V8DataModel/ManualJointHelper.h" #include "GfxBase/IAdornableCollector.h" #include "V8World/World.h" #include "Tool/DragUtilities.h" #include "V8World/ContactManager.h" #include "V8World/Contact.h" #include "V8World/Joint.h" #include "V8World/WeldJoint.h" #include "V8World/MegaClusterPoly.h" #include "Tool/ToolsArrow.h" #include "Humanoid/Humanoid.h" #include "V8DataModel/Workspace.h" #include "V8DataModel/PartInstance.h" #include "V8DataModel/PVInstance.h" #include "V8DataModel/JointInstance.h" #include "V8DataModel/MegaCluster.h" namespace RBX { const float autoJointLineThickness = 0.1f; ManualJointHelper::~ManualJointHelper() { if( workspace && isAdornable ) workspace->getAdornableCollector()->onRenderableDescendantRemoving(this); // Clear the existing part/surface pairs containers for( unsigned int i = 0; i < jointSurfacePairs.size(); i++ ) delete jointSurfacePairs[i]; jointSurfacePairs.clear(); autoJointsDetected = false; } ManualJointHelper::ManualJointHelper(Workspace* ws) { workspace = NULL; displayPotentialJoints = AdvArrowTool::advManualJointMode; isAdornable = false; autoJointsDetected = false; targetPrimitive = NULL; setWorkspace(ws); } ManualJointHelper::ManualJointHelper(void) { workspace = NULL; displayPotentialJoints = AdvArrowTool::advManualJointMode; isAdornable = false; autoJointsDetected = false; targetPrimitive = NULL; } void ManualJointHelper::clearAndDeleteJointSurfacePairs(void) { // Clear the existing part/surface pairs containers for( unsigned int i = 0; i < jointSurfacePairs.size(); i++ ) delete jointSurfacePairs[i]; jointSurfacePairs.clear(); autoJointsDetected = false; } void ManualJointHelper::setWorkspace(Workspace* ws) { if( !workspace ) { workspace = ws; if( !isAdornable ) { workspace->getAdornableCollector()->onRenderableDescendantAdded(this); isAdornable = true; } } } void ManualJointHelper::findPermissibleJointSurfacePairs(void) { // Clear the existing part/surface pairs containers clearAndDeleteJointSurfacePairs(); // find other parts that are contacting the selected parts for( unsigned int i = 0; i < selectedPrimitives.size(); i++ ) { G3D::Array found; size_t selectedPrimSurf = (size_t)-1; size_t foundPrimSurf = (size_t)-1; if(workspace) { workspace->getWorld()->getContactManager()->getPrimitivesTouchingExtents(selectedPrimitives[i]->getFastFuzzyExtents(), selectedPrimitives[i], 0, found); for( int j = 0; j < found.size(); j++ ) { if( !selectedPrimitives[i]->getGeometry()->isTerrain() ) { if( std::find(selectedPrimitives.begin(), selectedPrimitives.end(), found[j])== selectedPrimitives.end() ) { if( found[j]->getConstGeometry()->findTouchingSurfacesConvex(found[j]->getCoordinateFrame(), foundPrimSurf, *(selectedPrimitives[i]->getConstGeometry()), selectedPrimitives[i]->getCoordinateFrame(), selectedPrimSurf) ) createJointSurfacePair(*found[j], foundPrimSurf, *selectedPrimitives[i], selectedPrimSurf); } } } } } // add in joints with the terrain Primitive* mCPrim = workspace->getWorld()->getContactManager()->getMegaClusterPrimitive(); if (mCPrim && mCPrim->getGeometryType() == Geometry::GEOMETRY_MEGACLUSTER) { for( unsigned int i = 0; i < selectedPrimitives.size(); i++ ) { if( selectedPrimitives[i]->getGeometryType() != RBX::Geometry::GEOMETRY_MEGACLUSTER ) { std::vector cells; static_cast(mCPrim->getConstGeometry())->findPlanarTouchesWithGeom(mCPrim->getCoordinateFrame(), *(selectedPrimitives[i]->getConstGeometry()), selectedPrimitives[i]->getCoordinateFrame(), &cells); // for each cell call createJointSurfacePair for(size_t j = 0; j < cells.size(); ++j) { createTerrainJointSurfacePair(*mCPrim, *selectedPrimitives[i], cells[j]); } } } } if (mCPrim && mCPrim->getGeometryType() == Geometry::GEOMETRY_SMOOTHCLUSTER) { for( unsigned int i = 0; i < selectedPrimitives.size(); i++ ) { Geometry::GeometryType geometryType = selectedPrimitives[i]->getGeometryType(); if (geometryType != Geometry::GEOMETRY_SMOOTHCLUSTER && geometryType != Geometry::GEOMETRY_BALL) { if (ManualWeldJoint::isTouchingTerrain(mCPrim, selectedPrimitives[i])) createSmoothTerrainJointSurfacePair(*mCPrim, *selectedPrimitives[i]); } } } } void ManualJointHelper::createTerrainJointSurfacePair(Primitive& p0, Primitive& p1, Vector3int16& cellIndex) { PartInstance* part0 = PartInstance::fromPrimitive(&p0); RBXASSERT(part0->getParent()); PartInstance* part1 = PartInstance::fromPrimitive(&p1); RBXASSERT(part1->getParent()); ConstraintSurfacePair* aPair = NULL; RBXASSERT( p1.getConstGeometry()->getGeometryType() != RBX::Geometry::GEOMETRY_MEGACLUSTER ); size_t fix = -1; // need to check if p1 is about to be joined to a no_join cell! const MegaClusterPoly* terrainPoly = static_cast(p0.getConstGeometry()); size_t otherFaceId; std::vector intersectPolyInP0 = terrainPoly->findCellIntersectionWithGeom( cellIndex, p0.getCoordinateFrame(), *(p1.getConstGeometry()), p1.getCoordinateFrame(), otherFaceId); SurfaceType t1 = Joint::getSurfaceTypeFromNormal(p1, (NormalId)otherFaceId); if ( t1 == NO_JOIN ) { DisallowedTerrainJointSurfacePair* pair = new DisallowedTerrainJointSurfacePair(p0, fix, p1, otherFaceId); pair->setCellIndex(cellIndex); aPair = pair; } else { TerrainManualJointSurfacePair* pair = new TerrainManualJointSurfacePair(p0, fix, p1, fix); pair->setCellIndex(cellIndex); aPair = pair; } jointSurfacePairs.push_back(aPair); aPair->p0AncestorChangedConnection = part0->ancestryChangedSignal.connect(boost::bind(&ManualJointHelper::onPartAncestryChanged, this, _1, _2)); aPair->p1AncestorChangedConnection = part1->ancestryChangedSignal.connect(boost::bind(&ManualJointHelper::onPartAncestryChanged, this, _1, _2)); } void ManualJointHelper::createSmoothTerrainJointSurfacePair(Primitive& p0, Primitive& p1) { PartInstance* part0 = PartInstance::fromPrimitive(&p0); RBXASSERT(part0->getParent()); PartInstance* part1 = PartInstance::fromPrimitive(&p1); RBXASSERT(part1->getParent()); size_t fix = -1; SmoothTerrainManualJointSurfacePair* pair = new SmoothTerrainManualJointSurfacePair(p0, fix, p1, fix); jointSurfacePairs.push_back(pair); pair->p0AncestorChangedConnection = part0->ancestryChangedSignal.connect(boost::bind(&ManualJointHelper::onPartAncestryChanged, this, _1, _2)); pair->p1AncestorChangedConnection = part1->ancestryChangedSignal.connect(boost::bind(&ManualJointHelper::onPartAncestryChanged, this, _1, _2)); } bool ManualJointHelper::surfaceIsNoJoin(const Primitive& p0, size_t& face0Id, const Primitive& p1, size_t& face1Id) { SurfaceType t0 = Joint::getSurfaceTypeFromNormal(p0, (NormalId)face0Id); SurfaceType t1 = Joint::getSurfaceTypeFromNormal(p1, (NormalId)face1Id); return ( t0 == NO_JOIN || t1 == NO_JOIN ); } void ManualJointHelper::createJointSurfacePair(Primitive& p0, size_t& face0Id, Primitive& p1, size_t& face1Id) { PartInstance* part0 = PartInstance::fromPrimitive(&p0); RBXASSERT(part0->getParent()); PartInstance* part1 = PartInstance::fromPrimitive(&p1); RBXASSERT(part1->getParent()); ConstraintSurfacePair* aPair = NULL; // First check if either part is associated with a humanoid (body part or child gear, hat, etc) // If so, no joint allowed const Instance* parent0 = PartInstance::fromConstPrimitive(&p0)->getParent(); const Humanoid* aHumanoidModel0 = NULL; while( parent0 && !aHumanoidModel0 ) { aHumanoidModel0 = Humanoid::modelIsConstCharacter(parent0); parent0 = parent0->getParent(); } const Instance* parent1 = PartInstance::fromConstPrimitive(&p1)->getParent(); const Humanoid* aHumanoidModel1 = NULL; while( parent1 && !aHumanoidModel1 && !aHumanoidModel0 ) // don't bother walking p1's tree if we already found a character { aHumanoidModel1 = Humanoid::modelIsConstCharacter(parent1); parent1 = parent1->getParent(); } if( aHumanoidModel0 || aHumanoidModel1 || surfaceIsNoJoin(p0, face0Id, p1, face1Id) ) // also disallow if either surface type is NO_JOIN aPair = new DisallowedJointSurfacePair(p0, face0Id, p1, face1Id); else { RBXASSERT( p1.getConstGeometry()->getGeometryType() != RBX::Geometry::GEOMETRY_MEGACLUSTER ); if( p0.getConstGeometry()->getGeometryType() == RBX::Geometry::GEOMETRY_MEGACLUSTER ) aPair = new TerrainManualJointSurfacePair(p0, face0Id, p1, face1Id); else if( Joint::compatibleForStudAutoJoint(p0, face0Id, p1, face1Id) ) if(Joint::positionedForStudAutoJoint(p0, face0Id, p1, face1Id)) { aPair = new StudAutoJointSurfacePair(p0, face0Id, p1, face1Id); autoJointsDetected = true; } else #ifndef MACONLY_MANUAL_WELD_ALL_SURFACES aPair = new DisallowedJointSurfacePair(p0, face0Id, p1, face1Id); #else aPair = new ManualJointSurfacePair(p0, face0Id, p1, face1Id); #endif else if(Joint::compatibleForGlueAutoJoint(p0, face0Id, p1, face1Id)) { aPair = new GlueAutoJointSurfacePair(p0, face0Id, p1, face1Id); autoJointsDetected = true; } else if(Joint::compatibleForWeldAutoJoint(p0, face0Id, p1, face1Id)) { aPair = new WeldAutoJointSurfacePair(p0, face0Id, p1, face1Id); autoJointsDetected = true; } else if(Joint::compatibleForHingeAutoJoint(p0, face0Id, p1, face1Id)) { aPair = new HingeAutoJointSurfacePair(p0, face0Id, p1, face1Id); autoJointsDetected = true; } #ifndef MACONLY_MANUAL_WELD_ALL_SURFACES //this prevents welding of incompatible surfaces such as studs to smooth. else if(Joint::inCompatibleForAnyJoint(p0, face0Id, p1, face1Id)) aPair = new DisallowedJointSurfacePair(p0, face0Id, p1, face1Id); #endif else aPair = new ManualJointSurfacePair(p0, face0Id, p1, face1Id); } aPair->p0AncestorChangedConnection = part0->ancestryChangedSignal.connect(boost::bind(&ManualJointHelper::onPartAncestryChanged, this, _1, _2)); aPair->p1AncestorChangedConnection = part1->ancestryChangedSignal.connect(boost::bind(&ManualJointHelper::onPartAncestryChanged, this, _1, _2)); jointSurfacePairs.push_back(aPair); } void ManualJointHelper::setSelectedPrimitives(const std::vector& selectedInstances) { PartArray partInstances; DragUtilities::instancesToParts(selectedInstances, partInstances); selectedPrimitives.clear(); DragUtilities::partsToPrimitives(partInstances, selectedPrimitives); } void ManualJointHelper::setSelectedPrimitives(const Instances& selectedInstances) { PartArray partInstances; DragUtilities::instancesToParts(selectedInstances, partInstances); selectedPrimitives.clear(); DragUtilities::partsToPrimitives(partInstances, selectedPrimitives); } void ManualJointHelper::setPVInstanceToJoin(PVInstance& pVInstToJoin) { std::vector pvInstances; pvInstances.push_back(&pVInstToJoin); PartArray partInstances; DragUtilities::pvsToParts(pvInstances, partInstances); selectedPrimitives.clear(); DragUtilities::partsToPrimitives(partInstances, selectedPrimitives); } void ManualJointHelper::setPVInstanceTarget(PVInstance& pVInstToJoin) { PartInstance* part = dynamic_cast(&pVInstToJoin); if(part) targetPrimitive = part->getPartPrimitive(); else targetPrimitive = NULL; } void ManualJointHelper::createJoints(void) { for( unsigned int i = 0; i < jointSurfacePairs.size(); i++ ) jointSurfacePairs[i]->createJoint(); } void ManualJointHelper::createJointsIfEnabledFromGui(void) { if(AdvArrowTool::advManualJointMode) { for( unsigned int i = 0; i < jointSurfacePairs.size(); i++ ) jointSurfacePairs[i]->createJoint(); } } void ManualJointHelper::render3dAdorn(Adorn* adorn) { for( unsigned int i = 0; i < jointSurfacePairs.size(); i++ ) { // if the target primitive is non NULL, then the client wants to only render the target body outline // Otherwise, render all surface pairs if(targetPrimitive) { if(jointSurfacePairs[i]->getP0() == targetPrimitive || jointSurfacePairs[i]->getP1() == targetPrimitive) jointSurfacePairs[i]->dynamicDraw(adorn); } else jointSurfacePairs[i]->dynamicDraw(adorn); } } void ManualJointHelper::onPartAncestryChanged(shared_ptr instance, shared_ptr newParent) { if (!newParent) { if (PartInstance* part = instance->fastDynamicCast()) { Primitive * prim = PartInstance::getPrimitive(part); if (prim == targetPrimitive) targetPrimitive = NULL; std::vector::iterator iter = jointSurfacePairs.begin(); for (; iter != jointSurfacePairs.end(); iter++) { if (prim == (*iter)->getP0() || prim == (*iter)->getP1()) { // delete pair if one of the primitive has no parent, it's being deleted delete *iter; break; } } if (iter != jointSurfacePairs.end()) jointSurfacePairs.erase(iter); } } } ConstraintSurfacePair::ConstraintSurfacePair() { p0 = NULL; p1 = NULL; s0 = (size_t)-1; s1 = (size_t)-1; } ConstraintSurfacePair::ConstraintSurfacePair(const Primitive& prim0, size_t& face0Id, const Primitive& prim1, size_t& face1Id) { p0 = &prim0; p1 = &prim1; s0 = face0Id; s1 = face1Id; } void StudAutoJointSurfacePair::dynamicDraw(Adorn* adorn) { std::vector polygon1; if( p1 && p0 && p1->getConstGeometry() && p0->getConstGeometry() && s1 != (size_t)-1 && s0 != (size_t)-1 ) { 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 intersectPolyInP0 = p0->getConstGeometry()->polygonIntersectionWithFace(polygon1, s0); DrawAdorn::polygonRelativeToCoord(adorn, p0->getCoordinateFrame(), intersectPolyInP0, Color3::blue(), autoJointLineThickness); } } void GlueAutoJointSurfacePair::dynamicDraw(Adorn* adorn) { std::vector polygon1; if( p1 && p0 && p1->getConstGeometry() && p0->getConstGeometry() && s1 != (size_t)-1 && s0 != (size_t)-1 ) { 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 intersectPolyInP0 = p0->getConstGeometry()->polygonIntersectionWithFace(polygon1, s0); DrawAdorn::polygonRelativeToCoord(adorn, p0->getCoordinateFrame(), intersectPolyInP0, Color3::blue(), autoJointLineThickness); } } void WeldAutoJointSurfacePair::dynamicDraw(Adorn* adorn) { std::vector polygon1; if( p1 && p0 && p1->getConstGeometry() && p0->getConstGeometry() && s1 != (size_t)-1 && s0 != (size_t)-1 ) { 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 intersectPolyInP0 = p0->getConstGeometry()->polygonIntersectionWithFace(polygon1, s0); DrawAdorn::polygonRelativeToCoord(adorn, p0->getCoordinateFrame(), intersectPolyInP0, Color3::blue(), autoJointLineThickness); } } void HingeAutoJointSurfacePair::dynamicDraw(Adorn* adorn) { std::vector polygon1; if( p1 && p0 && p1->getConstGeometry() && p0->getConstGeometry() && s1 != (size_t)-1 && s0 != (size_t)-1 ) { 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 intersectPolyInP0 = p0->getConstGeometry()->polygonIntersectionWithFace(polygon1, s0); DrawAdorn::polygonRelativeToCoord(adorn, p0->getCoordinateFrame(), intersectPolyInP0, Color3::blue(), autoJointLineThickness); } } void DisallowedJointSurfacePair::dynamicDraw(Adorn* adorn) { std::vector polygon1; if( p1 && p0 && p1->getConstGeometry() && p0->getConstGeometry() && s1 != (size_t)-1 && s0 != (size_t)-1 ) { 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 intersectPolyInP0 = p0->getConstGeometry()->polygonIntersectionWithFace(polygon1, s0); DrawAdorn::polygonRelativeToCoord(adorn, p0->getCoordinateFrame(), intersectPolyInP0, Color3::red(), autoJointLineThickness); } } void ManualJointSurfacePair::dynamicDraw(Adorn* adorn) { if( p1 && p0 && p1->getConstGeometry() && p0->getConstGeometry() && s1 != (size_t)-1 && s0 != (size_t)-1 ) { std::vector 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 intersectPolyInP0 = p0->getConstGeometry()->polygonIntersectionWithFace(polygon1, s0); Color3 color = AdvArrowTool::advManualJointType == DRAG::WEAK_MANUAL_JOINT ? Color3::brown() : Color3::white(); DrawAdorn::polygonRelativeToCoord(adorn, p0->getCoordinateFrame(), intersectPolyInP0, color, autoJointLineThickness); } } void ManualJointSurfacePair::createJoint(void) { PartInstance* PartInst0 = (PartInstance*)PartInstance::fromConstPrimitive(p0); PartInstance* PartInst1 = (PartInstance*)PartInstance::fromConstPrimitive(p1); if(PartInst0 && PartInst1) { if( AdvArrowTool::advManualJointType == DRAG::STRONG_MANUAL_JOINT) { shared_ptr mJoint = Creatable::create(); std::string jointPostPend = " Strong Joint"; // The joint will appear as a child of the drag part in the tree view std::string p0Name = PartInst0->getName(); std::string p1Name = PartInst1->getName(); std::string jointName = p0Name + "-to-" + p1Name + jointPostPend; mJoint->setName(jointName); mJoint->setPart0(PartInst0); mJoint->setPart1(PartInst1); CoordinateFrame c0 = p0->getConstGeometry()->getSurfaceCoordInBody(s0); CoordinateFrame worldC = p0->getCoordinateFrame() * c0; CoordinateFrame c1 = p1->getCoordinateFrame().toObjectSpace(worldC); mJoint->setC0(c0); mJoint->setC1(c1); mJoint->setSurface0(s0); mJoint->setSurface1(s1); mJoint->setParent(PartInst0); } else { shared_ptr mJoint = Creatable::create(); std::string jointPostPend = " Glue Joint"; // The joint will appear as a child of the drag part in the tree view std::string p0Name = PartInst0->getName(); std::string p1Name = PartInst1->getName(); std::string jointName = p0Name + "-to-" + p1Name + jointPostPend; mJoint->setName(jointName); mJoint->setPart0(PartInst0); mJoint->setPart1(PartInst1); CoordinateFrame c0 = p0->getConstGeometry()->getSurfaceCoordInBody(s0); CoordinateFrame worldC = p0->getCoordinateFrame() * c0; CoordinateFrame c1 = p1->getCoordinateFrame().toObjectSpace(worldC); mJoint->setC0(c0); mJoint->setC1(c1); mJoint->setSurface0(s0); mJoint->setSurface1(s1); mJoint->setParent(PartInst0); } } } void TerrainManualJointSurfacePair::dynamicDraw(Adorn* adorn) { if( p1 && p0 && p1->getConstGeometry() && p0->getConstGeometry() ) { const MegaClusterPoly* terrainPoly = static_cast(p0->getConstGeometry()); size_t tempFaceId; std::vector intersectPolyInP0 = terrainPoly->findCellIntersectionWithGeom( cellIndex, p0->getCoordinateFrame(), *(p1->getConstGeometry()), p1->getCoordinateFrame(), tempFaceId); Color3 color = AdvArrowTool::advManualJointType == DRAG::WEAK_MANUAL_JOINT ? Color3::brown() : Color3::white(); DrawAdorn::polygonRelativeToCoord(adorn, p0->getCoordinateFrame(), intersectPolyInP0, color, autoJointLineThickness); } } void DisallowedTerrainJointSurfacePair::dynamicDraw(Adorn* adorn) { if( p1 && p0 && p1->getConstGeometry() && p0->getConstGeometry() ) { const MegaClusterPoly* terrainPoly = static_cast(p0->getConstGeometry()); size_t tempFaceId; std::vector intersectPolyInP0 = terrainPoly->findCellIntersectionWithGeom( cellIndex, p0->getCoordinateFrame(), *(p1->getConstGeometry()), p1->getCoordinateFrame(), tempFaceId); DrawAdorn::polygonRelativeToCoord(adorn, p0->getCoordinateFrame(), intersectPolyInP0, Color3::red(), autoJointLineThickness); } } void TerrainManualJointSurfacePair::createJoint(void) { // check if the non-terrain part, p1, is already welded to this terrain cell // in this case, do not create it RBXASSERT( p1->getConstGeometry()->getGeometryType() != RBX::Geometry::GEOMETRY_MEGACLUSTER ); for (int i = 0; i < p1->getNumJoints(); ++i) { const ManualWeldJoint* existingJoint = dynamic_cast(p1->getConstJoint(i)); if( existingJoint && cellIndex == existingJoint->getCell() ) return; } PartInstance* PartInst0 = (PartInstance*)PartInstance::fromConstPrimitive(p0); PartInstance* PartInst1 = (PartInstance*)PartInstance::fromConstPrimitive(p1); if(PartInst0 && PartInst1) { if( AdvArrowTool::advManualJointType == DRAG::STRONG_MANUAL_JOINT) { shared_ptr mJoint = Creatable::create(); std::string jointPostPend = " Terrain Joint"; // The joint will appear as a child of the drag part in the tree view std::string p0Name = PartInst0->getName(); std::string p1Name = PartInst1->getName(); std::string jointName = p1Name + jointPostPend; mJoint->setName(jointName); mJoint->setPart0(PartInst0); mJoint->setPart1(PartInst1); CoordinateFrame c0 = p0->getCoordinateFrame(); CoordinateFrame worldC = p0->getCoordinateFrame() * c0; CoordinateFrame c1 = p1->getCoordinateFrame().toObjectSpace(worldC); mJoint->setC0(c0); mJoint->setC1(c1); mJoint->setParent(PartInst1); RBXASSERT(mJoint->getJointType() == Joint::MANUAL_WELD_JOINT); static_cast(mJoint->getJoint())->setCell(cellIndex); } } } void SmoothTerrainManualJointSurfacePair::dynamicDraw(Adorn* adorn) { } void SmoothTerrainManualJointSurfacePair::createJoint(void) { // check if the non-terrain part, p1, is already welded to terrain // in this case, do not create it RBXASSERT( p1->getConstGeometry()->getGeometryType() != RBX::Geometry::GEOMETRY_MEGACLUSTER ); for (int i = 0; i < p1->getNumJoints(); ++i) { const Joint* existingJoint = p1->getConstJoint(i); if (Joint::isManualJoint(existingJoint) && (existingJoint->getConstPrimitive(0) == p0 || existingJoint->getConstPrimitive(1) == p1)) return; } PartInstance* PartInst0 = (PartInstance*)PartInstance::fromConstPrimitive(p0); PartInstance* PartInst1 = (PartInstance*)PartInstance::fromConstPrimitive(p1); if (PartInst0 && PartInst1) { if (AdvArrowTool::advManualJointType == DRAG::STRONG_MANUAL_JOINT) { shared_ptr mJoint = Creatable::create(); std::string jointPostPend = " Terrain Joint"; // The joint will appear as a child of the drag part in the tree view std::string p0Name = PartInst0->getName(); std::string p1Name = PartInst1->getName(); std::string jointName = p1Name + jointPostPend; mJoint->setName(jointName); mJoint->setPart0(PartInst0); mJoint->setPart1(PartInst1); mJoint->setParent(PartInst1); } } } } // namespace