mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-04 20:57:49 +00:00
187 lines
4.8 KiB
C++
187 lines
4.8 KiB
C++
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
|
#include "stdafx.h"
|
|
|
|
#include "V8World/Motor6DJoint.h"
|
|
#include "V8World/MotorJoint.h"
|
|
#include "V8World/Primitive.h"
|
|
#include "V8World/Assembly.h"
|
|
#include "V8World/World.h"
|
|
#include "V8Kernel/Body.h"
|
|
|
|
#include "boost/functional/hash/hash.hpp"
|
|
|
|
namespace RBX {
|
|
|
|
|
|
Motor6DJoint::Motor6DJoint()
|
|
: maxZAngleVelocity(0.0f)
|
|
, desiredZAngle(0.0f)
|
|
, link(new D6Link())
|
|
, poseMaskWeight(1.0f)
|
|
, poseFreshness(0)
|
|
{}
|
|
|
|
|
|
Motor6DJoint::~Motor6DJoint()
|
|
{
|
|
delete link;
|
|
}
|
|
|
|
// TODO: Big hack
|
|
// In a reverse polarity situation, where the joint polarity (set by P0, P1)
|
|
// is different than the assembly polarity, for now use the JOINT polarity
|
|
// to make kinematic adjustments.
|
|
// In the case where polarity == -1, we must move the ROOT body to make this adjustment.
|
|
// Only do this if the root is not anchored.
|
|
//
|
|
|
|
int Motor6DJoint::getParentId() const
|
|
{
|
|
const Body* b0 = getConstPrimitive(0)->getConstBody();
|
|
const Body* b1 = getConstPrimitive(1)->getConstBody();
|
|
|
|
int parentId = (b1->getConstParent() == b0) ? 0 : 1;
|
|
RBXASSERT((parentId == 0) || (b0->getConstParent() == b1));
|
|
|
|
return parentId;
|
|
}
|
|
|
|
|
|
void Motor6DJoint::setJointOffsetCFrame(const Vector3 offset, const Vector3 axisAngle)
|
|
{
|
|
RBXASSERT(link);
|
|
|
|
Vector3 axis = axisAngle;
|
|
float angle = axis.unitize();
|
|
link->setJointOffsetCFrame(CoordinateFrame(Matrix3::fromAxisAngleFast(axis, angle), offset)); // Parent id == 0: value
|
|
}
|
|
|
|
|
|
Link* Motor6DJoint::resetLink()
|
|
{
|
|
int parentId = getParentId();
|
|
int childId = (parentId == 1) ? 0 : 1;
|
|
|
|
link->reset( getJointCoord(parentId),
|
|
getJointCoord(childId) );
|
|
|
|
setJointOffsetCFrame(currentOffset, currentAxisAngle);
|
|
|
|
return link;
|
|
}
|
|
|
|
float Motor6DJoint::getCurrentZAngle() const
|
|
{
|
|
return currentAxisAngle.z; // todo: should re renormalize?
|
|
}
|
|
|
|
bool Motor6DJoint::stepUi(double distributedGameTime)
|
|
{
|
|
float maxVel = fabs(maxZAngleVelocity);
|
|
|
|
float currentZAngle = getCurrentZAngle();
|
|
float delta = (desiredZAngle - currentZAngle);
|
|
|
|
float scriptedZAngle;
|
|
|
|
if (fabs(delta) < maxVel) {
|
|
scriptedZAngle = desiredZAngle;
|
|
}
|
|
else if (delta > 0.0f) {
|
|
scriptedZAngle = currentZAngle + maxVel;
|
|
}
|
|
else {
|
|
scriptedZAngle = currentZAngle - maxVel;
|
|
}
|
|
|
|
if(poseFreshness > 0)
|
|
{
|
|
poseFreshness--;
|
|
}
|
|
else if (poseMaskWeight < 1.0f || !poseAxisAngleDelta.isZero() || !poseOffsetDelta.isZero()) // pose expired, fade back to normal.
|
|
{
|
|
poseMaskWeight = std::min(1.0f, poseMaskWeight+ (1.0f/MotorJoint::poseDuration));
|
|
|
|
// shorten vectors.
|
|
float sqangle = poseAxisAngleDelta.squaredMagnitude();
|
|
if(sqangle != 0)
|
|
{
|
|
float newsqangle = std::max(0.0f, sqangle * (1.0f - (1.0f / MotorJoint::poseDuration)) - 0.01f);
|
|
poseAxisAngleDelta *= (newsqangle/sqangle);
|
|
}
|
|
|
|
float sqmagnitude = poseOffsetDelta.squaredMagnitude();
|
|
if(sqmagnitude != 0)
|
|
{
|
|
float newsqmagnitude = std::max(0.0f, sqmagnitude * (1.0f - (1.0f / MotorJoint::poseDuration)) - 0.01f);
|
|
poseOffsetDelta *= (newsqmagnitude/sqmagnitude);
|
|
}
|
|
}
|
|
|
|
return setCurrentOffsetAngle(poseOffsetDelta, Vector3(0, 0, scriptedZAngle* poseMaskWeight ) + poseAxisAngleDelta);
|
|
}
|
|
|
|
void Motor6DJoint::setCurrentZAngle(float value)
|
|
{
|
|
setCurrentOffsetAngle(poseOffsetDelta, Vector3(0, 0, value* poseMaskWeight ) + poseAxisAngleDelta);
|
|
}
|
|
|
|
|
|
CoordinateFrame Motor6DJoint::getMeInOther(Primitive* me)
|
|
{
|
|
CoordinateFrame p1InP0 = link->getChildInParent();
|
|
|
|
if (me == getPrimitive(1)) {
|
|
return p1InP0;
|
|
}
|
|
else {
|
|
RBXASSERT(me == getPrimitive(0));
|
|
return p1InP0.inverse();
|
|
}
|
|
}
|
|
|
|
bool Motor6DJoint::setCurrentOffsetAngle(const Vector3 offset, const Vector3 axisAngle)
|
|
{
|
|
if (currentOffset != offset || currentAxisAngle != axisAngle) {
|
|
currentOffset = offset;
|
|
currentAxisAngle = axisAngle;
|
|
|
|
// RBX::StandardOut::singleton()->printf(RBX::MESSAGE_INFO, "angle: %f", currentAxisAngle.z);
|
|
if (World* world = this->findWorld()) {
|
|
|
|
setJointOffsetCFrame(currentOffset, axisAngle);
|
|
world->ticklePrimitive(getPrimitive(0), true);
|
|
world->ticklePrimitive(getPrimitive(1), true);
|
|
}
|
|
return true;
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
void Motor6DJoint::applyPose(const Vector3& poseOffset, const Vector3& poseAxisAngle, float poseWeight, float maskWeight)
|
|
{
|
|
// here we are essentially pre-lerping the pose inflence to the joint.
|
|
poseOffsetDelta = poseOffset * poseWeight;
|
|
poseAxisAngleDelta = poseAxisAngle * poseWeight;
|
|
poseMaskWeight = maskWeight;
|
|
poseFreshness = MotorJoint::poseDuration;
|
|
}
|
|
|
|
size_t Motor6DJoint::hashCode() const
|
|
{
|
|
std::size_t seed = boost::hash<G3D::Vector3>()(jointCoord0.translation);
|
|
boost::hash_combine(seed, jointCoord1.translation);
|
|
return seed;
|
|
}
|
|
|
|
bool Motor6DJoint::isAligned()
|
|
{
|
|
CoordinateFrame baseWorld = getJointWorldCoord(0);
|
|
CoordinateFrame rotorWorld = getJointWorldCoord(1);
|
|
|
|
return ( Math::fuzzyEq(baseWorld.translation, rotorWorld.translation)
|
|
&& Math::fuzzyEq(baseWorld.rotation.column(2), rotorWorld.rotation.column(2)) );
|
|
}
|
|
|
|
|
|
} // namespace
|