Compare commits
9 commits
ec65c6eddc
...
0dc8254065
Author | SHA1 | Date | |
---|---|---|---|
0dc8254065 | |||
c291be7552 | |||
fa2ba25c4d | |||
22291e6a60 | |||
de30976dc0 | |||
30d00a7de2 | |||
f6f7a5f151 | |||
bbe862b309 | |||
06a5f91769 |
31 changed files with 239 additions and 77 deletions
|
@ -172,7 +172,7 @@ void processField(CXCursor cur, ClassAnalysis* state) {
|
|||
auto cframePosition = parseAnnotationString(cframePositionDef.value());
|
||||
|
||||
PropertyAnalysis cframeProp;
|
||||
cframeProp.backingFieldType = anly.backingFieldType;
|
||||
cframeProp.backingFieldType = "Vector3";
|
||||
cframeProp.fieldName = anly.fieldName;
|
||||
cframeProp.name = cframePosition["name"];
|
||||
cframeProp.category = anly.category;
|
||||
|
@ -188,7 +188,7 @@ void processField(CXCursor cur, ClassAnalysis* state) {
|
|||
auto cframeRotation = parseAnnotationString(cframeRotationDef.value());
|
||||
|
||||
PropertyAnalysis cframeProp;
|
||||
cframeProp.backingFieldType = anly.backingFieldType;
|
||||
cframeProp.backingFieldType = "Vector3";
|
||||
cframeProp.fieldName = anly.fieldName;
|
||||
cframeProp.name = cframeRotation["name"];
|
||||
cframeProp.category = anly.category;
|
||||
|
|
|
@ -84,8 +84,6 @@ void writePropertySetHandler(std::ofstream& out, ClassAnalysis state) {
|
|||
<< "\n this->" << prop.fieldName << " = ref.expired() ? std::weak_ptr<" << subtype << ">() : std::dynamic_pointer_cast<" << subtype << ">(ref.lock());";
|
||||
} else {
|
||||
out << "\n this->" << prop.fieldName << " = " << castFromVariant("value", prop.backingFieldType) << ";";
|
||||
if (!prop.onUpdateCallback.empty())
|
||||
out << "\n " << prop.onUpdateCallback << "(name);";
|
||||
}
|
||||
|
||||
out << "\n }";
|
||||
|
@ -106,6 +104,26 @@ void writePropertySetHandler(std::ofstream& out, ClassAnalysis state) {
|
|||
out << "\n};\n\n";
|
||||
}
|
||||
|
||||
void writePropertyUpdateHandler(std::ofstream& out, ClassAnalysis state) {
|
||||
out << "void " << state.name << "::InternalUpdateProperty(std::string name) {";
|
||||
|
||||
out << "\n ";
|
||||
bool first = true;
|
||||
for (auto& prop : state.properties) {
|
||||
if (prop.onUpdateCallback.empty()) continue;
|
||||
out << (first ? "" : " else ") << "if (name == \"" << prop.name << "\") {";
|
||||
|
||||
out << "\n " << prop.onUpdateCallback << "(name);";
|
||||
|
||||
out << "\n }";
|
||||
first = false;
|
||||
}
|
||||
|
||||
out << "\n " << state.baseClass << "::InternalUpdateProperty(name);";
|
||||
|
||||
out << "\n};\n\n";
|
||||
}
|
||||
|
||||
void writePropertyGetHandler(std::ofstream& out, ClassAnalysis state) {
|
||||
out << "result<Data::Variant, MemberNotFound> " << state.name << "::InternalGetPropertyValue(std::string name) {";
|
||||
|
||||
|
@ -224,5 +242,6 @@ void writeCodeForClass(std::ofstream& out, ClassAnalysis& state) {
|
|||
writePropertySetHandler(out, state);
|
||||
writePropertyGetHandler(out, state);
|
||||
writePropertyMetaHandler(out, state);
|
||||
writePropertyUpdateHandler(out, state);
|
||||
writePropertiesList(out, state);
|
||||
}
|
|
@ -67,6 +67,10 @@ const Data::String Data::CFrame::ToString() const {
|
|||
return std::to_string(X()) + ", " + std::to_string(Y()) + ", " + std::to_string(Z());
|
||||
}
|
||||
|
||||
Data::CFrame Data::CFrame::pointToward(Vector3 position, Vector3 toward) {
|
||||
return Data::CFrame(position, position + toward, (abs(glm::dot((glm::vec3)toward, glm::vec3(0, 1, 0))) > 0.999) ? glm::vec3(0, 0, 1) : glm::vec3(0, 1, 0));
|
||||
}
|
||||
|
||||
Data::CFrame::operator glm::mat4() const {
|
||||
// Always make sure to translate the position first, then rotate. Matrices work backwards
|
||||
return glm::translate(glm::mat4(1.0f), this->translation) * glm::mat4(this->rotation);
|
||||
|
|
|
@ -27,6 +27,9 @@ namespace Data {
|
|||
CFrame(Vector3 position, Vector3 lookAt, Vector3 up = Vector3(0, 1, 0));
|
||||
~CFrame();
|
||||
|
||||
// Same as CFrame(position, position + toward), but makes sure that up and toward are not linearly dependant
|
||||
static CFrame pointToward(Vector3 position, Vector3 toward);
|
||||
|
||||
static const CFrame IDENTITY;
|
||||
static const CFrame YToZ;
|
||||
|
||||
|
|
|
@ -24,8 +24,12 @@
|
|||
|
||||
#define AUTOGEN_PREAMBLE \
|
||||
protected: \
|
||||
result<PropertyMeta, MemberNotFound> InternalGetPropertyMeta(std::string name) override; \
|
||||
fallible<MemberNotFound, AssignToReadOnlyMember> InternalSetPropertyValue(std::string name, Data::Variant value) override; \
|
||||
result<Data::Variant, MemberNotFound> InternalGetPropertyValue(std::string name) override; \
|
||||
std::vector<std::string> InternalGetProperties() override; \
|
||||
virtual result<PropertyMeta, MemberNotFound> InternalGetPropertyMeta(std::string name) override; \
|
||||
virtual fallible<MemberNotFound, AssignToReadOnlyMember> InternalSetPropertyValue(std::string name, Data::Variant value) override; \
|
||||
virtual result<Data::Variant, MemberNotFound> InternalGetPropertyValue(std::string name) override; \
|
||||
virtual void InternalUpdateProperty(std::string name) override; \
|
||||
virtual std::vector<std::string> InternalGetProperties() override; \
|
||||
public: \
|
||||
const static InstanceType TYPE; \
|
||||
virtual const InstanceType* GetClass() override; \
|
||||
private:
|
||||
|
|
|
@ -189,9 +189,12 @@ result<Data::Variant, MemberNotFound> Instance::GetPropertyValue(std::string nam
|
|||
return InternalGetPropertyValue(name);
|
||||
}
|
||||
|
||||
fallible<MemberNotFound, AssignToReadOnlyMember> Instance::SetPropertyValue(std::string name, Data::Variant value) {
|
||||
fallible<MemberNotFound, AssignToReadOnlyMember> Instance::SetPropertyValue(std::string name, Data::Variant value, bool sendUpdateEvent) {
|
||||
auto result = InternalSetPropertyValue(name, value);
|
||||
if (result.isSuccess()) sendPropertyUpdatedSignal(shared_from_this(), name, value);
|
||||
if (result.isSuccess() && sendUpdateEvent) {
|
||||
InternalUpdateProperty(name);
|
||||
sendPropertyUpdatedSignal(shared_from_this(), name, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -236,6 +239,9 @@ fallible<MemberNotFound, AssignToReadOnlyMember> Instance::InternalSetPropertyVa
|
|||
return {};
|
||||
}
|
||||
|
||||
void Instance::InternalUpdateProperty(std::string name) {
|
||||
}
|
||||
|
||||
std::vector<std::string> Instance::InternalGetProperties() {
|
||||
std::vector<std::string> members;
|
||||
members.push_back("Name");
|
||||
|
@ -245,12 +251,7 @@ std::vector<std::string> Instance::InternalGetProperties() {
|
|||
}
|
||||
|
||||
void Instance::UpdateProperty(std::string name) {
|
||||
// TODO: temporary workaround because I'm too lazy to implement this in autogen
|
||||
InternalSetPropertyValue(name, InternalGetPropertyValue(name).expect()).expect();
|
||||
|
||||
// PropertyMeta meta = GetPropertyMeta(name).expect();
|
||||
// if (!meta.updateCallback) return; // Nothing to update, exit.
|
||||
// meta.updateCallback.value()(name);
|
||||
InternalUpdateProperty(name);
|
||||
}
|
||||
|
||||
std::vector<std::string> Instance::GetProperties() {
|
||||
|
@ -291,7 +292,6 @@ result<InstanceRef, NoSuchInstance> Instance::Deserialize(pugi::xml_node node) {
|
|||
return NoSuchInstance(className);
|
||||
}
|
||||
// This will error if an abstract instance is used in the file. Oh well, not my prob rn.
|
||||
// printf("What are you? A %s sandwich\n", className.c_str());
|
||||
InstanceRef object = INSTANCE_MAP[className]->constructor();
|
||||
object->GetChildren();
|
||||
|
||||
|
@ -398,7 +398,6 @@ std::optional<std::shared_ptr<Instance>> Instance::Clone(RefState<_RefStatePrope
|
|||
}
|
||||
} else {
|
||||
Data::Variant value = GetPropertyValue(property).expect();
|
||||
// printf("property: %s, value: %s\n", property.c_str(), std::string(value.ToString()).c_str());
|
||||
newInstance->SetPropertyValue(property, value).expect();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,6 +72,7 @@ protected:
|
|||
virtual result<Data::Variant, MemberNotFound> InternalGetPropertyValue(std::string name);
|
||||
virtual fallible<MemberNotFound, AssignToReadOnlyMember> InternalSetPropertyValue(std::string name, Data::Variant value);
|
||||
virtual result<PropertyMeta, MemberNotFound> InternalGetPropertyMeta(std::string name);
|
||||
virtual void InternalUpdateProperty(std::string name);
|
||||
virtual std::vector<std::string> InternalGetProperties();
|
||||
|
||||
virtual void OnParentUpdated(std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent);
|
||||
|
@ -110,7 +111,7 @@ public:
|
|||
|
||||
// Properties
|
||||
result<Data::Variant, MemberNotFound> GetPropertyValue(std::string name);
|
||||
fallible<MemberNotFound, AssignToReadOnlyMember> SetPropertyValue(std::string name, Data::Variant value);
|
||||
fallible<MemberNotFound, AssignToReadOnlyMember> SetPropertyValue(std::string name, Data::Variant value, bool sendUpdateEvent = true);
|
||||
result<PropertyMeta, MemberNotFound> GetPropertyMeta(std::string name);
|
||||
// Manually trigger the update of a property. Useful internally when setting properties directly
|
||||
void UpdateProperty(std::string name);
|
||||
|
|
|
@ -19,8 +19,6 @@ private:
|
|||
void DeserializeService(pugi::xml_node node);
|
||||
static void cloneService(std::shared_ptr<DataModel> target, std::shared_ptr<Service>, RefState<_RefStatePropertyCell>);
|
||||
public:
|
||||
const static InstanceType TYPE;
|
||||
|
||||
std::map<std::string, std::shared_ptr<Service>> services;
|
||||
|
||||
std::optional<std::string> currentFile;
|
||||
|
@ -29,7 +27,6 @@ public:
|
|||
void Init(bool runMode = false);
|
||||
|
||||
static inline std::shared_ptr<DataModel> New() { return std::make_shared<DataModel>(); };
|
||||
virtual const InstanceType* GetClass() override;
|
||||
|
||||
result<std::shared_ptr<Service>, NoSuchService> GetService(std::string className);
|
||||
result<std::optional<std::shared_ptr<Service>>, NoSuchService> FindService(std::string className);
|
||||
|
|
|
@ -34,8 +34,6 @@ enum HandlesType {
|
|||
class INSTANCE_WITH(abstract) Handles : public Instance {
|
||||
AUTOGEN_PREAMBLE
|
||||
public:
|
||||
const static InstanceType TYPE;
|
||||
|
||||
bool nixAxes = false; // XYZ -> ZXY, used with rotation
|
||||
bool active;
|
||||
std::weak_ptr<Part> adornee;
|
||||
|
@ -54,5 +52,4 @@ public:
|
|||
std::optional<HandleFace> RaycastHandle(rp3d::Ray ray);
|
||||
|
||||
static inline std::shared_ptr<Handles> New() { return std::make_shared<Handles>(); };
|
||||
virtual const InstanceType* GetClass() override;
|
||||
};
|
|
@ -4,6 +4,7 @@
|
|||
#include "../annotation.h"
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <reactphysics3d/engine/PhysicsWorld.h>
|
||||
|
||||
//this is necessary ebcause we use std::weak_ptr<Part> without including it in this file
|
||||
#ifdef __AUTOGEN_EXTRA_INCLUDES__
|
||||
|
@ -29,7 +30,6 @@ protected:
|
|||
virtual void buildJoint() = 0;
|
||||
virtual void breakJoint() = 0;
|
||||
public:
|
||||
const static InstanceType TYPE;
|
||||
|
||||
[[ def_prop(name="Part0", on_update=onUpdated) ]]
|
||||
std::weak_ptr<Part> part0;
|
||||
|
@ -42,6 +42,4 @@ public:
|
|||
|
||||
JointInstance(const InstanceType*);
|
||||
~JointInstance();
|
||||
|
||||
virtual const InstanceType* GetClass() override;
|
||||
};
|
48
core/src/objects/joint/rotate.cpp
Normal file
48
core/src/objects/joint/rotate.cpp
Normal file
|
@ -0,0 +1,48 @@
|
|||
#include "rotate.h"
|
||||
#include "objects/jointsservice.h"
|
||||
#include "objects/part.h"
|
||||
#include "objects/workspace.h"
|
||||
#include "rendering/renderer.h"
|
||||
#include <reactphysics3d/constraint/HingeJoint.h>
|
||||
|
||||
Rotate::Rotate(): JointInstance(&TYPE) {
|
||||
}
|
||||
|
||||
Rotate::~Rotate() {
|
||||
}
|
||||
static CFrame XYZToZXY(glm::vec3(0, 0, 0), -glm::vec3(1, 0, 0), glm::vec3(0, 0, 1));
|
||||
|
||||
void Rotate::buildJoint() {
|
||||
// Only if both parts are set, are not the same part, are part of a workspace, and are part of the same workspace, we build the joint
|
||||
if (part0.expired() || part1.expired() || part0.lock() == part1.lock() || !workspaceOfPart(part0.lock()) || workspaceOfPart(part0.lock()) != workspaceOfPart(part1.lock())) return;
|
||||
|
||||
// Don't build the joint if we're not part of either a workspace or JointsService
|
||||
if ((!GetParent() || GetParent().value()->GetClass() != &JointsService::TYPE) && !workspace()) return;
|
||||
|
||||
std::shared_ptr<Workspace> workspace = workspaceOfPart(part0.lock()).value();
|
||||
if (!workspace->physicsWorld) return;
|
||||
|
||||
// Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it
|
||||
// used to be rather than specifying an anchor rotation, so whatever.
|
||||
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
||||
part1.lock()->cframe = newFrame;
|
||||
workspace->SyncPartPhysics(part1.lock());
|
||||
// Do NOT use Abs() in this scenario. For some reason that breaks it
|
||||
rp::HingeJointInfo jointInfo(part0.lock()->rigidBody, part1.lock()->rigidBody, newFrame.Position(), -(part0.lock()->cframe * c0).LookVector().Unit());
|
||||
this->joint = dynamic_cast<rp::HingeJoint*>(workspace->physicsWorld->createJoint(jointInfo));
|
||||
jointWorkspace = workspace;
|
||||
|
||||
// part1.lock()->rigidBody->getCollider(0)->setCollideWithMaskBits(0b10);
|
||||
// part1.lock()->rigidBody->getCollider(0)->setCollisionCategoryBits(0b10);
|
||||
// part0.lock()->rigidBody->getCollider(0)->setCollideWithMaskBits(0b01);
|
||||
// part0.lock()->rigidBody->getCollider(0)->setCollisionCategoryBits(0b01);
|
||||
}
|
||||
|
||||
// !!! REMINDER: This has to be called manually when parts are destroyed/removed from the workspace, or joints will linger
|
||||
void Rotate::breakJoint() {
|
||||
// If the joint doesn't exist, or its workspace expired (not our problem anymore), then no need to do anything
|
||||
if (!this->joint || jointWorkspace.expired() || !jointWorkspace.lock()->physicsWorld) return;
|
||||
|
||||
jointWorkspace.lock()->physicsWorld->destroyJoint(this->joint);
|
||||
this->joint = nullptr;
|
||||
}
|
21
core/src/objects/joint/rotate.h
Normal file
21
core/src/objects/joint/rotate.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include "objects/annotation.h"
|
||||
#include "objects/base/instance.h"
|
||||
#include "objects/joint/jointinstance.h"
|
||||
#include <memory>
|
||||
|
||||
class INSTANCE Rotate : public JointInstance {
|
||||
AUTOGEN_PREAMBLE
|
||||
|
||||
rp::HingeJoint* joint = nullptr;
|
||||
|
||||
virtual void buildJoint() override;
|
||||
virtual void breakJoint() override;
|
||||
public:
|
||||
Rotate();
|
||||
~Rotate();
|
||||
|
||||
static inline std::shared_ptr<Rotate> New() { return std::make_shared<Rotate>(); };
|
||||
static inline std::shared_ptr<Instance> Create() { return std::make_shared<Rotate>(); };
|
||||
};
|
|
@ -28,12 +28,10 @@ void Snap::buildJoint() {
|
|||
|
||||
// Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it
|
||||
// used to be rather than specifying an anchor rotation, so whatever.
|
||||
CFrame newFrame = part0.lock()->cframe * (c1.Inverse() * c0);
|
||||
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
||||
part1.lock()->cframe = newFrame;
|
||||
workspace->SyncPartPhysics(part1.lock());
|
||||
|
||||
// printf("c1.Rotation: ");
|
||||
// printVec(c1.ToEulerAnglesXYZ());
|
||||
rp::FixedJointInfo jointInfo(part0.lock()->rigidBody, part1.lock()->rigidBody, (c0.Inverse() * c1).Position());
|
||||
this->joint = dynamic_cast<rp::FixedJoint*>(workspace->physicsWorld->createJoint(jointInfo));
|
||||
jointWorkspace = workspace;
|
||||
|
|
|
@ -13,12 +13,9 @@ class INSTANCE Snap : public JointInstance {
|
|||
virtual void buildJoint() override;
|
||||
virtual void breakJoint() override;
|
||||
public:
|
||||
const static InstanceType TYPE;
|
||||
|
||||
Snap();
|
||||
~Snap();
|
||||
|
||||
static inline std::shared_ptr<Snap> New() { return std::make_shared<Snap>(); };
|
||||
static inline std::shared_ptr<Instance> Create() { return std::make_shared<Snap>(); };
|
||||
virtual const InstanceType* GetClass() override;
|
||||
};
|
|
@ -28,12 +28,10 @@ void Weld::buildJoint() {
|
|||
|
||||
// Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it
|
||||
// used to be rather than specifying an anchor rotation, so whatever.
|
||||
CFrame newFrame = part0.lock()->cframe * (c1.Inverse() * c0);
|
||||
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
||||
part1.lock()->cframe = newFrame;
|
||||
workspace->SyncPartPhysics(part1.lock());
|
||||
|
||||
// printf("c1.Rotation: ");
|
||||
// printVec(c1.ToEulerAnglesXYZ());
|
||||
rp::FixedJointInfo jointInfo(part0.lock()->rigidBody, part1.lock()->rigidBody, (c0.Inverse() * c1).Position());
|
||||
this->joint = dynamic_cast<rp::FixedJoint*>(workspace->physicsWorld->createJoint(jointInfo));
|
||||
jointWorkspace = workspace;
|
||||
|
|
|
@ -13,12 +13,9 @@ class INSTANCE Weld : public JointInstance {
|
|||
virtual void buildJoint() override;
|
||||
virtual void breakJoint() override;
|
||||
public:
|
||||
const static InstanceType TYPE;
|
||||
|
||||
Weld();
|
||||
~Weld();
|
||||
|
||||
static inline std::shared_ptr<Weld> New() { return std::make_shared<Weld>(); };
|
||||
static inline std::shared_ptr<Instance> Create() { return std::make_shared<Weld>(); };
|
||||
virtual const InstanceType* GetClass() override;
|
||||
};
|
|
@ -12,11 +12,8 @@ protected:
|
|||
bool initialized = false;
|
||||
|
||||
public:
|
||||
const static InstanceType TYPE;
|
||||
|
||||
JointsService();
|
||||
~JointsService();
|
||||
|
||||
static inline std::shared_ptr<Instance> Create() { return std::make_shared<JointsService>(); };
|
||||
virtual const InstanceType* GetClass() override;
|
||||
};
|
|
@ -6,10 +6,12 @@
|
|||
#include "datatypes/color3.h"
|
||||
#include "datatypes/vector.h"
|
||||
#include "objects/base/member.h"
|
||||
#include "objects/joint/rotate.h"
|
||||
#include "objects/joint/weld.h"
|
||||
#include "objects/jointsservice.h"
|
||||
#include "objects/joint/jointinstance.h"
|
||||
#include "objects/joint/snap.h"
|
||||
#include "rendering/renderer.h"
|
||||
#include "rendering/surface.h"
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
@ -185,6 +187,8 @@ std::optional<std::shared_ptr<JointInstance>> makeJointFromSurfaces(SurfaceType
|
|||
|| (a == SurfaceInlets && (b == SurfaceStuds || b == SurfaceUniversal))
|
||||
|| (a == SurfaceUniversal && (b == SurfaceStuds || b == SurfaceInlets || b == SurfaceUniversal)))
|
||||
return Snap::New();
|
||||
if (a == SurfaceHinge)
|
||||
return Rotate::New();
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -209,28 +213,45 @@ void Part::MakeJoints() {
|
|||
for (Vector3 myFace : FACES) {
|
||||
Vector3 myWorldNormal = cframe.Rotation() * myFace;
|
||||
Vector3 validUp = cframe.Rotation() * Vector3(1,1,1).Unit(); // If myFace == (0, 1, 0), then (0, 1, 0) would produce NaN as up, so we fudge the up so that it works
|
||||
CFrame surfaceFrame(cframe.Position(), cframe * (myFace * size), validUp);
|
||||
CFrame surfaceFrame = CFrame::pointToward(cframe * (myFace * size / 2.f), cframe.Rotation() * myFace);
|
||||
Vector3 mySurfaceCenter = cframe * (myFace * size / 2.f);
|
||||
|
||||
for (Vector3 otherFace : FACES) {
|
||||
Vector3 otherWorldNormal = otherPart->cframe.Rotation() * otherFace;
|
||||
Vector3 otherSurfaceCenter = otherPart->cframe * (otherFace * otherPart->size);
|
||||
Vector3 otherSurfaceCenter = otherPart->cframe * (otherFace * otherPart->size / 2.f);
|
||||
Vector3 surfacePointLocalToMyFrame = surfaceFrame.Inverse() * otherSurfaceCenter;
|
||||
|
||||
float dot = myWorldNormal.Dot(otherWorldNormal);
|
||||
if (dot > -0.99) continue; // Surface is pointing opposite to ours
|
||||
|
||||
if (abs(surfacePointLocalToMyFrame.Z()) > 0.05) continue; // Surfaces are within 0.05 studs of one another
|
||||
if (!checkJointContinuity(otherPart)) continue;
|
||||
|
||||
SurfaceType mySurface = surfaceFromFace(faceFromNormal(myFace));
|
||||
SurfaceType otherSurface = surfaceFromFace(faceFromNormal(otherFace));
|
||||
|
||||
// Create contacts
|
||||
// Contact always occurs at the center of Part0's surface (even if that point does not overlap both surfaces)
|
||||
// Contact 0 is Part0's contact relative to Part0. It should point *opposite* the direction of its surface normal
|
||||
// Contact 1 is Part1's contact relative to Part1. It should point directly toward the direction of its surface normal
|
||||
|
||||
// My additional notes:
|
||||
// Contact == Part0.CFrame * C0 == Part1.CFrame * C1
|
||||
// C1 == Part1.CFrame:Inverse() * Part0.CFrame * C0
|
||||
// Part1.CFrame == Part0.CFrame * C0 * C1:Inverse()
|
||||
// C0 == Part0.CFrame:Inverse() * Contact
|
||||
|
||||
CFrame contactPoint = CFrame::pointToward(mySurfaceCenter, -myWorldNormal);
|
||||
CFrame contact0 = cframe.Inverse() * contactPoint;
|
||||
CFrame contact1 = otherPart->cframe.Inverse() * contactPoint;
|
||||
|
||||
auto joint_ = makeJointFromSurfaces(mySurface, otherSurface);
|
||||
if (!joint_) continue;
|
||||
std::shared_ptr<JointInstance> joint = joint_.value();
|
||||
joint->part0 = shared<Part>();
|
||||
joint->part1 = otherPart->shared<Part>();
|
||||
joint->c1 = cframe;
|
||||
joint->c0 = otherPart->cframe;
|
||||
joint->c0 = contact0;
|
||||
joint->c1 = contact1;
|
||||
dataModel().value()->GetService<JointsService>()->AddChild(joint);
|
||||
joint->UpdateProperty("Part0");
|
||||
|
||||
|
|
|
@ -49,8 +49,6 @@ protected:
|
|||
void OnAncestryChanged(std::optional<std::shared_ptr<Instance>> child, std::optional<std::shared_ptr<Instance>> newParent) override;
|
||||
void onUpdated(std::string);
|
||||
public:
|
||||
const static InstanceType TYPE;
|
||||
|
||||
[[ def_prop(name="Velocity", on_update=onUpdated) ]]
|
||||
Vector3 velocity;
|
||||
[[ def_prop(name="CFrame", on_update=onUpdated), cframe_position_prop(name="Position"), cframe_rotation_prop(name="Rotation") ]]
|
||||
|
@ -89,7 +87,6 @@ public:
|
|||
static inline std::shared_ptr<Part> New() { return std::make_shared<Part>(); };
|
||||
static inline std::shared_ptr<Part> New(PartConstructParams params) { return std::make_shared<Part>(params); };
|
||||
static inline InstanceRef Create() { return std::make_shared<Part>(); };
|
||||
virtual const InstanceType* GetClass() override;
|
||||
|
||||
inline Vector3 position() { return cframe.Position(); }
|
||||
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
class INSTANCE_WITH(explorer_icon="script") Script : public Instance {
|
||||
AUTOGEN_PREAMBLE
|
||||
public:
|
||||
const static InstanceType TYPE;
|
||||
|
||||
Script();
|
||||
~Script();
|
||||
|
||||
|
@ -19,5 +17,4 @@ public:
|
|||
|
||||
static inline std::shared_ptr<Script> New() { return std::make_shared<Script>(); };
|
||||
static inline std::shared_ptr<Instance> Create() { return std::make_shared<Script>(); };
|
||||
virtual const InstanceType* GetClass() override;
|
||||
};
|
|
@ -11,13 +11,10 @@ protected:
|
|||
bool initialized = false;
|
||||
|
||||
public:
|
||||
const static InstanceType TYPE;
|
||||
|
||||
ScriptContext();
|
||||
~ScriptContext();
|
||||
|
||||
lua_State* state;
|
||||
|
||||
static inline std::shared_ptr<Instance> Create() { return std::make_shared<ScriptContext>(); };
|
||||
virtual const InstanceType* GetClass() override;
|
||||
};
|
|
@ -13,11 +13,8 @@ protected:
|
|||
bool initialized = false;
|
||||
|
||||
public:
|
||||
const static InstanceType TYPE;
|
||||
|
||||
ServerScriptService();
|
||||
~ServerScriptService();
|
||||
|
||||
static inline std::shared_ptr<Instance> Create() { return std::make_shared<ServerScriptService>(); };
|
||||
virtual const InstanceType* GetClass() override;
|
||||
};
|
|
@ -27,6 +27,7 @@ enum FilterResult {
|
|||
class Part;
|
||||
class Snap;
|
||||
class Weld;
|
||||
class Rotate;
|
||||
|
||||
typedef std::function<FilterResult(std::shared_ptr<Part>)> RaycastFilter;
|
||||
|
||||
|
@ -39,24 +40,21 @@ class INSTANCE_SERVICE(explorer_icon="workspace") Workspace : public Service {
|
|||
friend Part;
|
||||
friend Snap;
|
||||
friend Weld;
|
||||
friend Rotate;
|
||||
protected:
|
||||
void InitService() override;
|
||||
bool initialized = false;
|
||||
|
||||
public:
|
||||
const static InstanceType TYPE;
|
||||
|
||||
Workspace();
|
||||
~Workspace();
|
||||
|
||||
// static inline std::shared_ptr<Workspace> New() { return std::make_shared<Workspace>(); };
|
||||
static inline std::shared_ptr<Instance> Create() { return std::make_shared<Workspace>(); };
|
||||
virtual const InstanceType* GetClass() override;
|
||||
|
||||
void SyncPartPhysics(std::shared_ptr<Part> part);
|
||||
void DestroyRigidBody(rp::RigidBody* rigidBody);
|
||||
|
||||
void PhysicsStep(float deltaTime);
|
||||
std::optional<const RaycastResult> CastRayNearest(glm::vec3 point, glm::vec3 rotation, float maxLength, std::optional<RaycastFilter> filter = std::nullopt, unsigned short categoryMaskBits = 0xFFFF);
|
||||
|
||||
};
|
|
@ -11,6 +11,7 @@
|
|||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <glm/trigonometric.hpp>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "datatypes/cframe.h"
|
||||
#include "objects/handles.h"
|
||||
|
@ -453,12 +454,60 @@ void renderRotationArcs() {
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<CFrame> DEBUG_CFRAMES;
|
||||
|
||||
void renderDebugCFrames() {
|
||||
glDepthMask(GL_TRUE);
|
||||
glCullFace(GL_BACK);
|
||||
glFrontFace(GL_CCW); // This is right... Probably.....
|
||||
|
||||
// Use shader
|
||||
handleShader->use();
|
||||
|
||||
// view/projection transformations
|
||||
glm::mat4 projection = glm::perspective(glm::radians(45.f), (float)viewportWidth / (float)viewportHeight, 0.1f, 1000.0f);
|
||||
glm::mat4 view = camera.getLookAt();
|
||||
handleShader->set("projection", projection);
|
||||
handleShader->set("view", view);
|
||||
handleShader->set("sunLight", DirLight {
|
||||
.direction = glm::vec3(-0.2f, -1.0f, -0.3f),
|
||||
.ambient = glm::vec3(0.2f, 0.2f, 0.2f),
|
||||
.diffuse = glm::vec3(0.5f, 0.5f, 0.5f),
|
||||
.specular = glm::vec3(1.0f, 1.0f, 1.0f),
|
||||
});
|
||||
handleShader->set("numPointLights", 0);
|
||||
|
||||
// Pass in the camera position
|
||||
handleShader->set("viewPos", camera.cameraPos);
|
||||
|
||||
for (CFrame frame : DEBUG_CFRAMES) {
|
||||
glm::mat4 model = frame;
|
||||
model = glm::scale(model, glm::vec3(0.5, 0.5, 1.5));
|
||||
handleShader->set("model", model);
|
||||
handleShader->set("material", Material {
|
||||
.diffuse = glm::vec3(0.0f, 0.0f, 1.0f),
|
||||
.specular = glm::vec3(0.5f, 0.5f, 0.5f),
|
||||
.shininess = 16.0f,
|
||||
});
|
||||
glm::mat3 normalMatrix = glm::mat3(glm::transpose(glm::inverse(model)));
|
||||
handleShader->set("normalMatrix", normalMatrix);
|
||||
|
||||
ARROW_MESH->bind();
|
||||
glDrawArrays(GL_TRIANGLES, 0, ARROW_MESH->vertexCount);
|
||||
}
|
||||
}
|
||||
|
||||
void addDebugRenderCFrame(CFrame frame) {
|
||||
DEBUG_CFRAMES.push_back(frame);
|
||||
}
|
||||
|
||||
void render(GLFWwindow* window) {
|
||||
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
renderSkyBox();
|
||||
renderHandles();
|
||||
renderDebugCFrames();
|
||||
renderParts();
|
||||
renderOutlines();
|
||||
renderRotationArcs();
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
|
||||
extern bool wireframeRendering;
|
||||
|
||||
namespace Data { class CFrame; };
|
||||
|
||||
void renderInit(GLFWwindow* window, int width, int height);
|
||||
void render(GLFWwindow* window);
|
||||
void setViewport(int width, int height);
|
||||
void setViewport(int width, int height);
|
||||
void addDebugRenderCFrame(Data::CFrame);
|
|
@ -16,6 +16,7 @@ enum SurfaceType {
|
|||
SurfaceStuds = 3,
|
||||
SurfaceInlets = 4,
|
||||
SurfaceUniversal = 5,
|
||||
SurfaceHinge = 6,
|
||||
};
|
||||
|
||||
namespace Data { class Vector3; } using Data::Vector3;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <qsoundeffect.h>
|
||||
#include <string>
|
||||
#include "mainglwidget.h"
|
||||
#include "logger.h"
|
||||
#include "mainwindow.h"
|
||||
#include "common.h"
|
||||
#include "math_helper.h"
|
||||
|
@ -475,6 +476,9 @@ void MainGLWidget::keyPressEvent(QKeyEvent* evt) {
|
|||
|
||||
if (evt->key() == Qt::Key_C && getSelection().size() > 0 && !getSelection()[0].expired())
|
||||
getSelection()[0].lock()->Clone().value()->SetParent(gWorkspace());
|
||||
|
||||
if (evt->key() == Qt::Key_H && getSelection().size() > 0 && !getSelection()[0].expired())
|
||||
Logger::infof("Object at: 0x%x\n", getSelection()[0].lock().get());
|
||||
}
|
||||
|
||||
void MainGLWidget::keyReleaseEvent(QKeyEvent* evt) {
|
||||
|
|
|
@ -146,8 +146,8 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
|
||||
ui->mdiArea->setTabsClosable(true);
|
||||
|
||||
auto script = Script::New();
|
||||
gWorkspace()->AddChild(script);
|
||||
// auto script = Script::New();
|
||||
// gWorkspace()->AddChild(script);
|
||||
// ui->mdiArea->addSubWindow(new ScriptDocument(script));
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include <QStyledItemDelegate>
|
||||
#include <QPainter>
|
||||
#include <QTime>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <qnamespace.h>
|
||||
#include <qtreewidget.h>
|
||||
|
@ -340,6 +339,8 @@ void PropertiesView::setSelected(std::optional<InstanceRef> instance) {
|
|||
}
|
||||
|
||||
void PropertiesView::propertyChanged(QTreeWidgetItem *item, int column) {
|
||||
// Necessary because otherwise this will catch setCheckState from onPropertyUpdated
|
||||
if (ignorePropertyUpdates) return;
|
||||
if (!item->parent() || (item->parent() && item->parent()->parent()) || currentInstance.expired()) return;
|
||||
InstanceRef inst = currentInstance.lock();
|
||||
|
||||
|
@ -347,7 +348,7 @@ void PropertiesView::propertyChanged(QTreeWidgetItem *item, int column) {
|
|||
PropertyMeta meta = inst->GetPropertyMeta(propertyName).expect();
|
||||
|
||||
if (meta.type == &Data::Bool::TYPE) {
|
||||
inst->SetPropertyValue(propertyName, Data::Bool(item->checkState(1))).expect();
|
||||
inst->SetPropertyValue(propertyName, Data::Bool(item->checkState(1) == Qt::Checked)).expect();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -396,7 +397,10 @@ void PropertiesView::onPropertyUpdated(InstanceRef inst, std::string property, D
|
|||
if (item->data(0, Qt::DisplayRole).toString().toStdString() != property) continue;
|
||||
|
||||
if (meta.type == &Data::Bool::TYPE) {
|
||||
// This is done because otherwise propertyChanged will catch this change erroneously
|
||||
ignorePropertyUpdates = true;
|
||||
item->setCheckState(1, (bool)currentValue.get<Data::Bool>() ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
|
||||
ignorePropertyUpdates = false;
|
||||
} else if (meta.type == &Color3::TYPE) {
|
||||
Color3 color = currentValue.get<Color3>();
|
||||
item->setData(1, Qt::DecorationRole, QColor::fromRgbF(color.R(), color.G(), color.B()));
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace Data { class Variant; };
|
|||
class PropertiesView : public QTreeWidget {
|
||||
Q_DECLARE_PRIVATE(QTreeView)
|
||||
|
||||
bool ignorePropertyUpdates = false;
|
||||
InstanceRefWeak currentInstance;
|
||||
void propertyChanged(QTreeWidgetItem *item, int column);
|
||||
void activateProperty(QTreeWidgetItem *item, int column);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "common.h"
|
||||
#include "mainglwidget.h"
|
||||
#include "objects/joint/snap.h"
|
||||
#include "rendering/surface.h"
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <qboxlayout.h>
|
||||
|
@ -49,6 +50,7 @@ void PlaceDocument::closeEvent(QCloseEvent *closeEvent) {
|
|||
closeEvent->ignore();
|
||||
}
|
||||
|
||||
std::shared_ptr<Part> shit;
|
||||
static std::chrono::time_point lastTime = std::chrono::steady_clock::now();
|
||||
void PlaceDocument::timerEvent(QTimerEvent* evt) {
|
||||
if (evt->timerId() != timer.timerId()) {
|
||||
|
@ -65,10 +67,11 @@ void PlaceDocument::timerEvent(QTimerEvent* evt) {
|
|||
placeWidget->updateCycle();
|
||||
}
|
||||
|
||||
std::shared_ptr<Part> lastPart;
|
||||
|
||||
void PlaceDocument::init() {
|
||||
timer.start(33, this);
|
||||
|
||||
std::shared_ptr<Part> lastPart;
|
||||
// Baseplate
|
||||
gWorkspace()->AddChild(lastPart = Part::New({
|
||||
.position = glm::vec3(0, -5, 0),
|
||||
|
@ -100,13 +103,25 @@ void PlaceDocument::init() {
|
|||
gWorkspace()->SyncPartPhysics(lastPart);
|
||||
auto part1 = lastPart;
|
||||
|
||||
auto snap = Snap::New();
|
||||
snap->part0 = part0;
|
||||
snap->part1 = part1;
|
||||
snap->c0 = part1->cframe;
|
||||
snap->c1 = part0->cframe;
|
||||
lastPart = Part::New();
|
||||
shit = part1;
|
||||
|
||||
gWorkspace()->AddChild(snap);
|
||||
snap->UpdateProperty("Part0");
|
||||
snap->UpdateProperty("Part1");
|
||||
part0->anchored = true;
|
||||
part0->UpdateProperty("Anchored");
|
||||
|
||||
// auto snap = Snap::New();
|
||||
// snap->part0 = part0;
|
||||
// snap->part1 = part1;
|
||||
// snap->c0 = part1->cframe;
|
||||
// snap->c1 = part0->cframe;
|
||||
|
||||
// gWorkspace()->AddChild(snap);
|
||||
// snap->UpdateProperty("Part0");
|
||||
// snap->UpdateProperty("Part1");
|
||||
|
||||
// part0->backSurface = SurfaceWeld;
|
||||
// part1->frontSurface = SurfaceWeld;
|
||||
|
||||
part0->backSurface = SurfaceHinge;
|
||||
// part1->frontSurface = SurfaceHinge;
|
||||
}
|
Loading…
Add table
Reference in a new issue