Compare commits

...

9 commits

31 changed files with 239 additions and 77 deletions

View file

@ -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;

View file

@ -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);
}

View file

@ -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);

View file

@ -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;

View file

@ -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:

View file

@ -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();
}
}

View file

@ -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);

View file

@ -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);

View file

@ -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;
};

View file

@ -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;
};

View 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;
}

View 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>(); };
};

View file

@ -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;

View file

@ -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;
};

View file

@ -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;

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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");

View file

@ -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(); }

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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);
};

View file

@ -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();

View file

@ -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);

View file

@ -16,6 +16,7 @@ enum SurfaceType {
SurfaceStuds = 3,
SurfaceInlets = 4,
SurfaceUniversal = 5,
SurfaceHinge = 6,
};
namespace Data { class Vector3; } using Data::Vector3;

View file

@ -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) {

View file

@ -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));
}

View file

@ -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()));

View file

@ -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);

View file

@ -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;
}