Compare commits
1 commit
master
...
feature/cm
Author | SHA1 | Date | |
---|---|---|---|
2621f969ae |
71 changed files with 972 additions and 1565 deletions
1
.clangd
1
.clangd
|
@ -1,3 +1,2 @@
|
||||||
CompileFlags:
|
CompileFlags:
|
||||||
Add: [-std=c++20]
|
Add: [-std=c++20]
|
||||||
Remove: [-mno-direct-extern-access]
|
|
7
.vscode/launch.json
vendored
7
.vscode/launch.json
vendored
|
@ -4,13 +4,6 @@
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
|
||||||
"type": "gdb",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "Debug (gdb)",
|
|
||||||
"program": "${workspaceFolder}/build/bin/editor",
|
|
||||||
"cwd": "${workspaceFolder}",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "lldb",
|
"type": "lldb",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
|
|
|
@ -54,14 +54,11 @@ uniform int numPointLights;
|
||||||
uniform DirLight sunLight;
|
uniform DirLight sunLight;
|
||||||
uniform Material material;
|
uniform Material material;
|
||||||
uniform sampler2DArray studs;
|
uniform sampler2DArray studs;
|
||||||
uniform samplerCube skybox;
|
|
||||||
uniform float transparency;
|
uniform float transparency;
|
||||||
uniform float reflectance;
|
|
||||||
uniform vec3 texScale;
|
uniform vec3 texScale;
|
||||||
|
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
vec3 calculateReflection();
|
|
||||||
vec3 calculateDirectionalLight(DirLight light);
|
vec3 calculateDirectionalLight(DirLight light);
|
||||||
vec3 calculatePointLight(PointLight light);
|
vec3 calculatePointLight(PointLight light);
|
||||||
mat3 lookAlong(vec3 pos, vec3 forward, vec3 up);
|
mat3 lookAlong(vec3 pos, vec3 forward, vec3 up);
|
||||||
|
@ -71,7 +68,6 @@ mat3 lookAlong(vec3 pos, vec3 forward, vec3 up);
|
||||||
void main() {
|
void main() {
|
||||||
vec3 result = vec3(0.0);
|
vec3 result = vec3(0.0);
|
||||||
|
|
||||||
result += calculateReflection();
|
|
||||||
result += calculateDirectionalLight(sunLight);
|
result += calculateDirectionalLight(sunLight);
|
||||||
|
|
||||||
for (int i = 0; i < numPointLights; i++) {
|
for (int i = 0; i < numPointLights; i++) {
|
||||||
|
@ -99,25 +95,6 @@ mat3 lookAlong(vec3 pos, vec3 forward, vec3 up) {
|
||||||
return mat3(s, u, f);
|
return mat3(s, u, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
vec3 sampleSkybox()
|
|
||||||
{
|
|
||||||
vec3 norm = normalize(vNormal);
|
|
||||||
vec3 viewDir = normalize(viewPos - vPos);
|
|
||||||
vec3 reflectDir = reflect(-viewDir, norm);
|
|
||||||
|
|
||||||
return textureLod(skybox,reflectDir, 5.0 * (1.0-material.shininess)).rgb;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 calculateReflection() {
|
|
||||||
vec3 norm = normalize(vNormal);
|
|
||||||
vec3 viewDir = normalize(viewPos - vPos);
|
|
||||||
vec3 reflectDir = reflect(viewDir, norm);
|
|
||||||
float fresnel = (pow(1.0-max(dot(viewDir, norm), 0.0), 5.0));
|
|
||||||
vec3 result = sampleSkybox() * mix(/* TEMPORARY: will be replaced by setting */ 0 * /* /TEMPORARY */ fresnel * material.specular, vec3(1.0), reflectance);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 calculateDirectionalLight(DirLight light) {
|
vec3 calculateDirectionalLight(DirLight light) {
|
||||||
// Calculate diffuse
|
// Calculate diffuse
|
||||||
vec3 norm = normalize(vNormal);
|
vec3 norm = normalize(vNormal);
|
||||||
|
@ -128,13 +105,10 @@ vec3 calculateDirectionalLight(DirLight light) {
|
||||||
vec3 viewDir = normalize(viewPos - vPos);
|
vec3 viewDir = normalize(viewPos - vPos);
|
||||||
vec3 reflectDir = reflect(-lightDir, norm);
|
vec3 reflectDir = reflect(-lightDir, norm);
|
||||||
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
|
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
|
||||||
// float fresnel = (pow(1.0-max(dot(viewDir, norm), 0.0), 5.0));
|
|
||||||
|
|
||||||
|
vec3 ambient = light.ambient * material.diffuse;
|
||||||
vec3 ambient = light.ambient * (material.diffuse * (1.0-reflectance));
|
vec3 diffuse = light.diffuse * diff * material.diffuse;
|
||||||
vec3 diffuse = light.diffuse * diff * (material.diffuse * (1.0-reflectance));
|
|
||||||
vec3 specular = light.specular * spec * material.specular;
|
vec3 specular = light.specular * spec * material.specular;
|
||||||
// specular += sampleSkybox() * fresnel * material.specular;
|
|
||||||
|
|
||||||
return (ambient + diffuse + specular);
|
return (ambient + diffuse + specular);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "objects/part/part.h"
|
#include "objects/part/part.h"
|
||||||
#include "panic.h"
|
#include "panic.h"
|
||||||
#include "physics/world.h"
|
|
||||||
#include "rendering/renderer.h"
|
#include "rendering/renderer.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
@ -48,7 +47,6 @@ int main() {
|
||||||
Logger::debugf("Initialized GL context version %d.%d", GLAD_VERSION_MAJOR(version), GLAD_VERSION_MINOR(version));
|
Logger::debugf("Initialized GL context version %d.%d", GLAD_VERSION_MAJOR(version), GLAD_VERSION_MINOR(version));
|
||||||
}
|
}
|
||||||
|
|
||||||
physicsInit();
|
|
||||||
gDataModel->Init();
|
gDataModel->Init();
|
||||||
renderInit(1200, 900);
|
renderInit(1200, 900);
|
||||||
|
|
||||||
|
@ -88,7 +86,6 @@ int main() {
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
} while(!glfwWindowShouldClose(window));
|
} while(!glfwWindowShouldClose(window));
|
||||||
|
|
||||||
physicsDeinit();
|
|
||||||
glfwTerminate();
|
glfwTerminate();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,8 +57,6 @@ set(SOURCES
|
||||||
src/rendering/font.h
|
src/rendering/font.h
|
||||||
src/rendering/defaultmeshes.h
|
src/rendering/defaultmeshes.h
|
||||||
src/rendering/texture3d.cpp
|
src/rendering/texture3d.cpp
|
||||||
src/physics/world.h
|
|
||||||
src/physics/world.cpp
|
|
||||||
src/logger.cpp
|
src/logger.cpp
|
||||||
src/handles.h
|
src/handles.h
|
||||||
src/timeutil.h
|
src/timeutil.h
|
||||||
|
@ -128,6 +126,7 @@ set(SOURCES
|
||||||
src/panic.h
|
src/panic.h
|
||||||
src/lua/instancelib.cpp
|
src/lua/instancelib.cpp
|
||||||
src/timeutil.cpp
|
src/timeutil.cpp
|
||||||
|
src/physics/util.h
|
||||||
src/luaapis.h
|
src/luaapis.h
|
||||||
src/math_helper.h
|
src/math_helper.h
|
||||||
)
|
)
|
||||||
|
@ -198,8 +197,8 @@ list(APPEND SOURCES ${CMAKE_CURRENT_BINARY_DIR}/src/version.cpp)
|
||||||
add_library(openblocks STATIC ${SOURCES})
|
add_library(openblocks STATIC ${SOURCES})
|
||||||
set_target_properties(openblocks PROPERTIES OUTPUT_NAME "openblocks")
|
set_target_properties(openblocks PROPERTIES OUTPUT_NAME "openblocks")
|
||||||
target_link_directories(openblocks PUBLIC ${LUAJIT_LIBRARY_DIRS})
|
target_link_directories(openblocks PUBLIC ${LUAJIT_LIBRARY_DIRS})
|
||||||
target_link_libraries(openblocks Jolt pugixml::pugixml Freetype::Freetype glm::glm libluajit ${LuaJIT_LIBRARIES})
|
target_link_libraries(openblocks reactphysics3d pugixml::pugixml Freetype::Freetype glm::glm libluajit ${LuaJIT_LIBRARIES})
|
||||||
target_include_directories(openblocks PUBLIC "src" "../include" "${CMAKE_SOURCE_DIR}/external/glad" ${LUAJIT_INCLUDE_DIRS} ${stb_SOURCE_DIR})
|
target_include_directories(openblocks PUBLIC "src" "../include" "${CMAKE_SOURCE_DIR}/external/glad" ${ReactPhysics3D_SOURCE_DIR}/include ${LUAJIT_INCLUDE_DIRS} ${stb_SOURCE_DIR})
|
||||||
add_dependencies(openblocks autogen_build autogen)
|
add_dependencies(openblocks autogen_build autogen)
|
||||||
|
|
||||||
# Windows-specific dependencies
|
# Windows-specific dependencies
|
||||||
|
|
|
@ -6,7 +6,9 @@ set (PREV_BIN_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
|
||||||
unset (CMAKE_RUNTIME_OUTPUT_DIRECTORY)
|
unset (CMAKE_RUNTIME_OUTPUT_DIRECTORY)
|
||||||
|
|
||||||
CPMAddPackage("gh:g-truc/glm#1.0.1")
|
CPMAddPackage("gh:g-truc/glm#1.0.1")
|
||||||
CPMAddPackage(NAME Jolt GIT_REPOSITORY "https://github.com/jrouwe/JoltPhysics" VERSION 5.3.0 SOURCE_SUBDIR "Build")
|
CPMAddPackage(NAME reactphysics3d GITHUB_REPOSITORY "DanielChappuis/reactphysics3d" VERSION 0.10.2 PATCHES ${CMAKE_SOURCE_DIR}/patches/std_chrono.patch)
|
||||||
|
# https://github.com/StereoKit/StereoKit/blob/0be056efebcee5e58ad1438f4cf6dfdb942f6cf9/CMakeLists.txt#L205
|
||||||
|
set_property(TARGET reactphysics3d PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||||
CPMAddPackage("gh:zeux/pugixml@1.15")
|
CPMAddPackage("gh:zeux/pugixml@1.15")
|
||||||
|
|
||||||
CPMAddPackage(
|
CPMAddPackage(
|
||||||
|
|
|
@ -8,8 +8,9 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class Instance;
|
class Instance;
|
||||||
typedef std::function<void(std::shared_ptr<Instance> object, nullable std::shared_ptr<Instance> oldParent, nullable std::shared_ptr<Instance> newParent)> HierarchyPreUpdateHandler;
|
// typedef std::function<void(std::shared_ptr<Instance> element, std::optional<std::shared_ptr<Instance>> newParent)> HierarchyUpdateHandler;
|
||||||
typedef std::function<void(std::shared_ptr<Instance> object, nullable std::shared_ptr<Instance> oldParent, nullable std::shared_ptr<Instance> newParent)> HierarchyPostUpdateHandler;
|
typedef std::function<void(std::shared_ptr<Instance> object, std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent)> HierarchyPreUpdateHandler;
|
||||||
|
typedef std::function<void(std::shared_ptr<Instance> object, std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent)> HierarchyPostUpdateHandler;
|
||||||
typedef std::function<void(std::shared_ptr<Instance> instance, std::string property, Variant newValue)> PropertyUpdateHandler;
|
typedef std::function<void(std::shared_ptr<Instance> instance, std::string property, Variant newValue)> PropertyUpdateHandler;
|
||||||
|
|
||||||
// TEMPORARY COMMON DATA FOR VARIOUS INTERNAL COMPONENTS
|
// TEMPORARY COMMON DATA FOR VARIOUS INTERNAL COMPONENTS
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
#include "cframe.h"
|
#include "cframe.h"
|
||||||
#include "datatypes/vector.h"
|
#include "datatypes/vector.h"
|
||||||
#include "error/data.h"
|
#include "error/data.h"
|
||||||
|
#include "physics/util.h"
|
||||||
#include <glm/ext/matrix_transform.hpp>
|
#include <glm/ext/matrix_transform.hpp>
|
||||||
#include <glm/gtc/matrix_inverse.hpp>
|
#include <glm/gtc/matrix_inverse.hpp>
|
||||||
#include <glm/gtc/quaternion.hpp>
|
#include <glm/gtc/quaternion.hpp>
|
||||||
#include <glm/matrix.hpp>
|
#include <glm/matrix.hpp>
|
||||||
|
#include <reactphysics3d/mathematics/Transform.h>
|
||||||
#include "datatypes/variant.h"
|
#include "datatypes/variant.h"
|
||||||
#include <pugixml.hpp>
|
#include <pugixml.hpp>
|
||||||
#define GLM_ENABLE_EXPERIMENTAL
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
|
@ -38,6 +40,9 @@ CFrame::CFrame(Vector3 position, glm::quat quat)
|
||||||
, rotation(quat) {
|
, rotation(quat) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CFrame::CFrame(const rp::Transform& transform) : CFrame::CFrame(rpToGlm(transform.getPosition()), rpToGlm(transform.getOrientation())) {
|
||||||
|
}
|
||||||
|
|
||||||
glm::mat3 lookAt(Vector3 position, Vector3 lookAt, Vector3 up) {
|
glm::mat3 lookAt(Vector3 position, Vector3 lookAt, Vector3 up) {
|
||||||
// https://github.com/sgorsten/linalg/issues/29#issuecomment-743989030
|
// https://github.com/sgorsten/linalg/issues/29#issuecomment-743989030
|
||||||
Vector3 f = (lookAt - position).Unit(); // Forward/Look
|
Vector3 f = (lookAt - position).Unit(); // Forward/Look
|
||||||
|
@ -72,6 +77,10 @@ CFrame::operator glm::mat4() const {
|
||||||
return glm::translate(glm::mat4(1.0f), this->translation) * glm::mat4(this->rotation);
|
return glm::translate(glm::mat4(1.0f), this->translation) * glm::mat4(this->rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CFrame::operator rp::Transform() const {
|
||||||
|
return rp::Transform(glmToRp(translation), glmToRp(rotation));
|
||||||
|
}
|
||||||
|
|
||||||
Vector3 CFrame::ToEulerAnglesXYZ() {
|
Vector3 CFrame::ToEulerAnglesXYZ() {
|
||||||
float x;
|
float x;
|
||||||
float y;
|
float y;
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
#include <glm/gtc/matrix_access.hpp>
|
#include <glm/gtc/matrix_access.hpp>
|
||||||
#include <glm/matrix.hpp>
|
#include <glm/matrix.hpp>
|
||||||
|
|
||||||
|
namespace reactphysics3d { class Transform; };
|
||||||
|
|
||||||
class DEF_DATA_(name="CoordinateFrame") CFrame {
|
class DEF_DATA_(name="CoordinateFrame") CFrame {
|
||||||
AUTOGEN_PREAMBLE_DATA
|
AUTOGEN_PREAMBLE_DATA
|
||||||
|
|
||||||
|
@ -22,6 +24,7 @@ public:
|
||||||
DEF_DATA_CTOR CFrame();
|
DEF_DATA_CTOR CFrame();
|
||||||
DEF_DATA_CTOR CFrame(float x, float y, float z, float R00, float R01, float R02, float R10, float R11, float R12, float R20, float R21, float R22);
|
DEF_DATA_CTOR CFrame(float x, float y, float z, float R00, float R01, float R02, float R10, float R11, float R12, float R20, float R21, float R22);
|
||||||
DEF_DATA_CTOR CFrame(Vector3 , Vector3 lookAt, Vector3 up = Vector3(0, 1, 0));
|
DEF_DATA_CTOR CFrame(Vector3 , Vector3 lookAt, Vector3 up = Vector3(0, 1, 0));
|
||||||
|
CFrame(const reactphysics3d::Transform&);
|
||||||
CFrame(Vector3 position, glm::quat quat);
|
CFrame(Vector3 position, glm::quat quat);
|
||||||
virtual ~CFrame();
|
virtual ~CFrame();
|
||||||
|
|
||||||
|
@ -43,11 +46,11 @@ public:
|
||||||
static void PushLuaLibrary(lua_State*);
|
static void PushLuaLibrary(lua_State*);
|
||||||
|
|
||||||
operator glm::mat4() const;
|
operator glm::mat4() const;
|
||||||
|
operator reactphysics3d::Transform() const;
|
||||||
|
|
||||||
//inline static CFrame identity() { }
|
//inline static CFrame identity() { }
|
||||||
DEF_DATA_PROP inline Vector3 Position() const { return translation; }
|
DEF_DATA_PROP inline Vector3 Position() const { return translation; }
|
||||||
DEF_DATA_PROP inline CFrame Rotation() const { return CFrame { glm::vec3(0, 0, 0), rotation }; }
|
DEF_DATA_PROP inline CFrame Rotation() const { return CFrame { glm::vec3(0, 0, 0), rotation }; }
|
||||||
inline glm::mat3 RotMatrix() const { return rotation; }
|
|
||||||
DEF_DATA_METHOD CFrame Inverse() const;
|
DEF_DATA_METHOD CFrame Inverse() const;
|
||||||
DEF_DATA_PROP inline float X() const { return translation.x; }
|
DEF_DATA_PROP inline float X() const { return translation.x; }
|
||||||
DEF_DATA_PROP inline float Y() const { return translation.y; }
|
DEF_DATA_PROP inline float Y() const { return translation.y; }
|
||||||
|
|
|
@ -68,7 +68,7 @@ void Bool_PushLuaValue(Variant self, lua_State* L) {
|
||||||
result<Variant, LuaCastError> Bool_FromLuaValue(lua_State* L, int idx) {
|
result<Variant, LuaCastError> Bool_FromLuaValue(lua_State* L, int idx) {
|
||||||
if (!lua_isboolean(L, idx))
|
if (!lua_isboolean(L, idx))
|
||||||
return LuaCastError(lua_typename(L, idx), "boolean");
|
return LuaCastError(lua_typename(L, idx), "boolean");
|
||||||
return Variant((bool)lua_toboolean(L, idx));
|
return Variant(lua_toboolean(L, idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
const TypeDesc BOOL_TYPE {
|
const TypeDesc BOOL_TYPE {
|
||||||
|
|
|
@ -151,9 +151,9 @@ static int inst_index(lua_State* L) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for child
|
// Look for child
|
||||||
nullable std::shared_ptr<Instance> child = inst->FindFirstChild(key);
|
std::optional<std::shared_ptr<Instance>> child = inst->FindFirstChild(key);
|
||||||
if (child) {
|
if (child) {
|
||||||
InstanceRef(child).PushLuaValue(L);
|
InstanceRef(child.value()).PushLuaValue(L);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,7 +173,7 @@ static int inst_newindex(lua_State* L) {
|
||||||
if (meta->flags & PROP_READONLY)
|
if (meta->flags & PROP_READONLY)
|
||||||
return luaL_error(L, "'%s' of %s is read-only", key.c_str(), inst->GetClass()->className.c_str());
|
return luaL_error(L, "'%s' of %s is read-only", key.c_str(), inst->GetClass()->className.c_str());
|
||||||
if (key == "Parent" && inst->IsParentLocked())
|
if (key == "Parent" && inst->IsParentLocked())
|
||||||
return luaL_error(L, "Cannot set property Parent (%s) of %s, parent is locked", inst->GetParent() ? inst->GetParent()->name.c_str() : "NULL", inst->GetClass()->className.c_str());
|
return luaL_error(L, "Cannot set property Parent (%s) of %s, parent is locked", inst->GetParent() ? inst->GetParent().value()->name.c_str() : "NULL", inst->GetClass()->className.c_str());
|
||||||
|
|
||||||
// TODO: Make this work for enums, this is not a solution!!
|
// TODO: Make this work for enums, this is not a solution!!
|
||||||
result<Variant, LuaCastError> value = meta->type.descriptor->fromLuaValue(L, -1);
|
result<Variant, LuaCastError> value = meta->type.descriptor->fromLuaValue(L, -1);
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <glm/ext/quaternion_geometric.hpp>
|
#include <glm/ext/quaternion_geometric.hpp>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
#include <reactphysics3d/mathematics/Vector3.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <pugixml.hpp>
|
#include <pugixml.hpp>
|
||||||
#include "datatypes/base.h"
|
#include "datatypes/base.h"
|
||||||
|
@ -10,8 +11,11 @@
|
||||||
#include "error/data.h"
|
#include "error/data.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace rp = reactphysics3d;
|
||||||
|
|
||||||
Vector3::Vector3() : vector(glm::vec3(0, 0, 0)) {};
|
Vector3::Vector3() : vector(glm::vec3(0, 0, 0)) {};
|
||||||
Vector3::Vector3(const glm::vec3& src) : vector(src) {};
|
Vector3::Vector3(const glm::vec3& src) : vector(src) {};
|
||||||
|
Vector3::Vector3(const rp::Vector3& src) : vector(glm::vec3(src.x, src.y, src.z)) {};
|
||||||
Vector3::Vector3(float x, const float y, float z) : vector(glm::vec3(x, y, z)) {};
|
Vector3::Vector3(float x, const float y, float z) : vector(glm::vec3(x, y, z)) {};
|
||||||
|
|
||||||
Vector3::~Vector3() = default;
|
Vector3::~Vector3() = default;
|
||||||
|
@ -27,6 +31,7 @@ const std::string Vector3::ToString() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3::operator glm::vec3() const { return vector; };
|
Vector3::operator glm::vec3() const { return vector; };
|
||||||
|
Vector3::operator rp::Vector3() const { return rp::Vector3(X(), Y(), Z()); };
|
||||||
|
|
||||||
// Operators
|
// Operators
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
#include "error/data.h"
|
#include "error/data.h"
|
||||||
#include <glm/ext/vector_float3.hpp>
|
#include <glm/ext/vector_float3.hpp>
|
||||||
#include <glm/geometric.hpp>
|
#include <glm/geometric.hpp>
|
||||||
|
#include <reactphysics3d/mathematics/Vector3.h>
|
||||||
|
|
||||||
|
// namespace reactphysics3d { class Vector3; };
|
||||||
|
|
||||||
class DEF_DATA Vector3 {
|
class DEF_DATA Vector3 {
|
||||||
AUTOGEN_PREAMBLE_DATA
|
AUTOGEN_PREAMBLE_DATA
|
||||||
|
@ -15,6 +18,7 @@ public:
|
||||||
DEF_DATA_CTOR Vector3(float x, float y, float z);
|
DEF_DATA_CTOR Vector3(float x, float y, float z);
|
||||||
inline Vector3(float value) : Vector3(value, value, value) {}
|
inline Vector3(float value) : Vector3(value, value, value) {}
|
||||||
Vector3(const glm::vec3&);
|
Vector3(const glm::vec3&);
|
||||||
|
Vector3(const reactphysics3d::Vector3&);
|
||||||
virtual ~Vector3();
|
virtual ~Vector3();
|
||||||
|
|
||||||
DEF_DATA_PROP static Vector3 ZERO;
|
DEF_DATA_PROP static Vector3 ZERO;
|
||||||
|
@ -29,6 +33,7 @@ public:
|
||||||
static void PushLuaLibrary(lua_State*);
|
static void PushLuaLibrary(lua_State*);
|
||||||
|
|
||||||
operator glm::vec3() const;
|
operator glm::vec3() const;
|
||||||
|
operator reactphysics3d::Vector3() const;
|
||||||
|
|
||||||
DEF_DATA_PROP inline float X() const { return vector.x; }
|
DEF_DATA_PROP inline float X() const { return vector.x; }
|
||||||
DEF_DATA_PROP inline float Y() const { return vector.y; }
|
DEF_DATA_PROP inline float Y() const { return vector.y; }
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
enum class DEF_ENUM PartType {
|
enum class DEF_ENUM PartType {
|
||||||
Ball = 0,
|
Ball = 0,
|
||||||
Block = 1,
|
Block = 1,
|
||||||
Cylinder = 2,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace EnumType {
|
namespace EnumType {
|
||||||
|
|
|
@ -8,6 +8,10 @@
|
||||||
#include <glm/ext/scalar_common.hpp>
|
#include <glm/ext/scalar_common.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <reactphysics3d/collision/RaycastInfo.h>
|
||||||
|
#include <reactphysics3d/engine/PhysicsCommon.h>
|
||||||
|
#include <reactphysics3d/engine/PhysicsWorld.h>
|
||||||
|
#include <reactphysics3d/mathematics/Transform.h>
|
||||||
|
|
||||||
HandleFace HandleFace::XPos(0, glm::vec3(1,0,0));
|
HandleFace HandleFace::XPos(0, glm::vec3(1,0,0));
|
||||||
HandleFace HandleFace::XNeg(1, glm::vec3(-1,0,0));
|
HandleFace HandleFace::XNeg(1, glm::vec3(-1,0,0));
|
||||||
|
@ -19,6 +23,10 @@ std::array<HandleFace, 6> HandleFace::Faces { HandleFace::XPos, HandleFace::XNeg
|
||||||
|
|
||||||
static CFrame XYZToZXY(glm::vec3(0, 0, 0), -glm::vec3(1, 0, 0), glm::vec3(0, 0, 1));
|
static CFrame XYZToZXY(glm::vec3(0, 0, 0), -glm::vec3(1, 0, 0), glm::vec3(0, 0, 1));
|
||||||
|
|
||||||
|
// Shitty solution
|
||||||
|
static rp3d::PhysicsCommon common;
|
||||||
|
static rp3d::PhysicsWorld* world = common.createPhysicsWorld();
|
||||||
|
|
||||||
std::shared_ptr<BasePart> getHandleAdornee() {
|
std::shared_ptr<BasePart> getHandleAdornee() {
|
||||||
std::shared_ptr<Selection> selection = gDataModel->GetService<Selection>();
|
std::shared_ptr<Selection> selection = gDataModel->GetService<Selection>();
|
||||||
for (std::weak_ptr<Instance> inst : selection->Get()) {
|
for (std::weak_ptr<Instance> inst : selection->Get()) {
|
||||||
|
@ -44,25 +52,24 @@ CFrame partCFrameFromHandlePos(HandleFace face, Vector3 newPos) {
|
||||||
return adornee->cframe.Rotation() + newPartPos;
|
return adornee->cframe.Rotation() + newPartPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<HandleFace> raycastHandle(Vector3 rayStart, Vector3 rayEnd) {
|
std::optional<HandleFace> raycastHandle(rp3d::Ray ray) {
|
||||||
std::optional<HandleFace> closestFace = {};
|
|
||||||
float closestDistance = -1;
|
|
||||||
|
|
||||||
for (HandleFace face : HandleFace::Faces) {
|
for (HandleFace face : HandleFace::Faces) {
|
||||||
CFrame cframe = getHandleCFrame(face);
|
CFrame cframe = getHandleCFrame(face);
|
||||||
|
// Implement manual detection via boxes instead of... this shit
|
||||||
|
// This code also hardly works, and is not good at all... Hooo nope.
|
||||||
|
rp3d::RigidBody* body = world->createRigidBody(CFrame::IDENTITY + cframe.Position());
|
||||||
|
body->addCollider(common.createBoxShape((cframe.Rotation() * Vector3(handleSize(face) / 2.f)).Abs()), rp3d::Transform::identity());
|
||||||
|
|
||||||
Vector3 halfSize = (cframe.Rotation() * Vector3(handleSize(face) / 2.f)).Abs();
|
rp3d::RaycastInfo info;
|
||||||
Vector3 minB = cframe.Position() - halfSize, maxB = cframe.Position() + halfSize;
|
if (body->raycast(ray, info)) {
|
||||||
|
world->destroyRigidBody(body);
|
||||||
glm::vec3 hitPoint;
|
return face;
|
||||||
bool hit = HitBoundingBox(minB, maxB, rayStart, (rayEnd - rayStart).Unit(), hitPoint);
|
|
||||||
float distance = ((Vector3)hitPoint - rayStart).Magnitude();
|
|
||||||
|
|
||||||
if (hit && (closestDistance == -1 || distance < closestDistance))
|
|
||||||
closestFace = face, closestDistance = distance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return closestFace;
|
world->destroyRigidBody(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 handleSize(HandleFace face) {
|
Vector3 handleSize(HandleFace face) {
|
||||||
|
|
|
@ -40,7 +40,7 @@ std::shared_ptr<BasePart> getHandleAdornee();
|
||||||
CFrame getHandleCFrame(HandleFace face);
|
CFrame getHandleCFrame(HandleFace face);
|
||||||
CFrame partCFrameFromHandlePos(HandleFace face, Vector3 newPos);
|
CFrame partCFrameFromHandlePos(HandleFace face, Vector3 newPos);
|
||||||
Vector3 handleSize(HandleFace face);
|
Vector3 handleSize(HandleFace face);
|
||||||
std::optional<HandleFace> raycastHandle(Vector3 rayStart, Vector3 rayEnd);
|
std::optional<HandleFace> raycastHandle(rp3d::Ray ray);
|
||||||
|
|
||||||
// Gets the cframe of the handle local to the center of the selected objects
|
// Gets the cframe of the handle local to the center of the selected objects
|
||||||
CFrame getLocalHandleCFrame(HandleFace face);
|
CFrame getLocalHandleCFrame(HandleFace face);
|
||||||
|
|
|
@ -2,65 +2,9 @@
|
||||||
|
|
||||||
#define CMP_EPSILON 0.00001
|
#define CMP_EPSILON 0.00001
|
||||||
|
|
||||||
|
|
||||||
void expandAABB(glm::vec3& min, glm::vec3& max, glm::vec3 point) {
|
|
||||||
min = glm::vec3(glm::min(min.x, point.x), glm::min(min.y, point.y), glm::min(min.z, point.z));
|
|
||||||
max = glm::vec3(glm::max(max.x, point.x), glm::max(max.y, point.y), glm::max(max.z, point.z));
|
|
||||||
}
|
|
||||||
|
|
||||||
void computeAABBFromPoints(glm::vec3& min, glm::vec3& max, glm::vec3* points, int count) {
|
|
||||||
if (count == 0) return;
|
|
||||||
|
|
||||||
min = points[0];
|
|
||||||
max = points[0];
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
min = glm::vec3(glm::min(min.x, points[i].x), glm::min(min.y, points[i].y), glm::min(min.z, points[i].z));
|
|
||||||
max = glm::vec3(glm::max(max.x, points[i].x), glm::max(max.y, points[i].y), glm::max(max.z, points[i].z));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void getAABBCoords(glm::vec3 &pos, glm::vec3 &size, glm::vec3 min, glm::vec3 max) {
|
|
||||||
pos = (max + min) / 2.f;
|
|
||||||
size = (max - min);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ==================== THIRD-PARTY SOURCE CODE ==================== //
|
|
||||||
|
|
||||||
// After a long time researching, I was able to use and adapt Godot's implementation of movable handles (godot/editor/plugins/gizmos/gizmo_3d_helper.cpp)
|
// After a long time researching, I was able to use and adapt Godot's implementation of movable handles (godot/editor/plugins/gizmos/gizmo_3d_helper.cpp)
|
||||||
// All thanks goes to them and David Eberly for his algorithm.
|
// All thanks goes to them and David Eberly for his algorithm.
|
||||||
|
|
||||||
/**************************************************************************/
|
|
||||||
/* geometry_3d.cpp */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* This file is part of: */
|
|
||||||
/* GODOT ENGINE */
|
|
||||||
/* https://godotengine.org */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
|
||||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
|
||||||
/* */
|
|
||||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
|
||||||
/* a copy of this software and associated documentation files (the */
|
|
||||||
/* "Software"), to deal in the Software without restriction, including */
|
|
||||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
||||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
|
||||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
|
||||||
/* the following conditions: */
|
|
||||||
/* */
|
|
||||||
/* The above copyright notice and this permission notice shall be */
|
|
||||||
/* included in all copies or substantial portions of the Software. */
|
|
||||||
/* */
|
|
||||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
|
||||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
|
||||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
|
||||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
|
||||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
|
||||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
||||||
/**************************************************************************/
|
|
||||||
|
|
||||||
void get_closest_points_between_segments(const glm::vec3 &p_p0, const glm::vec3 &p_p1, const glm::vec3 &p_q0, const glm::vec3 &p_q1, glm::vec3 &r_ps, glm::vec3 &r_qt) {
|
void get_closest_points_between_segments(const glm::vec3 &p_p0, const glm::vec3 &p_p1, const glm::vec3 &p_q0, const glm::vec3 &p_q1, glm::vec3 &r_ps, glm::vec3 &r_qt) {
|
||||||
// Based on David Eberly's Computation of Distance Between Line Segments algorithm.
|
// Based on David Eberly's Computation of Distance Between Line Segments algorithm.
|
||||||
|
|
||||||
|
@ -158,83 +102,24 @@ void get_closest_points_between_segments(const glm::vec3 &p_p0, const glm::vec3
|
||||||
r_qt = (1 - t) * p_q0 + t * p_q1;
|
r_qt = (1 - t) * p_q0 + t * p_q1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/erich666/GraphicsGems/tree/master?tab=License-1-ov-file#readme
|
void expandAABB(glm::vec3& min, glm::vec3& max, glm::vec3 point) {
|
||||||
// Note: The code below predates open source
|
min = glm::vec3(glm::min(min.x, point.x), glm::min(min.y, point.y), glm::min(min.z, point.z));
|
||||||
|
max = glm::vec3(glm::max(max.x, point.x), glm::max(max.y, point.y), glm::max(max.z, point.z));
|
||||||
/*
|
|
||||||
* EULA: The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code as your own
|
|
||||||
* and resell it. Using the code is permitted in any program, product, or library, non-commercial or commercial. Giving
|
|
||||||
* credit is not required, though is a nice gesture. The code comes as-is, and if there are any flaws or problems with
|
|
||||||
* any Gems code, nobody involved with Gems - authors, editors, publishers, or webmasters - are to be held responsible.
|
|
||||||
* Basically, don't be a jerk, and remember that anything free comes with no guarantee.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Fast Ray-Box Intersection
|
|
||||||
by Andrew Woo
|
|
||||||
from "Graphics Gems", Academic Press, 1990
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define RIGHT 0
|
|
||||||
#define LEFT 1
|
|
||||||
#define MIDDLE 2
|
|
||||||
|
|
||||||
bool HitBoundingBox(
|
|
||||||
glm::vec3 minB, glm::vec3 maxB, /*box */
|
|
||||||
glm::vec3 origin, glm::vec3 dir, /*ray */
|
|
||||||
glm::vec3 &coord /* hit point */
|
|
||||||
) {
|
|
||||||
bool inside = true;
|
|
||||||
glm::vec3 quadrant;
|
|
||||||
int i;
|
|
||||||
int whichPlane;
|
|
||||||
glm::vec3 maxT;
|
|
||||||
glm::vec3 candidatePlane;
|
|
||||||
|
|
||||||
/* Find candidate planes; this loop can be avoided if
|
|
||||||
rays cast all from the eye(assume perpsective view) */
|
|
||||||
for (i = 0; i < 3; i++)
|
|
||||||
if(origin[i] < minB[i]) {
|
|
||||||
quadrant[i] = LEFT;
|
|
||||||
candidatePlane[i] = minB[i];
|
|
||||||
inside = false;
|
|
||||||
}else if (origin[i] > maxB[i]) {
|
|
||||||
quadrant[i] = RIGHT;
|
|
||||||
candidatePlane[i] = maxB[i];
|
|
||||||
inside = false;
|
|
||||||
}else {
|
|
||||||
quadrant[i] = MIDDLE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ray origin inside bounding box */
|
void computeAABBFromPoints(glm::vec3& min, glm::vec3& max, glm::vec3* points, int count) {
|
||||||
if (inside) {
|
if (count == 0) return;
|
||||||
coord = origin;
|
|
||||||
return (true);
|
min = points[0];
|
||||||
|
max = points[0];
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
min = glm::vec3(glm::min(min.x, points[i].x), glm::min(min.y, points[i].y), glm::min(min.z, points[i].z));
|
||||||
|
max = glm::vec3(glm::max(max.x, points[i].x), glm::max(max.y, points[i].y), glm::max(max.z, points[i].z));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void getAABBCoords(glm::vec3 &pos, glm::vec3 &size, glm::vec3 min, glm::vec3 max) {
|
||||||
/* Calculate T distances to candidate planes */
|
pos = (max + min) / 2.f;
|
||||||
for (i = 0; i < 3; i++)
|
size = (max - min);
|
||||||
if (quadrant[i] != MIDDLE && dir[i] !=0.)
|
|
||||||
maxT[i] = (candidatePlane[i]-origin[i]) / dir[i];
|
|
||||||
else
|
|
||||||
maxT[i] = -1.;
|
|
||||||
|
|
||||||
/* Get largest of the maxT's for final choice of intersection */
|
|
||||||
whichPlane = 0;
|
|
||||||
for (i = 1; i < 3; i++)
|
|
||||||
if (maxT[whichPlane] < maxT[i])
|
|
||||||
whichPlane = i;
|
|
||||||
|
|
||||||
/* Check final candidate actually inside box */
|
|
||||||
if (maxT[whichPlane] < 0.) return (false);
|
|
||||||
for (i = 0; i < 3; i++)
|
|
||||||
if (whichPlane != i) {
|
|
||||||
coord[i] = origin[i] + maxT[whichPlane] * dir[i];
|
|
||||||
if (coord[i] < minB[i] || coord[i] > maxB[i])
|
|
||||||
return (false);
|
|
||||||
} else {
|
|
||||||
coord[i] = candidatePlane[i];
|
|
||||||
}
|
|
||||||
return true; /* ray hits box */
|
|
||||||
}
|
}
|
|
@ -1,20 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
void expandAABB(glm::vec3& min, glm::vec3& max, glm::vec3 point);
|
|
||||||
void computeAABBFromPoints(glm::vec3& min, glm::vec3& max, glm::vec3* points, int count);
|
|
||||||
void getAABBCoords(glm::vec3& pos, glm::vec3& size, glm::vec3 min, glm::vec3 max);
|
|
||||||
|
|
||||||
// From godot/editor/plugins/gizmos/gizmo_3d_helper.h
|
// From godot/editor/plugins/gizmos/gizmo_3d_helper.h
|
||||||
void get_closest_points_between_segments(const glm::vec3 &p_p0, const glm::vec3 &p_p1, const glm::vec3 &p_q0, const glm::vec3 &p_q1, glm::vec3 &r_ps, glm::vec3 &r_qt);
|
void get_closest_points_between_segments(const glm::vec3 &p_p0, const glm::vec3 &p_p1, const glm::vec3 &p_q0, const glm::vec3 &p_q1, glm::vec3 &r_ps, glm::vec3 &r_qt);
|
||||||
|
|
||||||
/*
|
void expandAABB(glm::vec3& min, glm::vec3& max, glm::vec3 point);
|
||||||
Fast Ray-Box Intersection
|
void computeAABBFromPoints(glm::vec3& min, glm::vec3& max, glm::vec3* points, int count);
|
||||||
by Andrew Woo
|
void getAABBCoords(glm::vec3& pos, glm::vec3& size, glm::vec3 min, glm::vec3 max);
|
||||||
from "Graphics Gems", Academic Press, 1990
|
|
||||||
*/
|
|
||||||
bool HitBoundingBox(
|
|
||||||
glm::vec3 minB, glm::vec3 maxB, /*box */
|
|
||||||
glm::vec3 origin, glm::vec3 dir, /*ray */
|
|
||||||
glm::vec3 &coord /* hit point */
|
|
||||||
);
|
|
|
@ -44,16 +44,21 @@ Instance::Instance(const InstanceType* type) {
|
||||||
Instance::~Instance () {
|
Instance::~Instance () {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::weak_ptr<T> optional_to_weak(std::optional<std::shared_ptr<T>> a) {
|
||||||
|
return a ? a.value() : std::weak_ptr<T>();
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Test this
|
// TODO: Test this
|
||||||
bool Instance::ancestryContinuityCheck(nullable std::shared_ptr<Instance> newParent) {
|
bool Instance::ancestryContinuityCheck(std::optional<std::shared_ptr<Instance>> newParent) {
|
||||||
for (std::shared_ptr<Instance> currentParent = newParent; currentParent != nullptr; currentParent = currentParent->GetParent()) {
|
for (std::optional<std::shared_ptr<Instance>> currentParent = newParent; currentParent.has_value(); currentParent = currentParent.value()->GetParent()) {
|
||||||
if (currentParent == this->shared_from_this())
|
if (currentParent.value() == this->shared_from_this())
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Instance::SetParent(nullable std::shared_ptr<Instance> newParent) {
|
bool Instance::SetParent(std::optional<std::shared_ptr<Instance>> newParent) {
|
||||||
if (this->parentLocked || !ancestryContinuityCheck(newParent))
|
if (this->parentLocked || !ancestryContinuityCheck(newParent))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -65,10 +70,10 @@ bool Instance::SetParent(nullable std::shared_ptr<Instance> newParent) {
|
||||||
oldParent->children.erase(std::find(oldParent->children.begin(), oldParent->children.end(), this->shared_from_this()));
|
oldParent->children.erase(std::find(oldParent->children.begin(), oldParent->children.end(), this->shared_from_this()));
|
||||||
}
|
}
|
||||||
// Add ourselves to the new parent
|
// Add ourselves to the new parent
|
||||||
if (newParent != nullptr) {
|
if (newParent.has_value()) {
|
||||||
newParent->children.push_back(this->shared_from_this());
|
newParent.value()->children.push_back(this->shared_from_this());
|
||||||
}
|
}
|
||||||
this->parent = newParent;
|
this->parent = optional_to_weak(newParent);
|
||||||
// TODO: Add code for sending signals for parent updates
|
// TODO: Add code for sending signals for parent updates
|
||||||
// TODO: Yeahhh maybe this isn't the best way of doing this?
|
// TODO: Yeahhh maybe this isn't the best way of doing this?
|
||||||
if (hierarchyPostUpdateHandler.has_value()) hierarchyPostUpdateHandler.value()(this->shared_from_this(), lastParent, newParent);
|
if (hierarchyPostUpdateHandler.has_value()) hierarchyPostUpdateHandler.value()(this->shared_from_this(), lastParent, newParent);
|
||||||
|
@ -80,21 +85,21 @@ bool Instance::SetParent(nullable std::shared_ptr<Instance> newParent) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::updateAncestry(nullable std::shared_ptr<Instance> updatedChild, nullable std::shared_ptr<Instance> newParent) {
|
void Instance::updateAncestry(std::optional<std::shared_ptr<Instance>> updatedChild, std::optional<std::shared_ptr<Instance>> newParent) {
|
||||||
auto oldDataModel = _dataModel;
|
auto oldDataModel = _dataModel;
|
||||||
auto oldWorkspace = _workspace;
|
auto oldWorkspace = _workspace;
|
||||||
|
|
||||||
// Update parent data model and workspace, if applicable
|
// Update parent data model and workspace, if applicable
|
||||||
if (GetParent() != nullptr) {
|
if (GetParent()) {
|
||||||
this->_dataModel = GetParent()->GetClass() == &DataModel::TYPE ? std::dynamic_pointer_cast<DataModel>(GetParent()) : GetParent()->_dataModel;
|
this->_dataModel = GetParent().value()->GetClass() == &DataModel::TYPE ? std::dynamic_pointer_cast<DataModel>(GetParent().value()) : GetParent().value()->_dataModel;
|
||||||
this->_workspace = GetParent()->GetClass() == &Workspace::TYPE ? std::dynamic_pointer_cast<Workspace>(GetParent()) : GetParent()->_workspace;
|
this->_workspace = GetParent().value()->GetClass() == &Workspace::TYPE ? std::dynamic_pointer_cast<Workspace>(GetParent().value()) : GetParent().value()->_workspace;
|
||||||
} else {
|
} else {
|
||||||
this->_dataModel = {};
|
this->_dataModel = {};
|
||||||
this->_workspace = {};
|
this->_workspace = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
OnAncestryChanged(updatedChild, newParent);
|
OnAncestryChanged(updatedChild, newParent);
|
||||||
AncestryChanged->Fire({updatedChild != nullptr ? InstanceRef(updatedChild) : InstanceRef(), newParent != nullptr ? InstanceRef(newParent) : InstanceRef()});
|
AncestryChanged->Fire({updatedChild.has_value() ? InstanceRef(updatedChild.value()) : InstanceRef(), newParent.has_value() ? InstanceRef(newParent.value()) : InstanceRef()});
|
||||||
|
|
||||||
// Old workspace used to exist, and workspaces differ
|
// Old workspace used to exist, and workspaces differ
|
||||||
if (!oldWorkspace.expired() && oldWorkspace != _workspace) {
|
if (!oldWorkspace.expired() && oldWorkspace != _workspace) {
|
||||||
|
@ -103,7 +108,7 @@ void Instance::updateAncestry(nullable std::shared_ptr<Instance> updatedChild, n
|
||||||
|
|
||||||
// New workspace exists, and workspaces differ
|
// New workspace exists, and workspaces differ
|
||||||
if (!_workspace.expired() && (_workspace != oldWorkspace)) {
|
if (!_workspace.expired() && (_workspace != oldWorkspace)) {
|
||||||
OnWorkspaceAdded(oldWorkspace.expired() ? nullptr : oldWorkspace.lock(), _workspace.lock());
|
OnWorkspaceAdded(!oldWorkspace.expired() ? std::make_optional(oldWorkspace.lock()) : std::nullopt, _workspace.lock());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update ancestry in descendants
|
// Update ancestry in descendants
|
||||||
|
@ -112,22 +117,23 @@ void Instance::updateAncestry(nullable std::shared_ptr<Instance> updatedChild, n
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nullable std::shared_ptr<DataModel> Instance::dataModel() {
|
std::optional<std::shared_ptr<DataModel>> Instance::dataModel() {
|
||||||
return _dataModel.expired() ? nullptr : _dataModel.lock();
|
return (_dataModel.expired()) ? std::nullopt : std::make_optional(_dataModel.lock());
|
||||||
}
|
}
|
||||||
|
|
||||||
nullable std::shared_ptr<Workspace> Instance::workspace() {
|
std::optional<std::shared_ptr<Workspace>> Instance::workspace() {
|
||||||
return _workspace.expired() ? nullptr : _workspace.lock();
|
return (_workspace.expired()) ? std::nullopt : std::make_optional(_workspace.lock());
|
||||||
}
|
}
|
||||||
|
|
||||||
nullable std::shared_ptr<Instance> Instance::GetParent() {
|
std::optional<std::shared_ptr<Instance>> Instance::GetParent() {
|
||||||
return parent.expired() ? nullptr : parent.lock();
|
if (parent.expired()) return std::nullopt;
|
||||||
|
return parent.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::Destroy() {
|
void Instance::Destroy() {
|
||||||
if (parentLocked) return;
|
if (parentLocked) return;
|
||||||
// TODO: Implement proper distruction stuff
|
// TODO: Implement proper distruction stuff
|
||||||
SetParent(nullptr);
|
SetParent(std::nullopt);
|
||||||
parentLocked = true;
|
parentLocked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,12 +143,12 @@ bool Instance::IsA(std::string className) {
|
||||||
return cur != nullptr;
|
return cur != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
nullable std::shared_ptr<Instance> Instance::FindFirstChild(std::string name) {
|
std::optional<std::shared_ptr<Instance>> Instance::FindFirstChild(std::string name) {
|
||||||
for (auto child : children) {
|
for (auto child : children) {
|
||||||
if (child->name == name)
|
if (child->name == name)
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::shared_ptr<Instance> DUMMY_INSTANCE;
|
static std::shared_ptr<Instance> DUMMY_INSTANCE;
|
||||||
|
@ -158,15 +164,15 @@ bool Instance::IsParentLocked() {
|
||||||
return this->parentLocked;
|
return this->parentLocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::OnParentUpdated(nullable std::shared_ptr<Instance> oldParent, nullable std::shared_ptr<Instance> newParent) {
|
void Instance::OnParentUpdated(std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent) {
|
||||||
// Empty stub
|
// Empty stub
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::OnAncestryChanged(nullable std::shared_ptr<Instance> child, nullable std::shared_ptr<Instance> newParent) {
|
void Instance::OnAncestryChanged(std::optional<std::shared_ptr<Instance>> child, std::optional<std::shared_ptr<Instance>> newParent) {
|
||||||
// Empty stub
|
// Empty stub
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::OnWorkspaceAdded(nullable std::shared_ptr<Workspace> oldWorkspace, std::shared_ptr<Workspace> newWorkspace) {
|
void Instance::OnWorkspaceAdded(std::optional<std::shared_ptr<Workspace>> oldWorkspace, std::shared_ptr<Workspace> newWorkspace) {
|
||||||
// Empty stub
|
// Empty stub
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,7 +230,7 @@ fallible<MemberNotFound, AssignToReadOnlyMember> Instance::InternalSetPropertyVa
|
||||||
this->name = (std::string)value.get<std::string>();
|
this->name = (std::string)value.get<std::string>();
|
||||||
} else if (name == "Parent") {
|
} else if (name == "Parent") {
|
||||||
std::weak_ptr<Instance> ref = value.get<InstanceRef>();
|
std::weak_ptr<Instance> ref = value.get<InstanceRef>();
|
||||||
SetParent(ref.expired() ? nullptr : ref.lock());
|
SetParent(ref.expired() ? std::nullopt : std::make_optional(ref.lock()));
|
||||||
} else if (name == "ClassName") {
|
} else if (name == "ClassName") {
|
||||||
return AssignToReadOnlyMember(GetClass()->className, name);
|
return AssignToReadOnlyMember(GetClass()->className, name);
|
||||||
} else {
|
} else {
|
||||||
|
@ -424,9 +430,9 @@ DescendantsIterator::self_type DescendantsIterator::operator++(int _) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we've hit the end of this item's children, move one up
|
// If we've hit the end of this item's children, move one up
|
||||||
while (current->GetParent() != nullptr && current->GetParent()->GetChildren().size() <= size_t(siblingIndex.back() + 1)) {
|
while (current->GetParent() && current->GetParent().value()->GetChildren().size() <= size_t(siblingIndex.back() + 1)) {
|
||||||
siblingIndex.pop_back();
|
siblingIndex.pop_back();
|
||||||
current = current->GetParent();
|
current = current->GetParent().value();
|
||||||
|
|
||||||
// But not if one up is null or the root element
|
// But not if one up is null or the root element
|
||||||
if (!current->GetParent() || current == root) {
|
if (!current->GetParent() || current == root) {
|
||||||
|
@ -437,12 +443,12 @@ DescendantsIterator::self_type DescendantsIterator::operator++(int _) {
|
||||||
|
|
||||||
// Now move to the next sibling
|
// Now move to the next sibling
|
||||||
siblingIndex.back()++;
|
siblingIndex.back()++;
|
||||||
current = current->GetParent()->GetChildren()[siblingIndex.back()];
|
current = current->GetParent().value()->GetChildren()[siblingIndex.back()];
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
nullable std::shared_ptr<Instance> Instance::Clone(RefStateClone state) {
|
std::optional<std::shared_ptr<Instance>> Instance::Clone(RefStateClone state) {
|
||||||
if (state == nullptr) state = std::make_shared<__RefStateClone>();
|
if (state == nullptr) state = std::make_shared<__RefStateClone>();
|
||||||
std::shared_ptr<Instance> newInstance = GetClass()->constructor();
|
std::shared_ptr<Instance> newInstance = GetClass()->constructor();
|
||||||
|
|
||||||
|
@ -488,9 +494,9 @@ nullable std::shared_ptr<Instance> Instance::Clone(RefStateClone state) {
|
||||||
|
|
||||||
// Clone children
|
// Clone children
|
||||||
for (std::shared_ptr<Instance> child : GetChildren()) {
|
for (std::shared_ptr<Instance> child : GetChildren()) {
|
||||||
nullable std::shared_ptr<Instance> clonedChild = child->Clone(state);
|
std::optional<std::shared_ptr<Instance>> clonedChild = child->Clone(state);
|
||||||
if (clonedChild)
|
if (clonedChild)
|
||||||
newInstance->AddChild(clonedChild);
|
newInstance->AddChild(clonedChild.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
return newInstance;
|
return newInstance;
|
||||||
|
@ -515,12 +521,12 @@ std::vector<std::pair<std::string, std::shared_ptr<Instance>>> Instance::GetRefe
|
||||||
|
|
||||||
std::string Instance::GetFullName() {
|
std::string Instance::GetFullName() {
|
||||||
std::string currentName = name;
|
std::string currentName = name;
|
||||||
nullable std::shared_ptr<Instance> currentParent = GetParent();
|
std::optional<std::shared_ptr<Instance>> currentParent = GetParent();
|
||||||
|
|
||||||
while (currentParent && !currentParent->IsA("DataModel")) {
|
while (currentParent.has_value() && !currentParent.value()->IsA("DataModel")) {
|
||||||
currentName = currentParent->name + "." + currentName;
|
currentName = currentParent.value()->name + "." + currentName;
|
||||||
|
|
||||||
currentParent = currentParent->GetParent();
|
currentParent = currentParent.value()->GetParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
return currentName;
|
return currentName;
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
#include "error/result.h"
|
#include "error/result.h"
|
||||||
#include "member.h"
|
#include "member.h"
|
||||||
#include "objects/base/refstate.h"
|
#include "objects/base/refstate.h"
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
class Instance;
|
class Instance;
|
||||||
typedef std::shared_ptr<Instance>(*InstanceConstructor)();
|
typedef std::shared_ptr<Instance>(*InstanceConstructor)();
|
||||||
|
@ -60,8 +59,8 @@ private:
|
||||||
std::weak_ptr<DataModel> _dataModel;
|
std::weak_ptr<DataModel> _dataModel;
|
||||||
std::weak_ptr<Workspace> _workspace;
|
std::weak_ptr<Workspace> _workspace;
|
||||||
|
|
||||||
bool ancestryContinuityCheck(nullable std::shared_ptr<Instance> newParent);
|
bool ancestryContinuityCheck(std::optional<std::shared_ptr<Instance>> newParent);
|
||||||
void updateAncestry(nullable std::shared_ptr<Instance> child, nullable std::shared_ptr<Instance> newParent);
|
void updateAncestry(std::optional<std::shared_ptr<Instance>> child, std::optional<std::shared_ptr<Instance>> newParent);
|
||||||
|
|
||||||
friend JointInstance; // This isn't ideal, but oh well
|
friend JointInstance; // This isn't ideal, but oh well
|
||||||
protected:
|
protected:
|
||||||
|
@ -76,17 +75,17 @@ protected:
|
||||||
virtual void InternalUpdateProperty(std::string name);
|
virtual void InternalUpdateProperty(std::string name);
|
||||||
virtual std::vector<std::string> InternalGetProperties();
|
virtual std::vector<std::string> InternalGetProperties();
|
||||||
|
|
||||||
virtual void OnParentUpdated(nullable std::shared_ptr<Instance> oldParent, nullable std::shared_ptr<Instance> newParent);
|
virtual void OnParentUpdated(std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent);
|
||||||
virtual void OnAncestryChanged(nullable std::shared_ptr<Instance> child, nullable std::shared_ptr<Instance> newParent);
|
virtual void OnAncestryChanged(std::optional<std::shared_ptr<Instance>> child, std::optional<std::shared_ptr<Instance>> newParent);
|
||||||
virtual void OnWorkspaceAdded(nullable std::shared_ptr<Workspace> oldWorkspace, std::shared_ptr<Workspace> newWorkspace);
|
virtual void OnWorkspaceAdded(std::optional<std::shared_ptr<Workspace>> oldWorkspace, std::shared_ptr<Workspace> newWorkspace);
|
||||||
virtual void OnWorkspaceRemoved(std::shared_ptr<Workspace> oldWorkspace);
|
virtual void OnWorkspaceRemoved(std::shared_ptr<Workspace> oldWorkspace);
|
||||||
|
|
||||||
// The root data model this object is a descendant of
|
// The root data model this object is a descendant of
|
||||||
nullable std::shared_ptr<DataModel> dataModel();
|
std::optional<std::shared_ptr<DataModel>> dataModel();
|
||||||
// The root workspace this object is a descendant of
|
// The root workspace this object is a descendant of
|
||||||
// NOTE: This value is not necessarily present if dataModel is present
|
// NOTE: This value is not necessarily present if dataModel is present
|
||||||
// Objects under services other than workspace will NOT have this field set
|
// Objects under services other than workspace will NOT have this field set
|
||||||
nullable std::shared_ptr<Workspace> workspace();
|
std::optional<std::shared_ptr<Workspace>> workspace();
|
||||||
public:
|
public:
|
||||||
const static InstanceType TYPE;
|
const static InstanceType TYPE;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
@ -97,8 +96,8 @@ public:
|
||||||
// Instance is abstract, so it should not implement GetClass directly
|
// Instance is abstract, so it should not implement GetClass directly
|
||||||
virtual const InstanceType* GetClass() = 0;
|
virtual const InstanceType* GetClass() = 0;
|
||||||
static void PushLuaLibrary(lua_State*); // Defined in lua/instancelib.cpp
|
static void PushLuaLibrary(lua_State*); // Defined in lua/instancelib.cpp
|
||||||
bool SetParent(nullable std::shared_ptr<Instance> newParent);
|
bool SetParent(std::optional<std::shared_ptr<Instance>> newParent);
|
||||||
nullable std::shared_ptr<Instance> GetParent();
|
std::optional<std::shared_ptr<Instance>> GetParent();
|
||||||
bool IsParentLocked();
|
bool IsParentLocked();
|
||||||
inline const std::vector<std::shared_ptr<Instance>> GetChildren() { return children; }
|
inline const std::vector<std::shared_ptr<Instance>> GetChildren() { return children; }
|
||||||
void Destroy();
|
void Destroy();
|
||||||
|
@ -112,7 +111,7 @@ public:
|
||||||
DescendantsIterator GetDescendantsEnd();
|
DescendantsIterator GetDescendantsEnd();
|
||||||
// Utility functions
|
// Utility functions
|
||||||
inline void AddChild(std::shared_ptr<Instance> object) { object->SetParent(this->shared_from_this()); }
|
inline void AddChild(std::shared_ptr<Instance> object) { object->SetParent(this->shared_from_this()); }
|
||||||
nullable std::shared_ptr<Instance> FindFirstChild(std::string);
|
std::optional<std::shared_ptr<Instance>> FindFirstChild(std::string);
|
||||||
std::string GetFullName();
|
std::string GetFullName();
|
||||||
|
|
||||||
// Properties
|
// Properties
|
||||||
|
@ -137,7 +136,7 @@ public:
|
||||||
// Serialization
|
// Serialization
|
||||||
void Serialize(pugi::xml_node parent, RefStateSerialize state = {});
|
void Serialize(pugi::xml_node parent, RefStateSerialize state = {});
|
||||||
static result<std::shared_ptr<Instance>, NoSuchInstance> Deserialize(pugi::xml_node node, RefStateDeserialize state = {});
|
static result<std::shared_ptr<Instance>, NoSuchInstance> Deserialize(pugi::xml_node node, RefStateDeserialize state = {});
|
||||||
nullable std::shared_ptr<Instance> Clone(RefStateClone state = {});
|
std::optional<std::shared_ptr<Instance>> Clone(RefStateClone state = {});
|
||||||
};
|
};
|
||||||
|
|
||||||
// https://gist.github.com/jeetsukumaran/307264
|
// https://gist.github.com/jeetsukumaran/307264
|
||||||
|
@ -159,7 +158,7 @@ public:
|
||||||
|
|
||||||
self_type operator++(int _);
|
self_type operator++(int _);
|
||||||
private:
|
private:
|
||||||
nullable std::shared_ptr<Instance> root;
|
std::optional<std::shared_ptr<Instance>> root;
|
||||||
std::shared_ptr<Instance> current;
|
std::shared_ptr<Instance> current;
|
||||||
std::vector<int> siblingIndex;
|
std::vector<int> siblingIndex;
|
||||||
};
|
};
|
|
@ -7,9 +7,9 @@
|
||||||
Service::Service(const InstanceType* type) : Instance(type) {}
|
Service::Service(const InstanceType* type) : Instance(type) {}
|
||||||
|
|
||||||
// Fail if parented to non-datamodel, otherwise lock parent
|
// Fail if parented to non-datamodel, otherwise lock parent
|
||||||
void Service::OnParentUpdated(nullable std::shared_ptr<Instance> oldParent, nullable std::shared_ptr<Instance> newParent) {
|
void Service::OnParentUpdated(std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent) {
|
||||||
if (!newParent || newParent->GetClass() != &DataModel::TYPE) {
|
if (!newParent || newParent.value()->GetClass() != &DataModel::TYPE) {
|
||||||
Logger::fatalErrorf("Service %s was parented to object of type %s", GetClass()->className.c_str(), newParent ? newParent->GetClass()->className.c_str() : "NULL");
|
Logger::fatalErrorf("Service %s was parented to object of type %s", GetClass()->className.c_str(), newParent ? newParent.value()->GetClass()->className.c_str() : "NULL");
|
||||||
panic();
|
panic();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ protected:
|
||||||
virtual void InitService();
|
virtual void InitService();
|
||||||
virtual void OnRun();
|
virtual void OnRun();
|
||||||
|
|
||||||
void OnParentUpdated(nullable std::shared_ptr<Instance> oldParent, nullable std::shared_ptr<Instance> newParent) override;
|
void OnParentUpdated(std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent) override;
|
||||||
|
|
||||||
friend class DataModel;
|
friend class DataModel;
|
||||||
};
|
};
|
|
@ -20,12 +20,6 @@ DataModel::DataModel()
|
||||||
this->name = "Place";
|
this->name = "Place";
|
||||||
}
|
}
|
||||||
|
|
||||||
DataModel::~DataModel() {
|
|
||||||
#ifndef NDEBUG
|
|
||||||
printf("Datamodel successfully destroyed\n");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataModel::Init(bool runMode) {
|
void DataModel::Init(bool runMode) {
|
||||||
// Create default services
|
// Create default services
|
||||||
GetService<Workspace>();
|
GetService<Workspace>();
|
||||||
|
@ -113,14 +107,14 @@ result<std::shared_ptr<Service>, NoSuchService> DataModel::GetService(std::strin
|
||||||
return std::dynamic_pointer_cast<Service>(services[className]);
|
return std::dynamic_pointer_cast<Service>(services[className]);
|
||||||
}
|
}
|
||||||
|
|
||||||
result<nullable std::shared_ptr<Service>, NoSuchService> DataModel::FindService(std::string className) {
|
result<std::optional<std::shared_ptr<Service>>, NoSuchService> DataModel::FindService(std::string className) {
|
||||||
if (!INSTANCE_MAP[className] || (INSTANCE_MAP[className]->flags ^ (INSTANCE_NOTCREATABLE | INSTANCE_SERVICE)) != 0) {
|
if (!INSTANCE_MAP[className] || (INSTANCE_MAP[className]->flags ^ (INSTANCE_NOTCREATABLE | INSTANCE_SERVICE)) != 0) {
|
||||||
return NoSuchService(className);
|
return NoSuchService(className);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (services.count(className) != 0)
|
if (services.count(className) != 0)
|
||||||
return std::dynamic_pointer_cast<Service>(services[className]);
|
return std::make_optional(std::dynamic_pointer_cast<Service>(services[className]));
|
||||||
return nullptr;
|
return (std::optional<std::shared_ptr<Service>>)std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<DataModel> DataModel::CloneModel() {
|
std::shared_ptr<DataModel> DataModel::CloneModel() {
|
||||||
|
@ -172,11 +166,11 @@ std::shared_ptr<DataModel> DataModel::CloneModel() {
|
||||||
if (!result)
|
if (!result)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
newModel->AddChild(result);
|
newModel->AddChild(result.value());
|
||||||
|
|
||||||
// Special case: Ignore instances parented to DataModel which are not services
|
// Special case: Ignore instances parented to DataModel which are not services
|
||||||
if (child->GetClass()->flags & INSTANCE_SERVICE) {
|
if (child->GetClass()->flags & INSTANCE_SERVICE) {
|
||||||
newModel->services[child->GetClass()->className] = std::dynamic_pointer_cast<Service>(result);
|
newModel->services[child->GetClass()->className] = std::dynamic_pointer_cast<Service>(result.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,13 +24,12 @@ public:
|
||||||
std::optional<std::string> currentFile;
|
std::optional<std::string> currentFile;
|
||||||
|
|
||||||
DataModel();
|
DataModel();
|
||||||
~DataModel();
|
|
||||||
void Init(bool runMode = false);
|
void Init(bool runMode = false);
|
||||||
|
|
||||||
static inline std::shared_ptr<DataModel> New() { return std::make_shared<DataModel>(); };
|
static inline std::shared_ptr<DataModel> New() { return std::make_shared<DataModel>(); };
|
||||||
|
|
||||||
result<std::shared_ptr<Service>, NoSuchService> GetService(std::string className);
|
result<std::shared_ptr<Service>, NoSuchService> GetService(std::string className);
|
||||||
result<nullable std::shared_ptr<Service>, NoSuchService> FindService(std::string className);
|
result<std::optional<std::shared_ptr<Service>>, NoSuchService> FindService(std::string className);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::shared_ptr<T> GetService() {
|
std::shared_ptr<T> GetService() {
|
||||||
|
@ -39,10 +38,10 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
nullable std::shared_ptr<T> FindService() {
|
std::optional<std::shared_ptr<T>> FindService() {
|
||||||
auto result = FindService(T::TYPE.className).expect("FindService<T>() was called with a non-service instance type");
|
auto result = FindService(T::TYPE.className).expect("FindService<T>() was called with a non-service instance type");
|
||||||
if (!result) return nullptr;
|
if (!result) return std::nullopt;
|
||||||
return std::dynamic_pointer_cast<T>(result);
|
return std::dynamic_pointer_cast<T>(result.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Saving/loading
|
// Saving/loading
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
#include "jointinstance.h"
|
#include "jointinstance.h"
|
||||||
|
|
||||||
|
#include "datatypes/cframe.h"
|
||||||
#include "datatypes/ref.h"
|
#include "datatypes/ref.h"
|
||||||
#include "objects/datamodel.h"
|
#include "objects/datamodel.h"
|
||||||
#include "objects/service/jointsservice.h"
|
#include "objects/service/jointsservice.h"
|
||||||
#include "objects/part/basepart.h"
|
#include "objects/part/part.h"
|
||||||
#include "objects/service/workspace.h"
|
#include "objects/service/workspace.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <reactphysics3d/constraint/FixedJoint.h>
|
||||||
|
#include <reactphysics3d/engine/PhysicsWorld.h>
|
||||||
|
#include "ptr_helpers.h"
|
||||||
|
|
||||||
JointInstance::JointInstance(const InstanceType* type): Instance(type) {
|
JointInstance::JointInstance(const InstanceType* type): Instance(type) {
|
||||||
}
|
}
|
||||||
|
@ -13,49 +17,43 @@ JointInstance::JointInstance(const InstanceType* type): Instance(type) {
|
||||||
JointInstance::~JointInstance() {
|
JointInstance::~JointInstance() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void JointInstance::OnAncestryChanged(nullable std::shared_ptr<Instance>, nullable std::shared_ptr<Instance>) {
|
void JointInstance::OnAncestryChanged(std::optional<std::shared_ptr<Instance>>, std::optional<std::shared_ptr<Instance>>) {
|
||||||
Update();
|
// Destroy and rebuild the joint, it's the simplest solution that actually works
|
||||||
|
|
||||||
|
breakJoint();
|
||||||
|
buildJoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JointInstance::OnPartParamsUpdated() {
|
void JointInstance::onUpdated(std::string property) {
|
||||||
}
|
// Add ourselves to the attached parts, or remove, if applicable
|
||||||
|
|
||||||
void JointInstance::Update() {
|
// Parts differ, delete
|
||||||
// To keep it simple compared to our previous algorithm, this one is pretty barebones:
|
if (part0 != oldPart0 && !oldPart0.expired()) {
|
||||||
// 1. Every time we update, (whether our parent changed, or a property), destroy the current joints
|
|
||||||
// 2. If the new configuration is valid, rebuild our joints
|
|
||||||
|
|
||||||
if (!jointWorkspace.expired()) {
|
|
||||||
jointWorkspace.lock()->DestroyJoint(joint);
|
|
||||||
if (!oldPart0.expired())
|
|
||||||
oldPart0.lock()->untrackJoint(shared<JointInstance>());
|
oldPart0.lock()->untrackJoint(shared<JointInstance>());
|
||||||
if (!oldPart1.expired())
|
}
|
||||||
|
|
||||||
|
if (part1 != oldPart1 && !oldPart1.expired()) {
|
||||||
oldPart1.lock()->untrackJoint(shared<JointInstance>());
|
oldPart1.lock()->untrackJoint(shared<JointInstance>());
|
||||||
}
|
}
|
||||||
|
|
||||||
oldPart0 = part0;
|
// Parts differ, add
|
||||||
oldPart1 = part1;
|
if (part0 != oldPart0 && !part0.expired()) {
|
||||||
|
|
||||||
// Don't build the joint if we're not part of either a workspace or JointsService
|
|
||||||
if ((!GetParent() || GetParent()->GetClass() != &JointsService::TYPE) && !workspace()) return;
|
|
||||||
|
|
||||||
// If either part is invalid or they are part of separate worlds, fail
|
|
||||||
if (part0.expired()
|
|
||||||
|| part1.expired()
|
|
||||||
|| !workspaceOfPart(part0.lock())
|
|
||||||
|| !workspaceOfPart(part1.lock())
|
|
||||||
|| workspaceOfPart(part0.lock()) != workspaceOfPart(part1.lock())
|
|
||||||
) return;
|
|
||||||
|
|
||||||
// TODO: Add joint continuity check here
|
|
||||||
|
|
||||||
// Finally, build the joint
|
|
||||||
buildJoint();
|
|
||||||
|
|
||||||
part0.lock()->trackJoint(shared<JointInstance>());
|
part0.lock()->trackJoint(shared<JointInstance>());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (part1 != oldPart1 && !part1.expired()) {
|
||||||
part1.lock()->trackJoint(shared<JointInstance>());
|
part1.lock()->trackJoint(shared<JointInstance>());
|
||||||
}
|
}
|
||||||
|
|
||||||
nullable std::shared_ptr<Workspace> JointInstance::workspaceOfPart(std::shared_ptr<BasePart> part) {
|
// Destroy and rebuild the joint, if applicable
|
||||||
|
|
||||||
|
breakJoint();
|
||||||
|
buildJoint();
|
||||||
|
|
||||||
|
oldPart0 = part0;
|
||||||
|
oldPart1 = part1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::shared_ptr<Workspace>> JointInstance::workspaceOfPart(std::shared_ptr<BasePart> part) {
|
||||||
return part->workspace();
|
return part->workspace();
|
||||||
}
|
}
|
|
@ -3,16 +3,14 @@
|
||||||
#include "objects/base/instance.h"
|
#include "objects/base/instance.h"
|
||||||
#include "../annotation.h"
|
#include "../annotation.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include "datatypes/cframe.h"
|
#include "datatypes/cframe.h"
|
||||||
#include "physics/world.h"
|
|
||||||
|
|
||||||
//this is necessary ebcause we use std::weak_ptr<Part> without including it in this file
|
//this is necessary ebcause we use std::weak_ptr<Part> without including it in this file
|
||||||
#ifdef __AUTOGEN_EXTRA_INCLUDES__
|
#ifdef __AUTOGEN_EXTRA_INCLUDES__
|
||||||
#include "objects/part/part.h"
|
#include "objects/part/part.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DEF_PROP_PHYS DEF_PROP_(on_update=onUpdated)
|
|
||||||
|
|
||||||
class BasePart;
|
class BasePart;
|
||||||
class Workspace;
|
class Workspace;
|
||||||
|
|
||||||
|
@ -24,25 +22,20 @@ class DEF_INST_ABSTRACT JointInstance : public Instance {
|
||||||
protected:
|
protected:
|
||||||
// The workspace the joint was created in, if it exists
|
// The workspace the joint was created in, if it exists
|
||||||
std::weak_ptr<Workspace> jointWorkspace;
|
std::weak_ptr<Workspace> jointWorkspace;
|
||||||
PhysJoint joint;
|
|
||||||
|
|
||||||
void OnAncestryChanged(nullable std::shared_ptr<Instance>, nullable std::shared_ptr<Instance>) override;
|
void OnAncestryChanged(std::optional<std::shared_ptr<Instance>>, std::optional<std::shared_ptr<Instance>>) override;
|
||||||
|
|
||||||
nullable std::shared_ptr<Workspace> workspaceOfPart(std::shared_ptr<BasePart>);
|
|
||||||
inline void onUpdated(std::string property) { Update(); };
|
|
||||||
|
|
||||||
|
std::optional<std::shared_ptr<Workspace>> workspaceOfPart(std::shared_ptr<BasePart>);
|
||||||
|
void onUpdated(std::string property);
|
||||||
virtual void buildJoint() = 0;
|
virtual void buildJoint() = 0;
|
||||||
|
virtual void breakJoint() = 0;
|
||||||
public:
|
public:
|
||||||
void Update();
|
|
||||||
virtual void OnPartParamsUpdated();
|
|
||||||
|
|
||||||
DEF_PROP_PHYS std::weak_ptr<BasePart> part0;
|
DEF_PROP_(on_update=onUpdated) std::weak_ptr<BasePart> part0;
|
||||||
DEF_PROP_PHYS std::weak_ptr<BasePart> part1;
|
DEF_PROP_(on_update=onUpdated) std::weak_ptr<BasePart> part1;
|
||||||
DEF_PROP_PHYS CFrame c0;
|
DEF_PROP_(on_update=onUpdated) CFrame c0;
|
||||||
DEF_PROP_PHYS CFrame c1;
|
DEF_PROP_(on_update=onUpdated) CFrame c1;
|
||||||
|
|
||||||
JointInstance(const InstanceType*);
|
JointInstance(const InstanceType*);
|
||||||
~JointInstance();
|
~JointInstance();
|
||||||
};
|
};
|
||||||
|
|
||||||
#undef DEF_PROP_PHYS
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "objects/part/part.h"
|
#include "objects/part/part.h"
|
||||||
#include "objects/service/workspace.h"
|
#include "objects/service/workspace.h"
|
||||||
#include "rendering/renderer.h"
|
#include "rendering/renderer.h"
|
||||||
|
#include <reactphysics3d/constraint/HingeJoint.h>
|
||||||
|
|
||||||
Rotate::Rotate(): JointInstance(&TYPE) {
|
Rotate::Rotate(): JointInstance(&TYPE) {
|
||||||
}
|
}
|
||||||
|
@ -12,15 +13,35 @@ Rotate::~Rotate() {
|
||||||
static CFrame XYZToZXY(glm::vec3(0, 0, 0), -glm::vec3(1, 0, 0), glm::vec3(0, 0, 1));
|
static CFrame XYZToZXY(glm::vec3(0, 0, 0), -glm::vec3(1, 0, 0), glm::vec3(0, 0, 1));
|
||||||
|
|
||||||
void Rotate::buildJoint() {
|
void Rotate::buildJoint() {
|
||||||
std::shared_ptr<Workspace> workspace = workspaceOfPart(part0.lock());
|
// 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();
|
||||||
|
|
||||||
// Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it
|
// 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.
|
// used to be rather than specifying an anchor rotation, so whatever.
|
||||||
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
||||||
part1.lock()->cframe = newFrame;
|
part1.lock()->cframe = newFrame;
|
||||||
|
workspace->SyncPartPhysics(part1.lock());
|
||||||
// Do NOT use Abs() in this scenario. For some reason that breaks it
|
// Do NOT use Abs() in this scenario. For some reason that breaks it
|
||||||
PhysRotatingJointInfo jointInfo(c0, c1);
|
rp::HingeJointInfo jointInfo(part0.lock()->rigidBody, part1.lock()->rigidBody, (part0.lock()->cframe * c0).Position(), -(part0.lock()->cframe * c0).LookVector().Unit());
|
||||||
this->joint = workspace->CreateJoint(jointInfo, part0.lock(), part1.lock());
|
this->joint = dynamic_cast<rp::HingeJoint*>(workspace->CreateJoint(jointInfo));
|
||||||
jointWorkspace = workspace;
|
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()) return;
|
||||||
|
|
||||||
|
jointWorkspace.lock()->DestroyJoint(this->joint);
|
||||||
|
this->joint = nullptr;
|
||||||
}
|
}
|
|
@ -5,10 +5,15 @@
|
||||||
#include "objects/joint/jointinstance.h"
|
#include "objects/joint/jointinstance.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
namespace reactphysics3d { class HingeJoint; }
|
||||||
|
|
||||||
class DEF_INST Rotate : public JointInstance {
|
class DEF_INST Rotate : public JointInstance {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
|
|
||||||
|
reactphysics3d::HingeJoint* joint = nullptr;
|
||||||
|
|
||||||
virtual void buildJoint() override;
|
virtual void buildJoint() override;
|
||||||
|
virtual void breakJoint() override;
|
||||||
public:
|
public:
|
||||||
Rotate();
|
Rotate();
|
||||||
~Rotate();
|
~Rotate();
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "objects/part/part.h"
|
#include "objects/part/part.h"
|
||||||
#include "objects/service/workspace.h"
|
#include "objects/service/workspace.h"
|
||||||
#include "rendering/renderer.h"
|
#include "rendering/renderer.h"
|
||||||
|
#include <reactphysics3d/constraint/HingeJoint.h>
|
||||||
|
|
||||||
#define PI 3.14159
|
#define PI 3.14159
|
||||||
|
|
||||||
|
@ -14,21 +15,39 @@ RotateV::~RotateV() {
|
||||||
static CFrame XYZToZXY(glm::vec3(0, 0, 0), -glm::vec3(1, 0, 0), glm::vec3(0, 0, 1));
|
static CFrame XYZToZXY(glm::vec3(0, 0, 0), -glm::vec3(1, 0, 0), glm::vec3(0, 0, 1));
|
||||||
|
|
||||||
void RotateV::buildJoint() {
|
void RotateV::buildJoint() {
|
||||||
std::shared_ptr<Workspace> workspace = workspaceOfPart(part0.lock());
|
// 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();
|
||||||
|
|
||||||
|
|
||||||
// Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it
|
// 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.
|
// used to be rather than specifying an anchor rotation, so whatever.
|
||||||
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
||||||
part1.lock()->cframe = newFrame;
|
part1.lock()->cframe = newFrame;
|
||||||
|
workspace->SyncPartPhysics(part1.lock());
|
||||||
// Do NOT use Abs() in this scenario. For some reason that breaks it
|
// Do NOT use Abs() in this scenario. For some reason that breaks it
|
||||||
float vel = part0.lock()->GetSurfaceParamB(-c0.LookVector().Unit()) * 6.28;
|
rp::HingeJointInfo jointInfo(part0.lock()->rigidBody, part1.lock()->rigidBody, (part0.lock()->cframe * c0).Position(), -(part0.lock()->cframe * c0).LookVector().Unit());
|
||||||
PhysRotatingJointInfo jointInfo(c0, c1, vel);
|
|
||||||
|
|
||||||
this->joint = workspace->CreateJoint(jointInfo, part0.lock(), part1.lock());
|
jointInfo.isCollisionEnabled = false;
|
||||||
|
|
||||||
|
this->joint = dynamic_cast<rp::HingeJoint*>(workspace->CreateJoint(jointInfo));
|
||||||
jointWorkspace = workspace;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RotateV::OnPartParamsUpdated() {
|
void RotateV::breakJoint() {
|
||||||
float vel = part0.lock()->GetSurfaceParamB(-c0.LookVector().Unit()) * 6.28;
|
// If the joint doesn't exist, or its workspace expired (not our problem anymore), then no need to do anything
|
||||||
this->joint.setAngularVelocity(vel);
|
if (!this->joint || jointWorkspace.expired()) return;
|
||||||
|
|
||||||
|
jointWorkspace.lock()->DestroyJoint(this->joint);
|
||||||
|
this->joint = nullptr;
|
||||||
}
|
}
|
|
@ -4,17 +4,19 @@
|
||||||
#include "objects/base/instance.h"
|
#include "objects/base/instance.h"
|
||||||
#include "objects/joint/jointinstance.h"
|
#include "objects/joint/jointinstance.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
namespace reactphysics3d { class HingeJoint; }
|
||||||
|
|
||||||
class DEF_INST RotateV : public JointInstance {
|
class DEF_INST RotateV : public JointInstance {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
|
|
||||||
|
reactphysics3d::HingeJoint* joint = nullptr;
|
||||||
|
|
||||||
virtual void buildJoint() override;
|
virtual void buildJoint() override;
|
||||||
|
virtual void breakJoint() override;
|
||||||
public:
|
public:
|
||||||
RotateV();
|
RotateV();
|
||||||
~RotateV();
|
~RotateV();
|
||||||
|
|
||||||
void OnPartParamsUpdated() override;
|
|
||||||
|
|
||||||
static inline std::shared_ptr<RotateV> New() { return std::make_shared<RotateV>(); };
|
static inline std::shared_ptr<RotateV> New() { return std::make_shared<RotateV>(); };
|
||||||
static inline std::shared_ptr<Instance> Create() { return std::make_shared<RotateV>(); };
|
static inline std::shared_ptr<Instance> Create() { return std::make_shared<RotateV>(); };
|
||||||
};
|
};
|
|
@ -6,8 +6,9 @@
|
||||||
#include "objects/service/jointsservice.h"
|
#include "objects/service/jointsservice.h"
|
||||||
#include "objects/part/part.h"
|
#include "objects/part/part.h"
|
||||||
#include "objects/service/workspace.h"
|
#include "objects/service/workspace.h"
|
||||||
#include "physics/world.h"
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <reactphysics3d/constraint/FixedJoint.h>
|
||||||
|
#include <reactphysics3d/engine/PhysicsWorld.h>
|
||||||
|
|
||||||
Snap::Snap(): JointInstance(&TYPE) {
|
Snap::Snap(): JointInstance(&TYPE) {
|
||||||
}
|
}
|
||||||
|
@ -16,14 +17,30 @@ Snap::~Snap() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Snap::buildJoint() {
|
void Snap::buildJoint() {
|
||||||
std::shared_ptr<Workspace> workspace = workspaceOfPart(part0.lock());
|
// 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();
|
||||||
|
|
||||||
// Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it
|
// 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.
|
// used to be rather than specifying an anchor rotation, so whatever.
|
||||||
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
||||||
part1.lock()->cframe = newFrame;
|
part1.lock()->cframe = newFrame;
|
||||||
|
workspace->SyncPartPhysics(part1.lock());
|
||||||
|
|
||||||
PhysFixedJointInfo jointInfo(c0, c1);
|
rp::FixedJointInfo jointInfo(part0.lock()->rigidBody, part1.lock()->rigidBody, (c0.Inverse() * c1).Position());
|
||||||
this->joint = workspace->CreateJoint(jointInfo, part0.lock(), part1.lock());
|
this->joint = dynamic_cast<rp::FixedJoint*>(workspace->CreateJoint(jointInfo));
|
||||||
jointWorkspace = workspace;
|
jointWorkspace = workspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// !!! REMINDER: This has to be called manually when parts are destroyed/removed from the workspace, or joints will linger
|
||||||
|
void Snap::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()) return;
|
||||||
|
|
||||||
|
jointWorkspace.lock()->DestroyJoint(this->joint);
|
||||||
|
this->joint = nullptr;
|
||||||
|
}
|
|
@ -5,10 +5,15 @@
|
||||||
#include "objects/joint/jointinstance.h"
|
#include "objects/joint/jointinstance.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
namespace reactphysics3d { class FixedJoint; }
|
||||||
|
|
||||||
class DEF_INST Snap : public JointInstance {
|
class DEF_INST Snap : public JointInstance {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
|
|
||||||
|
reactphysics3d::FixedJoint* joint = nullptr;
|
||||||
|
|
||||||
virtual void buildJoint() override;
|
virtual void buildJoint() override;
|
||||||
|
virtual void breakJoint() override;
|
||||||
public:
|
public:
|
||||||
Snap();
|
Snap();
|
||||||
~Snap();
|
~Snap();
|
||||||
|
|
|
@ -6,8 +6,9 @@
|
||||||
#include "objects/service/jointsservice.h"
|
#include "objects/service/jointsservice.h"
|
||||||
#include "objects/part/part.h"
|
#include "objects/part/part.h"
|
||||||
#include "objects/service/workspace.h"
|
#include "objects/service/workspace.h"
|
||||||
#include "physics/world.h"
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <reactphysics3d/constraint/FixedJoint.h>
|
||||||
|
#include <reactphysics3d/engine/PhysicsWorld.h>
|
||||||
|
|
||||||
Weld::Weld(): JointInstance(&TYPE) {
|
Weld::Weld(): JointInstance(&TYPE) {
|
||||||
}
|
}
|
||||||
|
@ -16,14 +17,30 @@ Weld::~Weld() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Weld::buildJoint() {
|
void Weld::buildJoint() {
|
||||||
std::shared_ptr<Workspace> workspace = workspaceOfPart(part0.lock());
|
// 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();
|
||||||
|
|
||||||
// Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it
|
// 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.
|
// used to be rather than specifying an anchor rotation, so whatever.
|
||||||
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
||||||
part1.lock()->cframe = newFrame;
|
part1.lock()->cframe = newFrame;
|
||||||
|
workspace->SyncPartPhysics(part1.lock());
|
||||||
|
|
||||||
PhysFixedJointInfo jointInfo(c0, c1);
|
rp::FixedJointInfo jointInfo(part0.lock()->rigidBody, part1.lock()->rigidBody, (c0.Inverse() * c1).Position());
|
||||||
this->joint = workspace->CreateJoint(jointInfo, part0.lock(), part1.lock());
|
this->joint = dynamic_cast<rp::FixedJoint*>(workspace->CreateJoint(jointInfo));
|
||||||
jointWorkspace = workspace;
|
jointWorkspace = workspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// !!! REMINDER: This has to be called manually when parts are destroyed/removed from the workspace, or joints will linger
|
||||||
|
void Weld::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()) return;
|
||||||
|
|
||||||
|
jointWorkspace.lock()->DestroyJoint(this->joint);
|
||||||
|
this->joint = nullptr;
|
||||||
|
}
|
|
@ -5,10 +5,15 @@
|
||||||
#include "objects/joint/jointinstance.h"
|
#include "objects/joint/jointinstance.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
namespace reactphysics3d { class FixedJoint; }
|
||||||
|
|
||||||
class DEF_INST Weld : public JointInstance {
|
class DEF_INST Weld : public JointInstance {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
|
|
||||||
|
reactphysics3d::FixedJoint* joint = nullptr;
|
||||||
|
|
||||||
virtual void buildJoint() override;
|
virtual void buildJoint() override;
|
||||||
|
virtual void breakJoint() override;
|
||||||
public:
|
public:
|
||||||
Weld();
|
Weld();
|
||||||
~Weld();
|
~Weld();
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "objects/joint/snap.h"
|
#include "objects/joint/snap.h"
|
||||||
#include "rendering/renderer.h"
|
#include "rendering/renderer.h"
|
||||||
#include "enum/surface.h"
|
#include "enum/surface.h"
|
||||||
|
#include <cstdio>
|
||||||
#include <glm/common.hpp>
|
#include <glm/common.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
@ -26,17 +27,20 @@ BasePart::BasePart(const InstanceType* type, PartConstructParams params): PVInst
|
||||||
}
|
}
|
||||||
|
|
||||||
BasePart::~BasePart() {
|
BasePart::~BasePart() {
|
||||||
if (workspace() != nullptr) {
|
// This relies on physicsCommon still existing. Be very careful.
|
||||||
workspace()->RemoveBody(shared<BasePart>());
|
if (this->rigidBody && workspace()) {
|
||||||
|
workspace().value()->DestroyRigidBody(rigidBody);
|
||||||
|
this->rigidBody = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void BasePart::OnAncestryChanged(nullable std::shared_ptr<Instance> child, nullable std::shared_ptr<Instance> newParent) {
|
void BasePart::OnAncestryChanged(std::optional<std::shared_ptr<Instance>> child, std::optional<std::shared_ptr<Instance>> newParent) {
|
||||||
this->rigidBody.setActive(workspace() != nullptr);
|
if (this->rigidBody)
|
||||||
|
this->rigidBody->setIsActive(workspace().has_value());
|
||||||
|
|
||||||
if (workspace() != nullptr)
|
if (workspace())
|
||||||
workspace()->SyncPartPhysics(std::dynamic_pointer_cast<BasePart>(this->shared_from_this()));
|
workspace().value()->SyncPartPhysics(std::dynamic_pointer_cast<BasePart>(this->shared_from_this()));
|
||||||
|
|
||||||
// Destroy joints
|
// Destroy joints
|
||||||
if (!workspace()) BreakJoints();
|
if (!workspace()) BreakJoints();
|
||||||
|
@ -44,41 +48,26 @@ void BasePart::OnAncestryChanged(nullable std::shared_ptr<Instance> child, nulla
|
||||||
// TODO: Sleeping bodies that touch this one also need to be updated
|
// TODO: Sleeping bodies that touch this one also need to be updated
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasePart::OnWorkspaceAdded(nullable std::shared_ptr<Workspace> oldWorkspace, std::shared_ptr<Workspace> newWorkspace) {
|
void BasePart::OnWorkspaceAdded(std::optional<std::shared_ptr<Workspace>> oldWorkspace, std::shared_ptr<Workspace> newWorkspace) {
|
||||||
newWorkspace->AddBody(shared<BasePart>());
|
newWorkspace->AddBody(shared<BasePart>());
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasePart::OnWorkspaceRemoved(std::shared_ptr<Workspace> oldWorkspace) {
|
void BasePart::OnWorkspaceRemoved(std::shared_ptr<Workspace> oldWorkspace) {
|
||||||
BreakJoints();
|
if (simulationTicket.has_value())
|
||||||
oldWorkspace->RemoveBody(shared<BasePart>());
|
oldWorkspace->RemoveBody(shared<BasePart>());
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasePart::onUpdated(std::string property) {
|
void BasePart::onUpdated(std::string property) {
|
||||||
bool reset = property == "Position" || property == "Rotation" || property == "CFrame" || property == "Size" || property == "Shape";
|
bool reset = property == "Position" || property == "Rotation" || property == "CFrame" || property == "Size" || property == "Shape";
|
||||||
|
|
||||||
// Sanitize size
|
if (workspace())
|
||||||
// TODO: Replace this with a validator instead
|
workspace().value()->SyncPartPhysics(std::dynamic_pointer_cast<BasePart>(this->shared_from_this()));
|
||||||
if (property == "Size") {
|
|
||||||
size = glm::max((glm::vec3)size, glm::vec3(0.1f, 0.1f, 0.1f));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (workspace() != nullptr)
|
|
||||||
workspace()->SyncPartPhysics(std::dynamic_pointer_cast<BasePart>(this->shared_from_this()));
|
|
||||||
|
|
||||||
// When position/rotation/size is manually edited, break all joints, they don't apply anymore
|
// When position/rotation/size is manually edited, break all joints, they don't apply anymore
|
||||||
if (reset)
|
if (reset)
|
||||||
BreakJoints();
|
BreakJoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasePart::onParamUpdated(std::string property) {
|
|
||||||
// Send signal to joints to update themselves
|
|
||||||
for (std::weak_ptr<JointInstance> joint : primaryJoints) {
|
|
||||||
if (joint.expired()) continue;
|
|
||||||
|
|
||||||
joint.lock()->OnPartParamsUpdated();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expands provided extents to fit point
|
// Expands provided extents to fit point
|
||||||
static void expandMaxExtents(Vector3* min, Vector3* max, Vector3 point) {
|
static void expandMaxExtents(Vector3* min, Vector3* max, Vector3 point) {
|
||||||
*min = Vector3(glm::min(min->X(), point.X()), glm::min(min->Y(), point.Y()), glm::min(min->Z(), point.Z()));
|
*min = Vector3(glm::min(min->X(), point.X()), glm::min(min->Y(), point.Y()), glm::min(min->Z(), point.Z()));
|
||||||
|
@ -217,7 +206,7 @@ bool BasePart::checkSurfacesTouching(CFrame surfaceFrame, Vector3 size, Vector3
|
||||||
return horizOverlap && vertOverlap;
|
return horizOverlap && vertOverlap;
|
||||||
}
|
}
|
||||||
|
|
||||||
nullable std::shared_ptr<JointInstance> makeJointFromSurfaces(SurfaceType a, SurfaceType b) {
|
std::optional<std::shared_ptr<JointInstance>> makeJointFromSurfaces(SurfaceType a, SurfaceType b) {
|
||||||
if (a == SurfaceType::Weld || b == SurfaceType::Weld || a == SurfaceType::Glue || b == SurfaceType::Glue) return Weld::New();
|
if (a == SurfaceType::Weld || b == SurfaceType::Weld || a == SurfaceType::Glue || b == SurfaceType::Glue) return Weld::New();
|
||||||
if ((a == SurfaceType::Studs && (b == SurfaceType::Inlet || b == SurfaceType::Universal))
|
if ((a == SurfaceType::Studs && (b == SurfaceType::Inlet || b == SurfaceType::Universal))
|
||||||
|| (a == SurfaceType::Inlet && (b == SurfaceType::Studs || b == SurfaceType::Universal))
|
|| (a == SurfaceType::Inlet && (b == SurfaceType::Studs || b == SurfaceType::Universal))
|
||||||
|
@ -227,7 +216,7 @@ nullable std::shared_ptr<JointInstance> makeJointFromSurfaces(SurfaceType a, Sur
|
||||||
return Rotate::New();
|
return Rotate::New();
|
||||||
if (a == SurfaceType::Motor)
|
if (a == SurfaceType::Motor)
|
||||||
return RotateV::New();
|
return RotateV::New();
|
||||||
return nullptr;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasePart::MakeJoints() {
|
void BasePart::MakeJoints() {
|
||||||
|
@ -242,7 +231,7 @@ void BasePart::MakeJoints() {
|
||||||
|
|
||||||
// TEMPORARY
|
// TEMPORARY
|
||||||
// TODO: Use more efficient algorithm to *actually* find nearby parts)
|
// TODO: Use more efficient algorithm to *actually* find nearby parts)
|
||||||
for (auto it = workspace()->GetDescendantsStart(); it != workspace()->GetDescendantsEnd(); it++) {
|
for (auto it = workspace().value()->GetDescendantsStart(); it != workspace().value()->GetDescendantsEnd(); it++) {
|
||||||
std::shared_ptr<Instance> obj = *it;
|
std::shared_ptr<Instance> obj = *it;
|
||||||
if (obj == shared_from_this()) continue; // Skip ourselves
|
if (obj == shared_from_this()) continue; // Skip ourselves
|
||||||
if (!obj->IsA<BasePart>()) continue;
|
if (!obj->IsA<BasePart>()) continue;
|
||||||
|
@ -289,17 +278,15 @@ void BasePart::MakeJoints() {
|
||||||
|
|
||||||
auto joint_ = makeJointFromSurfaces(mySurface, otherSurface);
|
auto joint_ = makeJointFromSurfaces(mySurface, otherSurface);
|
||||||
if (!joint_) continue;
|
if (!joint_) continue;
|
||||||
std::shared_ptr<JointInstance> joint = joint_;
|
std::shared_ptr<JointInstance> joint = joint_.value();
|
||||||
joint->part0 = shared<BasePart>();
|
joint->part0 = shared<BasePart>();
|
||||||
joint->part1 = otherPart->shared<BasePart>();
|
joint->part1 = otherPart->shared<BasePart>();
|
||||||
joint->c0 = contact0;
|
joint->c0 = contact0;
|
||||||
joint->c1 = contact1;
|
joint->c1 = contact1;
|
||||||
// // If both parts touch directly, this can cause friction in Rotate and RotateV joints, so we leave a little extra space
|
dataModel().value()->GetService<JointsService>()->AddChild(joint);
|
||||||
// if (joint->IsA("Rotate") || joint->IsA("RotateV"))
|
|
||||||
// joint->c1 = joint->c1 + joint->c1.LookVector() * 0.02f,
|
|
||||||
// joint->c0 = joint->c0 - joint->c0.LookVector() * 0.02f;
|
|
||||||
dataModel()->GetService<JointsService>()->AddChild(joint);
|
|
||||||
joint->UpdateProperty("Part0");
|
joint->UpdateProperty("Part0");
|
||||||
|
|
||||||
|
Logger::debugf("Made joint between %s and %s!\n", name.c_str(), otherPart->name.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/ext.hpp>
|
#include <glm/ext.hpp>
|
||||||
|
@ -9,14 +10,16 @@
|
||||||
#include "datatypes/vector.h"
|
#include "datatypes/vector.h"
|
||||||
#include "objects/base/instance.h"
|
#include "objects/base/instance.h"
|
||||||
#include "enum/surface.h"
|
#include "enum/surface.h"
|
||||||
|
#include <mutex>
|
||||||
|
#include <optional>
|
||||||
|
#include <reactphysics3d/body/RigidBody.h>
|
||||||
|
#include <reactphysics3d/engine/PhysicsCommon.h>
|
||||||
|
#include <reactphysics3d/reactphysics3d.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "objects/annotation.h"
|
#include "objects/annotation.h"
|
||||||
#include "objects/pvinstance.h"
|
#include "objects/pvinstance.h"
|
||||||
#include "physics/world.h"
|
|
||||||
|
|
||||||
// Common macro for part properties
|
namespace rp = reactphysics3d;
|
||||||
#define DEF_PROP_PHYS DEF_PROP_(on_update=onUpdated)
|
|
||||||
#define DEF_PROP_PHYSPARAM DEF_PROP_(on_update=onParamUpdated)
|
|
||||||
|
|
||||||
// For easy construction from C++. Maybe should be removed?
|
// For easy construction from C++. Maybe should be removed?
|
||||||
struct PartConstructParams {
|
struct PartConstructParams {
|
||||||
|
@ -29,7 +32,13 @@ struct PartConstructParams {
|
||||||
bool locked = false;
|
bool locked = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PhysWorld;
|
class Workspace;
|
||||||
|
|
||||||
|
#ifndef __SIMULATION_TICKET
|
||||||
|
#define __SIMULATION_TICKET
|
||||||
|
class BasePart;
|
||||||
|
typedef std::list<std::shared_ptr<BasePart>>::iterator SimulationTicket;
|
||||||
|
#endif
|
||||||
|
|
||||||
class DEF_INST_ABSTRACT_(explorer_icon="part") BasePart : public PVInstance {
|
class DEF_INST_ABSTRACT_(explorer_icon="part") BasePart : public PVInstance {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
|
@ -49,35 +58,35 @@ protected:
|
||||||
bool checkSurfacesTouching(CFrame surfaceFrame, Vector3 size, Vector3 myFace, Vector3 otherFace, std::shared_ptr<BasePart> otherPart);
|
bool checkSurfacesTouching(CFrame surfaceFrame, Vector3 size, Vector3 myFace, Vector3 otherFace, std::shared_ptr<BasePart> otherPart);
|
||||||
|
|
||||||
friend JointInstance;
|
friend JointInstance;
|
||||||
friend PhysWorld;
|
friend Workspace;
|
||||||
|
|
||||||
virtual void OnWorkspaceAdded(nullable std::shared_ptr<Workspace> oldWorkspace, std::shared_ptr<Workspace> newWorkspace) override;
|
virtual void OnWorkspaceAdded(std::optional<std::shared_ptr<Workspace>> oldWorkspace, std::shared_ptr<Workspace> newWorkspace) override;
|
||||||
virtual void OnWorkspaceRemoved(std::shared_ptr<Workspace> oldWorkspace) override;
|
virtual void OnWorkspaceRemoved(std::shared_ptr<Workspace> oldWorkspace) override;
|
||||||
void OnAncestryChanged(nullable std::shared_ptr<Instance> child, nullable std::shared_ptr<Instance> newParent) override;
|
void OnAncestryChanged(std::optional<std::shared_ptr<Instance>> child, std::optional<std::shared_ptr<Instance>> newParent) override;
|
||||||
void onUpdated(std::string);
|
void onUpdated(std::string);
|
||||||
void onParamUpdated(std::string);
|
|
||||||
|
virtual void updateCollider(rp::PhysicsCommon* common) = 0;
|
||||||
|
|
||||||
BasePart(const InstanceType*);
|
BasePart(const InstanceType*);
|
||||||
BasePart(const InstanceType*, PartConstructParams params);
|
BasePart(const InstanceType*, PartConstructParams params);
|
||||||
public:
|
public:
|
||||||
DEF_PROP_CATEGORY(DATA)
|
DEF_PROP_CATEGORY(DATA)
|
||||||
DEF_PROP_PHYS Vector3 velocity;
|
DEF_PROP_(on_update=onUpdated) Vector3 velocity;
|
||||||
[[ def_prop(name="CFrame", on_update=onUpdated), cframe_position_prop(name="Position"), cframe_rotation_prop(name="Rotation") ]]
|
[[ def_prop(name="CFrame", on_update=onUpdated), cframe_position_prop(name="Position"), cframe_rotation_prop(name="Rotation") ]]
|
||||||
CFrame cframe;
|
CFrame cframe;
|
||||||
|
|
||||||
DEF_PROP_CATEGORY(PART)
|
DEF_PROP_CATEGORY(PART)
|
||||||
// Special compatibility changes for this property were made in
|
// Special compatibility changes for this property were made in
|
||||||
// Instance::Serialize
|
// Instance::Serialize
|
||||||
DEF_PROP_PHYS Vector3 size;
|
DEF_PROP_(on_update=onUpdated) Vector3 size;
|
||||||
|
|
||||||
DEF_PROP_CATEGORY(APPEARANCE)
|
DEF_PROP_CATEGORY(APPEARANCE)
|
||||||
DEF_PROP Color3 color;
|
DEF_PROP Color3 color;
|
||||||
DEF_PROP float transparency = 0.f;
|
DEF_PROP float transparency = 0.f;
|
||||||
DEF_PROP float reflectance = 0.f;
|
|
||||||
|
|
||||||
DEF_PROP_CATEGORY(BEHAVIOR)
|
DEF_PROP_CATEGORY(BEHAVIOR)
|
||||||
DEF_PROP_PHYS bool anchored = false;
|
DEF_PROP_(on_update=onUpdated) bool anchored = false;
|
||||||
DEF_PROP_PHYS bool canCollide = true;
|
DEF_PROP_(on_update=onUpdated) bool canCollide = true;
|
||||||
DEF_PROP bool locked = false;
|
DEF_PROP bool locked = false;
|
||||||
|
|
||||||
DEF_PROP_CATEGORY(SURFACE)
|
DEF_PROP_CATEGORY(SURFACE)
|
||||||
|
@ -89,24 +98,26 @@ public:
|
||||||
DEF_PROP SurfaceType backSurface = SurfaceType::Smooth;
|
DEF_PROP SurfaceType backSurface = SurfaceType::Smooth;
|
||||||
|
|
||||||
DEF_PROP_CATEGORY(SURFACE_INPUT)
|
DEF_PROP_CATEGORY(SURFACE_INPUT)
|
||||||
DEF_PROP_PHYSPARAM float topParamA = -0.5;
|
DEF_PROP float topParamA = -0.5;
|
||||||
DEF_PROP_PHYSPARAM float bottomParamA = -0.5;
|
DEF_PROP float bottomParamA = -0.5;
|
||||||
DEF_PROP_PHYSPARAM float leftParamA = -0.5;
|
DEF_PROP float leftParamA = -0.5;
|
||||||
DEF_PROP_PHYSPARAM float rightParamA = -0.5;
|
DEF_PROP float rightParamA = -0.5;
|
||||||
DEF_PROP_PHYSPARAM float frontParamA = -0.5;
|
DEF_PROP float frontParamA = -0.5;
|
||||||
DEF_PROP_PHYSPARAM float backParamA = -0.5;
|
DEF_PROP float backParamA = -0.5;
|
||||||
|
|
||||||
DEF_PROP_PHYSPARAM float topParamB = 0.5;
|
DEF_PROP float topParamB = 0.5;
|
||||||
DEF_PROP_PHYSPARAM float bottomParamB = 0.5;
|
DEF_PROP float bottomParamB = 0.5;
|
||||||
DEF_PROP_PHYSPARAM float leftParamB = 0.5;
|
DEF_PROP float leftParamB = 0.5;
|
||||||
DEF_PROP_PHYSPARAM float rightParamB = 0.5;
|
DEF_PROP float rightParamB = 0.5;
|
||||||
DEF_PROP_PHYSPARAM float frontParamB = 0.5;
|
DEF_PROP float frontParamB = 0.5;
|
||||||
DEF_PROP_PHYSPARAM float backParamB = 0.5;
|
DEF_PROP float backParamB = 0.5;
|
||||||
|
|
||||||
DEF_SIGNAL SignalSource Touched;
|
DEF_SIGNAL SignalSource Touched;
|
||||||
DEF_SIGNAL SignalSource TouchEnded;
|
DEF_SIGNAL SignalSource TouchEnded;
|
||||||
|
|
||||||
PhysRigidBody rigidBody;
|
rp::RigidBody* rigidBody = nullptr;
|
||||||
|
std::optional<SimulationTicket> simulationTicket;
|
||||||
|
bool rigidBodyDirty = true;
|
||||||
|
|
||||||
inline SurfaceType GetSurfaceFromFace(NormalId face) { return surfaceFromFace(face); }
|
inline SurfaceType GetSurfaceFromFace(NormalId face) { return surfaceFromFace(face); }
|
||||||
float GetSurfaceParamA(Vector3 face);
|
float GetSurfaceParamA(Vector3 face);
|
||||||
|
@ -123,6 +134,3 @@ public:
|
||||||
// Calculate size of axis-aligned bounding box
|
// Calculate size of axis-aligned bounding box
|
||||||
Vector3 GetAABB();
|
Vector3 GetAABB();
|
||||||
};
|
};
|
||||||
|
|
||||||
#undef DEF_PROP_PHYS
|
|
||||||
#undef DEF_PROP_PHYSPARAM
|
|
|
@ -1,22 +1,42 @@
|
||||||
#include "part.h"
|
#include "part.h"
|
||||||
#include "enum/part.h"
|
#include "enum/part.h"
|
||||||
|
#include "physics/util.h"
|
||||||
#include <glm/common.hpp>
|
#include <glm/common.hpp>
|
||||||
|
|
||||||
Part::Part(): BasePart(&TYPE) {
|
Part::Part(): BasePart(&TYPE) {
|
||||||
|
_lastShape = shape;
|
||||||
|
_lastSize = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
Part::Part(PartConstructParams params): BasePart(&TYPE, params) {
|
Part::Part(PartConstructParams params): BasePart(&TYPE, params) {
|
||||||
|
_lastShape = shape;
|
||||||
|
_lastSize = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::updateCollider(rp::PhysicsCommon* common) {
|
||||||
|
rp::CollisionShape* physShape;
|
||||||
|
if (shape == PartType::Ball) {
|
||||||
|
physShape = common->createSphereShape(glm::min(size.X(), size.Y(), size.Z()) * 0.5f);
|
||||||
|
} else if (shape == PartType::Block) {
|
||||||
|
physShape = common->createBoxShape(glmToRp(size * glm::vec3(0.5f)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recreate the rigidbody if the shape changes
|
||||||
|
if (rigidBody->getNbColliders() > 0 && (_lastShape != shape || _lastSize != size)) {
|
||||||
|
// TODO: This causes Touched to get called twice. Fix this.
|
||||||
|
rigidBody->removeCollider(rigidBody->getCollider(0));
|
||||||
|
rigidBody->addCollider(physShape, rp::Transform());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rigidBody->getNbColliders() == 0)
|
||||||
|
rigidBody->addCollider(physShape, rp::Transform());
|
||||||
|
|
||||||
|
|
||||||
|
_lastShape = shape;
|
||||||
|
_lastSize = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 Part::GetEffectiveSize() {
|
Vector3 Part::GetEffectiveSize() {
|
||||||
float diameter;
|
return shape == PartType::Ball ? (Vector3)glm::vec3(glm::min(size.X(), size.Y(), size.Z())) : size;
|
||||||
switch (shape) {
|
|
||||||
case PartType::Ball:
|
|
||||||
return (Vector3)glm::vec3(glm::min(size.X(), size.Y(), size.Z()));
|
|
||||||
case PartType::Cylinder:
|
|
||||||
diameter = glm::min(size.Y(), size.Z());
|
|
||||||
return Vector3(size.X(), diameter, diameter);
|
|
||||||
default:
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -6,7 +6,11 @@
|
||||||
|
|
||||||
class DEF_INST Part : public BasePart {
|
class DEF_INST Part : public BasePart {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
|
|
||||||
|
PartType _lastShape;
|
||||||
|
Vector3 _lastSize;
|
||||||
protected:
|
protected:
|
||||||
|
void updateCollider(rp::PhysicsCommon* common) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Part();
|
Part();
|
||||||
|
|
|
@ -1,6 +1,92 @@
|
||||||
#include "wedgepart.h"
|
#include "wedgepart.h"
|
||||||
|
#include "physics/util.h"
|
||||||
|
#include <reactphysics3d/collision/ConvexMesh.h>
|
||||||
|
#include <reactphysics3d/collision/shapes/ConvexMeshShape.h>
|
||||||
|
|
||||||
|
rp::ConvexMesh* wedgePhysMesh;
|
||||||
|
|
||||||
WedgePart::WedgePart(): BasePart(&TYPE) {
|
WedgePart::WedgePart(): BasePart(&TYPE) {
|
||||||
}
|
}
|
||||||
|
|
||||||
WedgePart::WedgePart(PartConstructParams params): BasePart(&TYPE, params) {}
|
WedgePart::WedgePart(PartConstructParams params): BasePart(&TYPE, params) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void WedgePart::updateCollider(rp::PhysicsCommon* common) {
|
||||||
|
Logger::fatalError("Wedges are currently disabled! Please do not use them or your editor may crash\n");
|
||||||
|
rp::ConvexMeshShape* shape = common->createConvexMeshShape(wedgePhysMesh, glmToRp(size * glm::vec3(0.5f)));
|
||||||
|
|
||||||
|
// Recreate the rigidbody if the shape changes
|
||||||
|
if (rigidBody->getNbColliders() > 0
|
||||||
|
&& dynamic_cast<rp::ConvexMeshShape*>(rigidBody->getCollider(0)->getCollisionShape())->getScale() != shape->getScale()) {
|
||||||
|
// TODO: This causes Touched to get called twice. Fix this.
|
||||||
|
rigidBody->removeCollider(rigidBody->getCollider(0));
|
||||||
|
rigidBody->addCollider(shape, rp::Transform());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rigidBody->getNbColliders() == 0)
|
||||||
|
rigidBody->addCollider(shape, rp::Transform());
|
||||||
|
}
|
||||||
|
|
||||||
|
void WedgePart::createWedgeShape(rp::PhysicsCommon* common) {
|
||||||
|
// https://www.reactphysics3d.com/documentation/index.html#creatingbody
|
||||||
|
float vertices[] = {
|
||||||
|
// X Y Z
|
||||||
|
/*0*/ -1, 1, 1, // 0
|
||||||
|
/*1*/ -1, -1, 1, // |
|
||||||
|
/*2*/ -1, -1, -1, // 1---2
|
||||||
|
|
||||||
|
/*3*/ 1, 1, 1,
|
||||||
|
/*4*/ 1, -1, 1,
|
||||||
|
/*5*/ 1, -1, -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
// -x +x
|
||||||
|
// +z 1----------4
|
||||||
|
// | bottom |
|
||||||
|
// -z 2----------5
|
||||||
|
|
||||||
|
// -x +x
|
||||||
|
// +y 0----------3
|
||||||
|
// | front |
|
||||||
|
// -y 1----------4
|
||||||
|
|
||||||
|
// -x +x
|
||||||
|
// +yz 0----------3
|
||||||
|
// | slope |
|
||||||
|
// -yz 2----------5
|
||||||
|
|
||||||
|
int indices[] = {
|
||||||
|
// Base
|
||||||
|
1, 2, 5, 4,
|
||||||
|
|
||||||
|
// Back-face
|
||||||
|
0, 1, 4, 3,
|
||||||
|
// 4, 1, 0, 3,
|
||||||
|
|
||||||
|
// Slope
|
||||||
|
0, 2, 5, 3,
|
||||||
|
// 3, 5, 2, 0,
|
||||||
|
|
||||||
|
// Sides
|
||||||
|
0, 1, 2,
|
||||||
|
3, 4, 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Description of the six faces of the convex mesh
|
||||||
|
rp::PolygonVertexArray::PolygonFace* polygonFaces = new rp::PolygonVertexArray::PolygonFace[5];
|
||||||
|
polygonFaces[0] = { 4, 0 }; // Bottom
|
||||||
|
polygonFaces[1] = { 4, 4 }; // Front
|
||||||
|
polygonFaces[2] = { 4, 8 }; // Slope
|
||||||
|
polygonFaces[3] = { 3, 12 }; // Side
|
||||||
|
polygonFaces[4] = { 3, 15 }; // Side
|
||||||
|
|
||||||
|
// Create the polygon vertex array
|
||||||
|
rp::PolygonVertexArray polygonVertexArray(6, vertices, 3 * sizeof(float), indices, sizeof(int), 5, polygonFaces,
|
||||||
|
rp::PolygonVertexArray::VertexDataType::VERTEX_FLOAT_TYPE,
|
||||||
|
rp::PolygonVertexArray::IndexDataType::INDEX_INTEGER_TYPE);
|
||||||
|
|
||||||
|
// Create the convex mesh
|
||||||
|
std::vector<rp3d::Message> messages;
|
||||||
|
// wedgePhysMesh = common->createConvexMesh(polygonVertexArray, messages);
|
||||||
|
}
|
|
@ -3,9 +3,14 @@
|
||||||
#include "basepart.h"
|
#include "basepart.h"
|
||||||
#include "objects/annotation.h"
|
#include "objects/annotation.h"
|
||||||
|
|
||||||
class DEF_INST WedgePart : public BasePart {
|
class DEF_INST_(hidden) WedgePart : public BasePart {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void updateCollider(rp::PhysicsCommon* common) override;
|
||||||
|
static void createWedgeShape(rp::PhysicsCommon* common);
|
||||||
|
|
||||||
|
friend Workspace;
|
||||||
public:
|
public:
|
||||||
WedgePart();
|
WedgePart();
|
||||||
WedgePart(PartConstructParams params);
|
WedgePart(PartConstructParams params);
|
||||||
|
|
|
@ -23,7 +23,7 @@ Script::~Script() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Script::Run() {
|
void Script::Run() {
|
||||||
std::shared_ptr<ScriptContext> scriptContext = dataModel()->GetService<ScriptContext>();
|
std::shared_ptr<ScriptContext> scriptContext = dataModel().value()->GetService<ScriptContext>();
|
||||||
|
|
||||||
lua_State* L = scriptContext->state;
|
lua_State* L = scriptContext->state;
|
||||||
int top = lua_gettop(L);
|
int top = lua_gettop(L);
|
||||||
|
|
|
@ -18,8 +18,8 @@ void JointsService::InitService() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nullable std::shared_ptr<Workspace> JointsService::jointWorkspace() {
|
std::optional<std::shared_ptr<Workspace>> JointsService::jointWorkspace() {
|
||||||
if (!dataModel()) return nullptr;
|
if (!dataModel()) return std::nullopt;
|
||||||
|
|
||||||
return dataModel()->FindService<Workspace>();
|
return dataModel().value()->FindService<Workspace>();
|
||||||
}
|
}
|
|
@ -3,10 +3,10 @@
|
||||||
#include "objects/annotation.h"
|
#include "objects/annotation.h"
|
||||||
#include "objects/base/service.h"
|
#include "objects/base/service.h"
|
||||||
|
|
||||||
class DEF_INST_SERVICE_(hidden) JointsService : public Service {
|
class DEF_INST_SERVICE JointsService : public Service {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
private:
|
private:
|
||||||
nullable std::shared_ptr<Workspace> jointWorkspace();
|
std::optional<std::shared_ptr<Workspace>> jointWorkspace();
|
||||||
protected:
|
protected:
|
||||||
void InitService() override;
|
void InitService() override;
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#include "objects/datamodel.h"
|
#include "objects/datamodel.h"
|
||||||
#include "objects/service/workspace.h"
|
#include "objects/service/workspace.h"
|
||||||
#include "timeutil.h"
|
#include "timeutil.h"
|
||||||
#include <chrono>
|
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "luaapis.h" // IWYU pragma: keep
|
#include "luaapis.h" // IWYU pragma: keep
|
||||||
|
@ -16,7 +15,6 @@ const char* WRAPPER_SRC = "local func, errhandler = ... return function(...) loc
|
||||||
|
|
||||||
int g_wait(lua_State*);
|
int g_wait(lua_State*);
|
||||||
int g_delay(lua_State*);
|
int g_delay(lua_State*);
|
||||||
int g_tick(lua_State*);
|
|
||||||
static int g_print(lua_State*);
|
static int g_print(lua_State*);
|
||||||
static int g_require(lua_State*);
|
static int g_require(lua_State*);
|
||||||
static const luaL_Reg luaglobals [] = {
|
static const luaL_Reg luaglobals [] = {
|
||||||
|
@ -61,10 +59,10 @@ void ScriptContext::InitService() {
|
||||||
// Add other globals
|
// Add other globals
|
||||||
lua_getglobal(state, "_G");
|
lua_getglobal(state, "_G");
|
||||||
|
|
||||||
InstanceRef(dataModel()).PushLuaValue(state);
|
InstanceRef(dataModel().value()).PushLuaValue(state);
|
||||||
lua_setfield(state, -2, "game");
|
lua_setfield(state, -2, "game");
|
||||||
|
|
||||||
InstanceRef(dataModel()->GetService<Workspace>()).PushLuaValue(state);
|
InstanceRef(dataModel().value()->GetService<Workspace>()).PushLuaValue(state);
|
||||||
lua_setfield(state, -2, "workspace");
|
lua_setfield(state, -2, "workspace");
|
||||||
|
|
||||||
lua_pushlightuserdata(state, this);
|
lua_pushlightuserdata(state, this);
|
||||||
|
@ -75,9 +73,6 @@ void ScriptContext::InitService() {
|
||||||
lua_pushcclosure(state, g_delay, 1);
|
lua_pushcclosure(state, g_delay, 1);
|
||||||
lua_setfield(state, -2, "delay");
|
lua_setfield(state, -2, "delay");
|
||||||
|
|
||||||
lua_pushcclosure(state, g_tick, 0);
|
|
||||||
lua_setfield(state, -2, "tick");
|
|
||||||
|
|
||||||
lua_pop(state, 1); // _G
|
lua_pop(state, 1); // _G
|
||||||
|
|
||||||
// Add wrapper function
|
// Add wrapper function
|
||||||
|
@ -248,13 +243,3 @@ int g_delay(lua_State* L) {
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int g_tick(lua_State* L) {
|
|
||||||
std::chrono::time_point now_local = std::chrono::current_zone()->to_local(std::chrono::system_clock::now());
|
|
||||||
std::chrono::microseconds us = std::chrono::duration_cast<std::chrono::microseconds>(now_local.time_since_epoch());
|
|
||||||
uint64_t _10millis = us.count() / 100;
|
|
||||||
double secs = (double)_10millis / 10000;
|
|
||||||
|
|
||||||
lua_pushnumber(L, secs);
|
|
||||||
return 1;
|
|
||||||
}
|
|
|
@ -15,7 +15,7 @@ struct SleepingThread {
|
||||||
|
|
||||||
class Script;
|
class Script;
|
||||||
|
|
||||||
class DEF_INST_SERVICE_(hidden) ScriptContext : public Service {
|
class DEF_INST_SERVICE ScriptContext : public Service {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
|
|
||||||
std::vector<SleepingThread> sleepingThreads;
|
std::vector<SleepingThread> sleepingThreads;
|
||||||
|
|
|
@ -14,7 +14,7 @@ void ServerScriptService::InitService() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerScriptService::OnRun() {
|
void ServerScriptService::OnRun() {
|
||||||
auto workspace = dataModel()->GetService<Workspace>();
|
auto workspace = dataModel().value()->GetService<Workspace>();
|
||||||
for (auto it = workspace->GetDescendantsStart(); it != workspace->GetDescendantsEnd(); it++) {
|
for (auto it = workspace->GetDescendantsStart(); it != workspace->GetDescendantsEnd(); it++) {
|
||||||
if (!it->IsA<Script>()) continue;
|
if (!it->IsA<Script>()) continue;
|
||||||
it->CastTo<Script>().expect()->Run();
|
it->CastTo<Script>().expect()->Run();
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
// Container class for server scripts
|
// Container class for server scripts
|
||||||
// Also handles/manages running server scripts on run
|
// Also handles/manages running server scripts on run
|
||||||
class DEF_INST_SERVICE_(explorer_icon="server-scripts", hidden) ServerScriptService : public Service {
|
class DEF_INST_SERVICE_(explorer_icon="server-scripts") ServerScriptService : public Service {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
protected:
|
protected:
|
||||||
void InitService() override;
|
void InitService() override;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class DEF_INST_SERVICE_(hidden) Selection : public Service {
|
class DEF_INST_SERVICE Selection : public Service {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
private:
|
private:
|
||||||
std::vector<std::shared_ptr<Instance>> selection;
|
std::vector<std::shared_ptr<Instance>> selection;
|
||||||
|
|
|
@ -9,20 +9,82 @@
|
||||||
#include "objects/service/jointsservice.h"
|
#include "objects/service/jointsservice.h"
|
||||||
#include "objects/joint/jointinstance.h"
|
#include "objects/joint/jointinstance.h"
|
||||||
#include "objects/datamodel.h"
|
#include "objects/datamodel.h"
|
||||||
|
#include "physics/util.h"
|
||||||
#include "timeutil.h"
|
#include "timeutil.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <reactphysics3d/collision/CollisionCallback.h>
|
||||||
|
#include <reactphysics3d/collision/OverlapCallback.h>
|
||||||
|
#include <reactphysics3d/engine/PhysicsCommon.h>
|
||||||
|
|
||||||
Workspace::Workspace(): Service(&TYPE), physicsWorld(std::make_shared<PhysWorld>()) {
|
rp::PhysicsCommon* Workspace::physicsCommon = new rp::PhysicsCommon;
|
||||||
|
|
||||||
|
Workspace::Workspace(): Service(&TYPE), physicsEventListener(this) {
|
||||||
|
physicsWorld = physicsCommon->createPhysicsWorld();
|
||||||
}
|
}
|
||||||
|
|
||||||
Workspace::~Workspace() = default;
|
Workspace::~Workspace() {
|
||||||
|
if (physicsCommon)
|
||||||
|
physicsCommon->destroyPhysicsWorld(physicsWorld);
|
||||||
|
}
|
||||||
|
|
||||||
|
PhysicsEventListener::PhysicsEventListener(Workspace* parent) : workspace(parent) {}
|
||||||
|
|
||||||
|
void PhysicsEventListener::onContact(const rp::CollisionCallback::CallbackData& data) {
|
||||||
|
workspace->contactQueueLock.lock();
|
||||||
|
for (size_t i = 0; i < data.getNbContactPairs(); i++) {
|
||||||
|
auto pair = data.getContactPair(i);
|
||||||
|
auto type = pair.getEventType();
|
||||||
|
if (type == rp::CollisionCallback::ContactPair::EventType::ContactStay) continue;
|
||||||
|
|
||||||
|
if (type == reactphysics3d::CollisionCallback::ContactPair::EventType::ContactStay)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ContactItem contact;
|
||||||
|
contact.part0 = reinterpret_cast<BasePart*>(pair.getBody1()->getUserData())->shared<BasePart>();
|
||||||
|
contact.part1 = reinterpret_cast<BasePart*>(pair.getBody2()->getUserData())->shared<BasePart>();
|
||||||
|
contact.action = type == reactphysics3d::CollisionCallback::ContactPair::EventType::ContactStart ? ContactItem::CONTACTITEM_TOUCHED : ContactItem::CONTACTITEM_TOUCHENDED;
|
||||||
|
|
||||||
|
workspace->contactQueue.push(contact);
|
||||||
|
}
|
||||||
|
workspace->contactQueueLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsEventListener::onTrigger(const rp::OverlapCallback::CallbackData& data) {
|
||||||
|
workspace->contactQueueLock.lock();
|
||||||
|
for (size_t i = 0; i < data.getNbOverlappingPairs(); i++) {
|
||||||
|
auto pair = data.getOverlappingPair(i);
|
||||||
|
auto type = pair.getEventType();
|
||||||
|
if (type == rp::OverlapCallback::OverlapPair::EventType::OverlapStay) continue;
|
||||||
|
|
||||||
|
auto part0 = reinterpret_cast<BasePart*>(pair.getBody1()->getUserData())->shared<BasePart>();
|
||||||
|
auto part1 = reinterpret_cast<BasePart*>(pair.getBody2()->getUserData())->shared<BasePart>();
|
||||||
|
|
||||||
|
if (type == reactphysics3d::OverlapCallback::OverlapPair::EventType::OverlapStart) {
|
||||||
|
part0->Touched->Fire({ (Variant)InstanceRef(part1) });
|
||||||
|
part1->Touched->Fire({ (Variant)InstanceRef(part0) });
|
||||||
|
} else if (type == reactphysics3d::OverlapCallback::OverlapPair::EventType::OverlapExit) {
|
||||||
|
part0->TouchEnded->Fire({ (Variant)InstanceRef(part1) });
|
||||||
|
part1->TouchEnded->Fire({ (Variant)InstanceRef(part0) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
workspace->contactQueueLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
void Workspace::InitService() {
|
void Workspace::InitService() {
|
||||||
if (initialized) return;
|
if (initialized) return;
|
||||||
initialized = true;
|
initialized = true;
|
||||||
|
|
||||||
|
physicsWorld->setGravity(rp::Vector3(0, -196.2, 0));
|
||||||
|
// world->setContactsPositionCorrectionTechnique(rp3d::ContactsPositionCorrectionTechnique::BAUMGARTE_CONTACTS);
|
||||||
|
physicsWorld->setNbIterationsPositionSolver(2000);
|
||||||
|
physicsWorld->setNbIterationsVelocitySolver(2000);
|
||||||
|
// physicsWorld->setSleepLinearVelocity(10);
|
||||||
|
// physicsWorld->setSleepAngularVelocity(5);
|
||||||
|
|
||||||
|
physicsWorld->setEventListener(&physicsEventListener);
|
||||||
|
|
||||||
// Create meshes
|
// Create meshes
|
||||||
// WedgePart::createWedgeShape(physicsCommon);
|
WedgePart::createWedgeShape(physicsCommon);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspace::OnRun() {
|
void Workspace::OnRun() {
|
||||||
|
@ -41,29 +103,211 @@ void Workspace::OnRun() {
|
||||||
joint->UpdateProperty("Part0");
|
joint->UpdateProperty("Part0");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto obj : dataModel()->GetService<JointsService>()->GetChildren()) {
|
for (auto obj : dataModel().value()->GetService<JointsService>()->GetChildren()) {
|
||||||
if (!obj->IsA<JointInstance>()) continue;
|
if (!obj->IsA<JointInstance>()) continue;
|
||||||
std::shared_ptr<JointInstance> joint = obj->CastTo<JointInstance>().expect();
|
std::shared_ptr<JointInstance> joint = obj->CastTo<JointInstance>().expect();
|
||||||
joint->UpdateProperty("Part0");
|
joint->UpdateProperty("Part0");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspace::SyncPartPhysics(std::shared_ptr<BasePart> part) {
|
void Workspace::updatePartPhysics(std::shared_ptr<BasePart> part) {
|
||||||
physicsWorld->syncBodyProperties(part);
|
rp::Transform transform = part->cframe;
|
||||||
|
if (!part->rigidBody) {
|
||||||
|
part->rigidBody = physicsWorld->createRigidBody(transform);
|
||||||
|
} else {
|
||||||
|
part->rigidBody->setTransform(transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspace::PhysicsStep(float deltaTime) {
|
part->updateCollider(physicsCommon);
|
||||||
physicsWorld->step(deltaTime);
|
|
||||||
|
part->rigidBody->setType(part->anchored ? rp::BodyType::STATIC : rp::BodyType::DYNAMIC);
|
||||||
|
part->rigidBody->getCollider(0)->setCollisionCategoryBits(0b11);
|
||||||
|
|
||||||
|
part->rigidBody->getCollider(0)->setIsSimulationCollider(part->canCollide);
|
||||||
|
part->rigidBody->getCollider(0)->setIsTrigger(!part->canCollide);
|
||||||
|
|
||||||
|
rp::Material& material = part->rigidBody->getCollider(0)->getMaterial();
|
||||||
|
material.setFrictionCoefficient(0.35);
|
||||||
|
material.setMassDensity(1.f);
|
||||||
|
|
||||||
|
//https://github.com/DanielChappuis/reactphysics3d/issues/170#issuecomment-691514860
|
||||||
|
part->rigidBody->updateMassFromColliders();
|
||||||
|
part->rigidBody->updateLocalInertiaTensorFromColliders();
|
||||||
|
|
||||||
|
part->rigidBody->setLinearVelocity(part->velocity);
|
||||||
|
// part->rigidBody->setMass(density * part->size.x * part->size.y * part->size.z);
|
||||||
|
|
||||||
|
part->rigidBody->setUserData(&*part);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Workspace::ProcessContactEvents() {
|
||||||
|
contactQueueLock.lock();
|
||||||
|
while (!contactQueue.empty()) {
|
||||||
|
ContactItem& contact = contactQueue.front();
|
||||||
|
contactQueue.pop();
|
||||||
|
if (contact.action == ContactItem::CONTACTITEM_TOUCHED) {
|
||||||
|
contact.part0->Touched->Fire({ (Variant)InstanceRef(contact.part1) });
|
||||||
|
contact.part1->Touched->Fire({ (Variant)InstanceRef(contact.part0) });
|
||||||
|
} else if (contact.action == ContactItem::CONTACTITEM_TOUCHENDED) {
|
||||||
|
contact.part0->TouchEnded->Fire({ (Variant)InstanceRef(contact.part1) });
|
||||||
|
contact.part1->TouchEnded->Fire({ (Variant)InstanceRef(contact.part0) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contactQueueLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Workspace::SyncPartPhysics(std::shared_ptr<BasePart> part) {
|
||||||
|
if (globalPhysicsLock.try_lock()) {
|
||||||
|
updatePartPhysics(part);
|
||||||
|
globalPhysicsLock.unlock();
|
||||||
|
} else {
|
||||||
|
part->rigidBodyDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tu_time_t physTime;
|
||||||
|
void Workspace::PhysicsStep(float deltaTime) {
|
||||||
|
tu_time_t startTime = tu_clock_micros();
|
||||||
|
|
||||||
|
std::scoped_lock lock(globalPhysicsLock);
|
||||||
|
physicsWorld->update(std::min(deltaTime / 2, (1/60.f)));
|
||||||
|
|
||||||
|
// Update queued objects
|
||||||
|
queueLock.lock();
|
||||||
|
for (QueueItem item : bodyQueue) {
|
||||||
|
if (item.action == QueueItem::QUEUEITEM_ADD) {
|
||||||
|
simulatedBodies.push_back(item.part);
|
||||||
|
item.part->simulationTicket = --simulatedBodies.end();
|
||||||
|
} else if (item.part->simulationTicket.has_value()) {
|
||||||
|
simulatedBodies.erase(item.part->simulationTicket.value());
|
||||||
|
item.part->simulationTicket = std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
queueLock.unlock();
|
||||||
|
|
||||||
|
// TODO: Add list of tracked parts in workspace based on their ancestry using inWorkspace property of Instance
|
||||||
|
for (std::shared_ptr<BasePart> part : simulatedBodies) {
|
||||||
|
// If the part's body is dirty, update it now instead
|
||||||
|
if (part->rigidBodyDirty) {
|
||||||
|
updatePartPhysics(part);
|
||||||
|
part->rigidBodyDirty = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!part->rigidBody) continue;
|
||||||
|
|
||||||
|
// Sync properties
|
||||||
|
const rp::Transform& transform = part->rigidBody->getTransform();
|
||||||
|
part->cframe = CFrame(transform);
|
||||||
|
part->velocity = part->rigidBody->getLinearVelocity();
|
||||||
|
|
||||||
|
// part->rigidBody->enableGravity(true);
|
||||||
|
// RotateV/Motor joint
|
||||||
|
for (auto& joint : part->secondaryJoints) {
|
||||||
|
if (joint.expired() || !joint.lock()->IsA("RotateV")) continue;
|
||||||
|
|
||||||
|
std::shared_ptr<JointInstance> motor = joint.lock()->CastTo<JointInstance>().expect();
|
||||||
|
float rate = motor->part0.lock()->GetSurfaceParamB(-motor->c0.LookVector().Unit()) * 30;
|
||||||
|
// part->rigidBody->enableGravity(false);
|
||||||
|
part->rigidBody->setAngularVelocity(-(motor->part0.lock()->cframe * motor->c0).LookVector() * rate);
|
||||||
|
}
|
||||||
|
|
||||||
for (std::shared_ptr<BasePart> part : physicsWorld->getSimulatedBodies()) {
|
|
||||||
// Destroy fallen parts
|
// Destroy fallen parts
|
||||||
if (part->cframe.Position().Y() < this->fallenPartsDestroyHeight) {
|
if (part->cframe.Position().Y() < this->fallenPartsDestroyHeight) {
|
||||||
auto parent = part->GetParent();
|
auto parent = part->GetParent();
|
||||||
part->Destroy();
|
part->Destroy();
|
||||||
|
|
||||||
// If the parent of the part is a Model, destroy it too
|
// If the parent of the part is a Model, destroy it too
|
||||||
if (parent != nullptr && parent->IsA("Model"))
|
if (parent.has_value() && parent.value()->IsA("Model"))
|
||||||
parent->Destroy();
|
parent.value()->Destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
physTime = tu_clock_micros() - startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RaycastResult::RaycastResult(const rp::RaycastInfo& raycastInfo)
|
||||||
|
: worldPoint(raycastInfo.worldPoint)
|
||||||
|
, worldNormal(raycastInfo.worldNormal)
|
||||||
|
, hitFraction(raycastInfo.hitFraction)
|
||||||
|
, triangleIndex(raycastInfo.triangleIndex)
|
||||||
|
, body(raycastInfo.body)
|
||||||
|
, collider(raycastInfo.collider) {}
|
||||||
|
|
||||||
|
class NearestRayHit : public rp::RaycastCallback {
|
||||||
|
rp::Vector3 startPos;
|
||||||
|
std::optional<RaycastFilter> filter;
|
||||||
|
|
||||||
|
std::optional<RaycastResult> nearestHit;
|
||||||
|
float nearestHitDistance = -1;
|
||||||
|
|
||||||
|
// Order is not guaranteed, so we have to figure out the nearest object using a more sophisticated algorith,
|
||||||
|
rp::decimal notifyRaycastHit(const rp::RaycastInfo& raycastInfo) override {
|
||||||
|
// If the detected object is further away than the nearest object, continue.
|
||||||
|
int distance = (raycastInfo.worldPoint - startPos).length();
|
||||||
|
if (nearestHitDistance != -1 && distance >= nearestHitDistance)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!filter) {
|
||||||
|
nearestHit = raycastInfo;
|
||||||
|
nearestHitDistance = distance;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<BasePart> part = partFromBody(raycastInfo.body);
|
||||||
|
FilterResult result = filter.value()(part);
|
||||||
|
if (result == FilterResult::BLOCK) {
|
||||||
|
nearestHit = std::nullopt;
|
||||||
|
nearestHitDistance = distance;
|
||||||
|
return 1;
|
||||||
|
} else if (result == FilterResult::TARGET) {
|
||||||
|
nearestHit = raycastInfo;
|
||||||
|
nearestHitDistance = distance;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
NearestRayHit(rp::Vector3 startPos, std::optional<RaycastFilter> filter = std::nullopt) : startPos(startPos), filter(filter) {}
|
||||||
|
std::optional<const RaycastResult> getNearestHit() { return nearestHit; };
|
||||||
|
};
|
||||||
|
|
||||||
|
std::optional<const RaycastResult> Workspace::CastRayNearest(glm::vec3 point, glm::vec3 rotation, float maxLength, std::optional<RaycastFilter> filter, unsigned short categoryMaskBits) {
|
||||||
|
// std::scoped_lock lock(globalPhysicsLock);
|
||||||
|
rp::Ray ray(glmToRp(point), glmToRp(glm::normalize(rotation)) * maxLength);
|
||||||
|
NearestRayHit rayHit(glmToRp(point), filter);
|
||||||
|
physicsWorld->raycast(ray, &rayHit, categoryMaskBits);
|
||||||
|
return rayHit.getNearestHit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Workspace::DestroyRigidBody(rp::RigidBody* rigidBody) {
|
||||||
|
std::scoped_lock lock(globalPhysicsLock);
|
||||||
|
physicsWorld->destroyRigidBody(rigidBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Workspace::DestroyJoint(rp::Joint* joint) {
|
||||||
|
std::scoped_lock lock(globalPhysicsLock);
|
||||||
|
physicsWorld->destroyJoint(joint);
|
||||||
|
}
|
||||||
|
|
||||||
|
rp::Joint* Workspace::CreateJoint(const rp::JointInfo& jointInfo) {
|
||||||
|
std::scoped_lock lock(globalPhysicsLock);
|
||||||
|
rp::Joint* joint = physicsWorld->createJoint(jointInfo);
|
||||||
|
|
||||||
|
return joint;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Workspace::AddBody(std::shared_ptr<BasePart> part) {
|
||||||
|
queueLock.lock();
|
||||||
|
bodyQueue.push_back({part, QueueItem::QUEUEITEM_ADD});
|
||||||
|
part->rigidBodyDirty = true;
|
||||||
|
queueLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Workspace::RemoveBody(std::shared_ptr<BasePart> part) {
|
||||||
|
queueLock.lock();
|
||||||
|
bodyQueue.push_back({part, QueueItem::QUEUEITEM_REMOVE});
|
||||||
|
queueLock.unlock();
|
||||||
}
|
}
|
|
@ -2,13 +2,35 @@
|
||||||
|
|
||||||
#include "objects/annotation.h"
|
#include "objects/annotation.h"
|
||||||
#include "objects/base/service.h"
|
#include "objects/base/service.h"
|
||||||
#include "physics/world.h"
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include <glm/ext/vector_float3.hpp>
|
#include <glm/ext/vector_float3.hpp>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
#include <reactphysics3d/body/RigidBody.h>
|
||||||
|
#include <reactphysics3d/engine/EventListener.h>
|
||||||
|
#include <reactphysics3d/engine/PhysicsCommon.h>
|
||||||
|
#include <reactphysics3d/engine/PhysicsWorld.h>
|
||||||
|
|
||||||
|
namespace rp = reactphysics3d;
|
||||||
|
|
||||||
|
struct RaycastResult {
|
||||||
|
rp::Vector3 worldPoint;
|
||||||
|
rp::Vector3 worldNormal;
|
||||||
|
rp::decimal hitFraction;
|
||||||
|
int triangleIndex;
|
||||||
|
rp::Body* body;
|
||||||
|
rp::Collider* collider;
|
||||||
|
|
||||||
|
RaycastResult(const rp::RaycastInfo& raycastInfo);
|
||||||
|
};
|
||||||
|
|
||||||
|
enum FilterResult {
|
||||||
|
TARGET, // The object is captured
|
||||||
|
BLOCK, // The object blocks any objects behind it, but is not captured
|
||||||
|
PASS, // The object is transparent, ignore it
|
||||||
|
};
|
||||||
|
|
||||||
class BasePart;
|
class BasePart;
|
||||||
class Snap;
|
class Snap;
|
||||||
|
@ -16,6 +38,21 @@ class Weld;
|
||||||
class Rotate;
|
class Rotate;
|
||||||
class RotateV;
|
class RotateV;
|
||||||
|
|
||||||
|
#ifndef __SIMULATION_TICKET
|
||||||
|
#define __SIMULATION_TICKET
|
||||||
|
typedef std::list<std::shared_ptr<BasePart>>::iterator SimulationTicket;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef std::function<FilterResult(std::shared_ptr<BasePart>)> RaycastFilter;
|
||||||
|
|
||||||
|
struct QueueItem {
|
||||||
|
std::shared_ptr<BasePart> part;
|
||||||
|
enum {
|
||||||
|
QUEUEITEM_ADD,
|
||||||
|
QUEUEITEM_REMOVE,
|
||||||
|
} action;
|
||||||
|
};
|
||||||
|
|
||||||
struct ContactItem {
|
struct ContactItem {
|
||||||
std::shared_ptr<BasePart> part0;
|
std::shared_ptr<BasePart> part0;
|
||||||
std::shared_ptr<BasePart> part1;
|
std::shared_ptr<BasePart> part1;
|
||||||
|
@ -25,14 +62,31 @@ struct ContactItem {
|
||||||
} action;
|
} action;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Workspace;
|
||||||
|
class PhysicsEventListener : public rp::EventListener {
|
||||||
|
friend Workspace;
|
||||||
|
Workspace* workspace;
|
||||||
|
|
||||||
|
PhysicsEventListener(Workspace*);
|
||||||
|
|
||||||
|
void onContact(const rp::CollisionCallback::CallbackData&) override;
|
||||||
|
void onTrigger(const rp::OverlapCallback::CallbackData&) override;
|
||||||
|
};
|
||||||
|
|
||||||
class DEF_INST_SERVICE_(explorer_icon="workspace") Workspace : public Service {
|
class DEF_INST_SERVICE_(explorer_icon="workspace") Workspace : public Service {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
|
|
||||||
|
friend PhysicsEventListener;
|
||||||
|
|
||||||
|
std::list<std::shared_ptr<BasePart>> simulatedBodies;
|
||||||
|
std::list<QueueItem> bodyQueue;
|
||||||
std::queue<ContactItem> contactQueue;
|
std::queue<ContactItem> contactQueue;
|
||||||
std::mutex contactQueueLock;
|
std::mutex contactQueueLock;
|
||||||
|
rp::PhysicsWorld* physicsWorld;
|
||||||
|
static rp::PhysicsCommon* physicsCommon;
|
||||||
|
PhysicsEventListener physicsEventListener;
|
||||||
|
|
||||||
std::shared_ptr<PhysWorld> physicsWorld;
|
void updatePartPhysics(std::shared_ptr<BasePart> part);
|
||||||
friend PhysWorld;
|
|
||||||
protected:
|
protected:
|
||||||
void InitService() override;
|
void InitService() override;
|
||||||
void OnRun() override;
|
void OnRun() override;
|
||||||
|
@ -42,6 +96,7 @@ public:
|
||||||
Workspace();
|
Workspace();
|
||||||
~Workspace();
|
~Workspace();
|
||||||
|
|
||||||
|
std::mutex globalPhysicsLock;
|
||||||
std::recursive_mutex queueLock;
|
std::recursive_mutex queueLock;
|
||||||
|
|
||||||
DEF_PROP float fallenPartsDestroyHeight = -500;
|
DEF_PROP float fallenPartsDestroyHeight = -500;
|
||||||
|
@ -49,13 +104,15 @@ public:
|
||||||
// static inline std::shared_ptr<Workspace> New() { return std::make_shared<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>(); };
|
static inline std::shared_ptr<Instance> Create() { return std::make_shared<Workspace>(); };
|
||||||
|
|
||||||
inline void AddBody(std::shared_ptr<BasePart> part) { physicsWorld->addBody(part); }
|
void AddBody(std::shared_ptr<BasePart> part);
|
||||||
inline void RemoveBody(std::shared_ptr<BasePart> part) { physicsWorld->removeBody(part); }
|
void RemoveBody(std::shared_ptr<BasePart> part);
|
||||||
|
void DestroyRigidBody(rp::RigidBody* rigidBody);
|
||||||
void SyncPartPhysics(std::shared_ptr<BasePart> part);
|
void SyncPartPhysics(std::shared_ptr<BasePart> part);
|
||||||
|
|
||||||
inline PhysJoint CreateJoint(PhysJointInfo& info, std::shared_ptr<BasePart> part0, std::shared_ptr<BasePart> part1) { return physicsWorld->createJoint(info, part0, part1); }
|
rp::Joint* CreateJoint(const rp::JointInfo& jointInfo);
|
||||||
inline void DestroyJoint(PhysJoint joint) { physicsWorld->destroyJoint(joint); }
|
void DestroyJoint(rp::Joint* joint);
|
||||||
|
|
||||||
|
void ProcessContactEvents();
|
||||||
void PhysicsStep(float deltaTime);
|
void PhysicsStep(float deltaTime);
|
||||||
inline std::optional<const RaycastResult> CastRayNearest(glm::vec3 point, glm::vec3 rotation, float maxLength, std::optional<RaycastFilter> filter = std::nullopt, unsigned short categoryMaskBits = 0xFFFF) { return physicsWorld->castRay(point, rotation, maxLength, filter, categoryMaskBits); }
|
std::optional<const RaycastResult> CastRayNearest(glm::vec3 point, glm::vec3 rotation, float maxLength, std::optional<RaycastFilter> filter = std::nullopt, unsigned short categoryMaskBits = 0xFFFF);
|
||||||
};
|
};
|
|
@ -1,8 +1,13 @@
|
||||||
#include "panic.h"
|
#include "panic.h"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
|
#ifdef _NDEBUG
|
||||||
|
#define NDEBUG
|
||||||
|
#endif
|
||||||
|
|
||||||
bool trySafeAbort = false;
|
bool trySafeAbort = false;
|
||||||
void panic() {
|
void panic() {
|
||||||
// We've already been here, safe aborting has failed.
|
// We've already been here, safe aborting has failed.
|
||||||
|
|
|
@ -61,7 +61,7 @@ PartAssembly PartAssembly::FromSelection(std::shared_ptr<Selection> selection) {
|
||||||
|
|
||||||
void PartAssembly::SetCollisionsEnabled(bool enabled) {
|
void PartAssembly::SetCollisionsEnabled(bool enabled) {
|
||||||
for (auto part : parts) {
|
for (auto part : parts) {
|
||||||
part->rigidBody.setCollisionsEnabled(enabled);
|
part->rigidBody->getCollider(0)->setIsWorldQueryCollider(enabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include "datatypes/cframe.h"
|
|
||||||
#include "datatypes/vector.h"
|
|
||||||
#include <glm/ext/vector_float3.hpp>
|
|
||||||
#include <glm/ext.hpp>
|
|
||||||
|
|
||||||
#include <Jolt/Jolt.h>
|
|
||||||
|
|
||||||
template <typename T, typename F>
|
|
||||||
T convert(F vec) = delete;
|
|
||||||
|
|
||||||
// Vector3
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline Vector3 convert<Vector3>(JPH::Vec3 vec) {
|
|
||||||
return Vector3(vec.GetX(), vec.GetY(), vec.GetZ());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline JPH::Vec3 convert<JPH::Vec3>(Vector3 vec) {
|
|
||||||
return JPH::Vec3(vec.X(), vec.Y(), vec.Z());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline glm::vec3 convert<glm::vec3>(JPH::Vec3 vec) {
|
|
||||||
return glm::vec3(vec.GetX(), vec.GetY(), vec.GetZ());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline JPH::Vec3 convert<JPH::Vec3>(glm::vec3 vec) {
|
|
||||||
return JPH::Vec3(vec.x, vec.y, vec.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Quaternion
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline glm::quat convert<glm::quat>(JPH::Quat quat) {
|
|
||||||
return glm::quat(quat.GetW(), quat.GetX(), quat.GetY(), quat.GetZ());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline JPH::Quat convert<JPH::Quat>(glm::quat quat) {
|
|
||||||
return JPH::Quat(quat.x, quat.y, quat.z, quat.w);
|
|
||||||
}
|
|
39
core/src/physics/util.h
Normal file
39
core/src/physics/util.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#pragma once
|
||||||
|
#include <glm/ext/vector_float3.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <reactphysics3d/body/Body.h>
|
||||||
|
#include <reactphysics3d/mathematics/Matrix3x3.h>
|
||||||
|
#include <reactphysics3d/mathematics/Quaternion.h>
|
||||||
|
#include <reactphysics3d/mathematics/Vector3.h>
|
||||||
|
#include <reactphysics3d/mathematics/mathematics.h>
|
||||||
|
#include <glm/ext.hpp>
|
||||||
|
#include "objects/part/part.h"
|
||||||
|
|
||||||
|
namespace rp = reactphysics3d;
|
||||||
|
|
||||||
|
inline rp::Vector3 glmToRp(glm::vec3 vec) {
|
||||||
|
return rp::Vector3(vec.x, vec.y, vec.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline rp::Quaternion glmToRp(glm::quat quat) {
|
||||||
|
return rp::Quaternion(quat.w, rp::Vector3(quat.x, quat.y, quat.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline rp::Matrix3x3 glmToRp(glm::mat3 mat) {
|
||||||
|
// return (rp::Quaternion)glmToRp((glm::quat)mat);
|
||||||
|
// }
|
||||||
|
|
||||||
|
inline glm::vec3 rpToGlm(rp::Vector3 vec) {
|
||||||
|
return glm::vec3(vec.x, vec.y, vec.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline glm::quat rpToGlm(rp::Quaternion quat) {
|
||||||
|
return glm::quat(quat.w, quat.x, quat.y, quat.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make this std::optional
|
||||||
|
inline std::shared_ptr<BasePart> partFromBody(rp::Body* body) {
|
||||||
|
BasePart* raw = reinterpret_cast<BasePart*>(body->getUserData());
|
||||||
|
std::shared_ptr<BasePart> shared = std::dynamic_pointer_cast<BasePart>(raw->shared_from_this());
|
||||||
|
return shared;
|
||||||
|
}
|
|
@ -1,346 +0,0 @@
|
||||||
#include "world.h"
|
|
||||||
#include "datatypes/vector.h"
|
|
||||||
#include "enum/part.h"
|
|
||||||
#include "logger.h"
|
|
||||||
#include "objects/part/basepart.h"
|
|
||||||
#include "objects/part/part.h"
|
|
||||||
#include "objects/part/wedgepart.h"
|
|
||||||
#include "objects/service/workspace.h"
|
|
||||||
#include "physics/convert.h"
|
|
||||||
#include "timeutil.h"
|
|
||||||
|
|
||||||
#include <Jolt/Jolt.h>
|
|
||||||
#include <Jolt/Core/JobSystemThreadPool.h>
|
|
||||||
#include <Jolt/Core/TempAllocator.h>
|
|
||||||
#include <Jolt/Physics/Collision/BroadPhase/BroadPhaseLayer.h>
|
|
||||||
#include <Jolt/Physics/Collision/ObjectLayer.h>
|
|
||||||
#include <Jolt/Core/Factory.h>
|
|
||||||
#include <Jolt/Core/Memory.h>
|
|
||||||
#include <Jolt/Physics/Body/BodyCreationSettings.h>
|
|
||||||
#include <Jolt/Physics/Body/BodyInterface.h>
|
|
||||||
#include <Jolt/Physics/Body/MotionType.h>
|
|
||||||
#include <Jolt/Physics/Collision/RayCast.h>
|
|
||||||
#include <Jolt/Physics/Collision/Shape/BoxShape.h>
|
|
||||||
#include <Jolt/Physics/Collision/Shape/SphereShape.h>
|
|
||||||
#include <Jolt/Physics/Collision/Shape/CylinderShape.h>
|
|
||||||
#include <Jolt/Physics/Collision/Shape/ScaledShape.h>
|
|
||||||
#include <Jolt/Physics/Collision/Shape/ConvexHullShape.h>
|
|
||||||
#include <Jolt/Physics/Collision/Shape/RotatedTranslatedShape.h>
|
|
||||||
#include <Jolt/Physics/EActivation.h>
|
|
||||||
#include <Jolt/Physics/PhysicsSettings.h>
|
|
||||||
#include <Jolt/RegisterTypes.h>
|
|
||||||
#include <Jolt/Physics/Collision/CollisionCollectorImpl.h>
|
|
||||||
#include <Jolt/Physics/Collision/CastResult.h>
|
|
||||||
#include <Jolt/Physics/Collision/Shape/SubShapeID.h>
|
|
||||||
#include <Jolt/Physics/Body/BodyFilter.h>
|
|
||||||
#include <Jolt/Physics/Body/BodyLockInterface.h>
|
|
||||||
#include <Jolt/Physics/Collision/NarrowPhaseQuery.h>
|
|
||||||
#include <Jolt/Physics/Constraints/FixedConstraint.h>
|
|
||||||
#include <Jolt/Physics/Constraints/HingeConstraint.h>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
static JPH::TempAllocator* allocator;
|
|
||||||
static JPH::JobSystem* jobSystem;
|
|
||||||
|
|
||||||
namespace Layers
|
|
||||||
{
|
|
||||||
static constexpr JPH::ObjectLayer DYNAMIC = 0;
|
|
||||||
static constexpr JPH::ObjectLayer ANCHORED = 1;
|
|
||||||
static constexpr JPH::ObjectLayer NOCOLLIDE = 2;
|
|
||||||
// static constexpr JPH::ObjectLayer NUM_LAYERS = 3;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace BPLayers
|
|
||||||
{
|
|
||||||
static constexpr JPH::BroadPhaseLayer ANCHORED(0);
|
|
||||||
static constexpr JPH::BroadPhaseLayer DYNAMIC(1);
|
|
||||||
static constexpr JPH::BroadPhaseLayer NOCOLLIDE(2);
|
|
||||||
static constexpr uint NUM_LAYERS(3);
|
|
||||||
};
|
|
||||||
|
|
||||||
static JPH::Ref<JPH::Shape> wedgeShape;
|
|
||||||
|
|
||||||
void physicsInit() {
|
|
||||||
JPH::RegisterDefaultAllocator();
|
|
||||||
JPH::Factory::sInstance = new JPH::Factory();
|
|
||||||
JPH::RegisterTypes();
|
|
||||||
|
|
||||||
allocator = new JPH::TempAllocatorImpl(10 * 1024 * 1024);
|
|
||||||
jobSystem = new JPH::JobSystemThreadPool(JPH::cMaxPhysicsJobs, JPH::cMaxPhysicsBarriers, std::thread::hardware_concurrency() - 1);
|
|
||||||
|
|
||||||
// Create special shapes
|
|
||||||
JPH::Array<JPH::Vec3> wedgeVerts;
|
|
||||||
wedgeVerts.push_back({-1, -1, -1});
|
|
||||||
wedgeVerts.push_back({ 1, -1, -1});
|
|
||||||
wedgeVerts.push_back({-1, -1, 1});
|
|
||||||
wedgeVerts.push_back({ 1, -1, 1});
|
|
||||||
wedgeVerts.push_back({ 1, 1, 1});
|
|
||||||
wedgeVerts.push_back({-1, 1, 1});
|
|
||||||
// // Invisible bevel to avoid phasing
|
|
||||||
// wedgeVerts.push_back({1, 1, 0.9});
|
|
||||||
// wedgeVerts.push_back({0, 1, 0.9});
|
|
||||||
|
|
||||||
wedgeShape = JPH::ConvexHullShapeSettings(wedgeVerts).Create().Get();
|
|
||||||
}
|
|
||||||
|
|
||||||
void physicsDeinit() {
|
|
||||||
JPH::UnregisterTypes();
|
|
||||||
delete JPH::Factory::sInstance;
|
|
||||||
JPH::Factory::sInstance = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
PhysWorld::PhysWorld() {
|
|
||||||
worldImpl.Init(4096, 0, 4096, 4096, broadPhaseLayerInterface, objectBroadPhasefilter, objectLayerPairFilter);
|
|
||||||
worldImpl.SetGravity(JPH::Vec3(0, -196, 0));
|
|
||||||
JPH::PhysicsSettings settings = worldImpl.GetPhysicsSettings();
|
|
||||||
// settings.mPointVelocitySleepThreshold = 0.04f; // Fix parts not sleeping
|
|
||||||
// settings.mNumVelocitySteps *= 20;
|
|
||||||
// settings.mNumPositionSteps *= 20;
|
|
||||||
worldImpl.SetPhysicsSettings(settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
PhysWorld::~PhysWorld() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysWorld::addBody(std::shared_ptr<BasePart> part) {
|
|
||||||
syncBodyProperties(part);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysWorld::removeBody(std::shared_ptr<BasePart> part) {
|
|
||||||
JPH::BodyInterface& interface = worldImpl.GetBodyInterface();
|
|
||||||
|
|
||||||
// https://jrouwe.github.io/JoltPhysics/index.html#sleeping-bodies
|
|
||||||
// Wake sleeping bodies in its area before removing it
|
|
||||||
Vector3 aabbSize = part->GetAABB();
|
|
||||||
interface.ActivateBodiesInAABox(JPH::AABox(convert<JPH::Vec3>(part->position() - aabbSize), convert<JPH::Vec3>(part->position() + aabbSize)), {}, {});
|
|
||||||
|
|
||||||
interface.RemoveBody(part->rigidBody.bodyImpl->GetID());
|
|
||||||
interface.DestroyBody(part->rigidBody.bodyImpl->GetID());
|
|
||||||
part->rigidBody.bodyImpl = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
JPH::Shape* makeShape(std::shared_ptr<BasePart> basePart) {
|
|
||||||
if (std::shared_ptr<Part> part = std::dynamic_pointer_cast<Part>(basePart)) {
|
|
||||||
switch (part->shape) {
|
|
||||||
case PartType::Block:
|
|
||||||
return new JPH::BoxShape(convert<JPH::Vec3>(part->size / 2.f), JPH::cDefaultConvexRadius);
|
|
||||||
case PartType::Ball:
|
|
||||||
return new JPH::SphereShape(glm::min(part->size.X(), part->size.Y(), part->size.Z()) / 2.f);
|
|
||||||
case PartType::Cylinder:
|
|
||||||
return new JPH::RotatedTranslatedShape(JPH::Vec3(), JPH::Quat::sEulerAngles(JPH::Vec3(0, 0, JPH::JPH_PI * 0.5)), new JPH::CylinderShape(part->size.X() / 2.f, glm::min(part->size.Z(), part->size.Y()) / 2.f));
|
|
||||||
}
|
|
||||||
} else if (std::shared_ptr<WedgePart> part = std::dynamic_pointer_cast<WedgePart>(basePart)) {
|
|
||||||
return new JPH::ScaledShape(wedgeShape, convert<JPH::Vec3>(part->size / 2.f));
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysWorld::syncBodyProperties(std::shared_ptr<BasePart> part) {
|
|
||||||
JPH::BodyInterface& interface = worldImpl.GetBodyInterface();
|
|
||||||
|
|
||||||
JPH::EMotionType motionType = part->anchored ? JPH::EMotionType::Static : JPH::EMotionType::Dynamic;
|
|
||||||
JPH::EActivation activationMode = part->anchored ? JPH::EActivation::DontActivate : JPH::EActivation::Activate;
|
|
||||||
JPH::ObjectLayer objectLayer = !part->canCollide ? Layers::NOCOLLIDE : (part->anchored ? Layers::ANCHORED : Layers::DYNAMIC);
|
|
||||||
|
|
||||||
JPH::Body* body = part->rigidBody.bodyImpl;
|
|
||||||
|
|
||||||
// Generate a new rigidBody
|
|
||||||
if (body == nullptr) {
|
|
||||||
JPH::Shape* shape = makeShape(part);
|
|
||||||
JPH::BodyCreationSettings settings(shape, convert<JPH::Vec3>(part->position()), convert<JPH::Quat>((glm::quat)part->cframe.RotMatrix()), motionType, objectLayer);
|
|
||||||
settings.mAllowDynamicOrKinematic = true;
|
|
||||||
settings.mRestitution = 0.5;
|
|
||||||
|
|
||||||
body = interface.CreateBody(settings);
|
|
||||||
body->SetUserData((JPH::uint64)part.get());
|
|
||||||
part->rigidBody.bodyImpl = body;
|
|
||||||
|
|
||||||
interface.AddBody(body->GetID(), activationMode);
|
|
||||||
interface.SetLinearVelocity(body->GetID(), convert<JPH::Vec3>(part->velocity));
|
|
||||||
} else {
|
|
||||||
std::shared_ptr<Part> part2 = std::dynamic_pointer_cast<Part>(part);
|
|
||||||
bool shouldUpdateShape = (part2 != nullptr && part->rigidBody._lastShape != part2->shape) || part->rigidBody._lastSize == part->size;
|
|
||||||
|
|
||||||
if (shouldUpdateShape) {
|
|
||||||
// const JPH::Shape* oldShape = body->GetShape();
|
|
||||||
JPH::Shape* newShape = makeShape(part);
|
|
||||||
|
|
||||||
interface.SetShape(body->GetID(), newShape, true, activationMode);
|
|
||||||
// Seems like Jolt manages its memory for us, so we don't need the below
|
|
||||||
// delete oldShape;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface.SetObjectLayer(body->GetID(), objectLayer);
|
|
||||||
interface.SetMotionType(body->GetID(), motionType, activationMode);
|
|
||||||
interface.SetPositionRotationAndVelocity(body->GetID(), convert<JPH::Vec3>(part->position()), convert<JPH::Quat>((glm::quat)part->cframe.RotMatrix()), convert<JPH::Vec3>(part->velocity), /* Angular velocity is NYI: */ body->GetAngularVelocity());
|
|
||||||
}
|
|
||||||
|
|
||||||
part->rigidBody._lastSize = part->size;
|
|
||||||
if (std::shared_ptr<Part> part2 = std::dynamic_pointer_cast<Part>(part)) part->rigidBody._lastShape = part2->shape;
|
|
||||||
}
|
|
||||||
|
|
||||||
tu_time_t physTime;
|
|
||||||
void PhysWorld::step(float deltaTime) {
|
|
||||||
tu_time_t startTime = tu_clock_micros();
|
|
||||||
// Depending on the load, it may be necessary to call this with a differing collision step count
|
|
||||||
// 5 seems to be a good number supporting the high gravity
|
|
||||||
worldImpl.Update(deltaTime, 5, allocator, jobSystem);
|
|
||||||
|
|
||||||
JPH::BodyInterface& interface = worldImpl.GetBodyInterface();
|
|
||||||
JPH::BodyIDVector bodyIDs;
|
|
||||||
worldImpl.GetBodies(bodyIDs);
|
|
||||||
for (JPH::BodyID bodyID : bodyIDs) {
|
|
||||||
std::shared_ptr<BasePart> part = ((Instance*)interface.GetUserData(bodyID))->shared<BasePart>();
|
|
||||||
part->cframe = CFrame(convert<Vector3>(interface.GetPosition(bodyID)), convert<glm::quat>(interface.GetRotation(bodyID)));
|
|
||||||
}
|
|
||||||
|
|
||||||
physTime = tu_clock_micros() - startTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
PhysJoint PhysWorld::createJoint(PhysJointInfo& type, std::shared_ptr<BasePart> part0, std::shared_ptr<BasePart> part1) {
|
|
||||||
if (part0->rigidBody.bodyImpl == nullptr
|
|
||||||
|| part1->rigidBody.bodyImpl == nullptr
|
|
||||||
|| !part0->workspace()
|
|
||||||
|| !part1->workspace()
|
|
||||||
|| part0->workspace()->physicsWorld != shared_from_this()
|
|
||||||
|| part1->workspace()->physicsWorld != shared_from_this()
|
|
||||||
) { Logger::fatalError("Failed to create joint between two parts due to the call being invalid"); panic(); };
|
|
||||||
|
|
||||||
JPH::TwoBodyConstraint* constraint;
|
|
||||||
if (PhysFixedJointInfo* info = dynamic_cast<PhysFixedJointInfo*>(&type)) {
|
|
||||||
JPH::FixedConstraintSettings settings;
|
|
||||||
settings.mSpace = JPH::EConstraintSpace::LocalToBodyCOM;
|
|
||||||
settings.mPoint1 = convert<JPH::Vec3>(info->c0.Position());
|
|
||||||
settings.mAxisX1 = convert<JPH::Vec3>(info->c0.RightVector());
|
|
||||||
settings.mAxisY1 = convert<JPH::Vec3>(info->c0.UpVector());
|
|
||||||
settings.mPoint2 = convert<JPH::Vec3>(info->c1.Position());
|
|
||||||
settings.mAxisX2 = convert<JPH::Vec3>(info->c1.RightVector());
|
|
||||||
settings.mAxisY2 = convert<JPH::Vec3>(info->c1.UpVector());
|
|
||||||
constraint = settings.Create(*part0->rigidBody.bodyImpl, *part1->rigidBody.bodyImpl);
|
|
||||||
} else if (PhysRotatingJointInfo* info = dynamic_cast<PhysRotatingJointInfo*>(&type)) {
|
|
||||||
JPH::HingeConstraintSettings settings;
|
|
||||||
settings.mSpace = JPH::EConstraintSpace::LocalToBodyCOM;
|
|
||||||
settings.mPoint1 = convert<JPH::Vec3>(info->c0.Position());
|
|
||||||
settings.mNormalAxis1 = convert<JPH::Vec3>(info->c0.RightVector());
|
|
||||||
settings.mHingeAxis1 = convert<JPH::Vec3>(info->c0.LookVector());
|
|
||||||
settings.mPoint2 = convert<JPH::Vec3>(info->c1.Position());
|
|
||||||
settings.mNormalAxis2 = convert<JPH::Vec3>(info->c1.RightVector());
|
|
||||||
settings.mHingeAxis2 = convert<JPH::Vec3>(info->c1.LookVector());
|
|
||||||
// settings.mMotorSettings = JPH::MotorSettings(1.0f, 1.0f);
|
|
||||||
constraint = settings.Create(*part0->rigidBody.bodyImpl, *part1->rigidBody.bodyImpl);
|
|
||||||
if (info->motorized) {
|
|
||||||
static_cast<JPH::HingeConstraint*>(constraint)->SetMotorState(JPH::EMotorState::Velocity);
|
|
||||||
static_cast<JPH::HingeConstraint*>(constraint)->SetTargetAngularVelocity(-info->initialVelocity);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
panic();
|
|
||||||
}
|
|
||||||
|
|
||||||
worldImpl.AddConstraint(constraint);
|
|
||||||
return { constraint };
|
|
||||||
}
|
|
||||||
|
|
||||||
// WATCH OUT! This should only be called for HingeConstraints.
|
|
||||||
// Can't use dynamic_cast because TwoBodyConstraint is not virtual
|
|
||||||
void PhysJoint::setAngularVelocity(float velocity) {
|
|
||||||
JPH::HingeConstraint* constraint = static_cast<JPH::HingeConstraint*>(jointImpl);
|
|
||||||
if (!constraint) return;
|
|
||||||
constraint->SetTargetAngularVelocity(-velocity);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysWorld::destroyJoint(PhysJoint joint) {
|
|
||||||
worldImpl.RemoveConstraint(joint.jointImpl);
|
|
||||||
}
|
|
||||||
|
|
||||||
class PhysRayCastBodyFilter : public JPH::BodyFilter {
|
|
||||||
bool ShouldCollideLocked(const JPH::Body &inBody) const override {
|
|
||||||
std::shared_ptr<BasePart> part = ((Instance*)inBody.GetUserData())->shared<BasePart>();
|
|
||||||
|
|
||||||
// Ignore specifically "hidden" parts from raycast
|
|
||||||
// TODO: Replace this with a better system... Please.
|
|
||||||
if (!part->rigidBody.isCollisionsEnabled()) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::optional<const RaycastResult> PhysWorld::castRay(Vector3 point, Vector3 rotation, float maxLength, std::optional<RaycastFilter> filter, unsigned short categoryMaskBits) {
|
|
||||||
if (filter != std::nullopt) { Logger::fatalError("The filter property of PhysWorld::castRay is not yet implemented"); panic(); };
|
|
||||||
|
|
||||||
const JPH::BodyLockInterface& lockInterface = worldImpl.GetBodyLockInterfaceNoLock();
|
|
||||||
const JPH::BodyInterface& interface = worldImpl.GetBodyInterface();
|
|
||||||
const JPH::NarrowPhaseQuery& query = worldImpl.GetNarrowPhaseQuery();
|
|
||||||
|
|
||||||
// First we cast a ray to find a matching part
|
|
||||||
Vector3 end = point + rotation.Unit() * maxLength;
|
|
||||||
JPH::RRayCast ray { convert<JPH::Vec3>(point), convert<JPH::Vec3>(end) };
|
|
||||||
JPH::RayCastResult result;
|
|
||||||
PhysRayCastBodyFilter bodyFilter;
|
|
||||||
bool hitFound = query.CastRay(ray, result, {}, {}, bodyFilter);
|
|
||||||
|
|
||||||
// No matches found, return empty
|
|
||||||
if (!hitFound) return std::nullopt;
|
|
||||||
|
|
||||||
// Next we cast a ray to find the hit surface and its world position and normal
|
|
||||||
JPH::BodyID hitBodyId = result.mBodyID;
|
|
||||||
std::shared_ptr<BasePart> part = ((Instance*)interface.GetUserData(hitBodyId))->shared<BasePart>();
|
|
||||||
const JPH::Shape* shape = interface.GetShape(hitBodyId);
|
|
||||||
|
|
||||||
// Find the hit position and hence the surface normal of the shape at that specific point
|
|
||||||
Vector3 hitPosition = point + rotation.Unit() * (maxLength * result.mFraction);
|
|
||||||
JPH::Vec3 surfaceNormal = shape->GetSurfaceNormal(result.mSubShapeID2, convert<JPH::Vec3>(part->cframe.Inverse() * hitPosition));
|
|
||||||
Vector3 worldNormal = part->cframe.Rotation() * convert<Vector3>(surfaceNormal);
|
|
||||||
|
|
||||||
return RaycastResult {
|
|
||||||
.worldPoint = hitPosition,
|
|
||||||
.worldNormal = worldNormal,
|
|
||||||
.body = lockInterface.TryGetBody(hitBodyId),
|
|
||||||
.hitPart = part,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
uint BroadPhaseLayerInterface::GetNumBroadPhaseLayers() const {
|
|
||||||
return BPLayers::NUM_LAYERS;
|
|
||||||
}
|
|
||||||
|
|
||||||
JPH::BroadPhaseLayer BroadPhaseLayerInterface::GetBroadPhaseLayer(JPH::ObjectLayer inLayer) const {
|
|
||||||
switch (inLayer) {
|
|
||||||
case Layers::DYNAMIC: return BPLayers::DYNAMIC;
|
|
||||||
case Layers::ANCHORED: return BPLayers::ANCHORED;
|
|
||||||
case Layers::NOCOLLIDE: return BPLayers::NOCOLLIDE;
|
|
||||||
default: panic();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char * BroadPhaseLayerInterface::GetBroadPhaseLayerName(JPH::BroadPhaseLayer inLayer) const {
|
|
||||||
using T = JPH::BroadPhaseLayer::Type;
|
|
||||||
switch ((T)inLayer) {
|
|
||||||
case (T)BPLayers::DYNAMIC: return "DYNAMIC";
|
|
||||||
case (T)BPLayers::ANCHORED: return "ANCHORED";
|
|
||||||
case (T)BPLayers::NOCOLLIDE: return "NOCOLLIDE";
|
|
||||||
default: panic();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ObjectBroadPhaseFilter::ShouldCollide(JPH::ObjectLayer inLayer1, JPH::BroadPhaseLayer inLayer2) const {
|
|
||||||
using T = JPH::BroadPhaseLayer::Type;
|
|
||||||
switch ((T)inLayer2) {
|
|
||||||
case (T)BPLayers::DYNAMIC: return true;
|
|
||||||
case (T)BPLayers::ANCHORED: return true;
|
|
||||||
case (T)BPLayers::NOCOLLIDE: return false;
|
|
||||||
default: panic();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ObjectLayerPairFilter::ShouldCollide(JPH::ObjectLayer inLayer1, JPH::ObjectLayer inLayer2) const {
|
|
||||||
switch (inLayer1) {
|
|
||||||
case Layers::DYNAMIC:
|
|
||||||
return true;
|
|
||||||
case Layers::ANCHORED:
|
|
||||||
return inLayer2 == Layers::DYNAMIC;
|
|
||||||
case Layers::NOCOLLIDE:
|
|
||||||
return false;
|
|
||||||
default:
|
|
||||||
panic();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,126 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "datatypes/cframe.h"
|
|
||||||
#include "datatypes/vector.h"
|
|
||||||
#include "enum/part.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include <functional>
|
|
||||||
#include <list>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include <Jolt/Jolt.h>
|
|
||||||
#include <Jolt/Physics/Body/Body.h>
|
|
||||||
#include <Jolt/Physics/PhysicsSystem.h>
|
|
||||||
#include <Jolt/Physics/Constraints/TwoBodyConstraint.h>
|
|
||||||
|
|
||||||
class BasePart;
|
|
||||||
class PhysWorld;
|
|
||||||
|
|
||||||
struct PhysJointInfo { virtual ~PhysJointInfo() = default; protected: PhysJointInfo() = default; };
|
|
||||||
|
|
||||||
struct PhysFixedJointInfo : PhysJointInfo {
|
|
||||||
CFrame c0;
|
|
||||||
CFrame c1;
|
|
||||||
|
|
||||||
inline PhysFixedJointInfo(CFrame c0, CFrame c1) : c0(c0), c1(c1) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PhysRotatingJointInfo : PhysJointInfo {
|
|
||||||
CFrame c0;
|
|
||||||
CFrame c1;
|
|
||||||
bool motorized;
|
|
||||||
float initialVelocity;
|
|
||||||
|
|
||||||
inline PhysRotatingJointInfo(CFrame c0, CFrame c1) : c0(c0), c1(c1), motorized(false), initialVelocity(0.f){}
|
|
||||||
inline PhysRotatingJointInfo(CFrame c0, CFrame c1, float initialVelocity) : c0(c0), c1(c1), motorized(true), initialVelocity(initialVelocity) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class PhysWorld;
|
|
||||||
struct PhysJoint {
|
|
||||||
public:
|
|
||||||
JPH::TwoBodyConstraint* jointImpl;
|
|
||||||
|
|
||||||
void setAngularVelocity(float velocity);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RaycastResult;
|
|
||||||
class PhysRigidBody {
|
|
||||||
JPH::Body* bodyImpl = nullptr;
|
|
||||||
inline PhysRigidBody(JPH::Body* rigidBody) : bodyImpl(rigidBody) {}
|
|
||||||
Vector3 _lastSize;
|
|
||||||
PartType _lastShape;
|
|
||||||
bool collisionsEnabled = true;
|
|
||||||
|
|
||||||
friend PhysWorld;
|
|
||||||
friend RaycastResult;
|
|
||||||
public:
|
|
||||||
inline PhysRigidBody() {}
|
|
||||||
|
|
||||||
inline void setActive(bool active) { if (!bodyImpl) return; }
|
|
||||||
inline void setCollisionsEnabled(bool enabled) { collisionsEnabled = enabled; }
|
|
||||||
inline bool isCollisionsEnabled() { return collisionsEnabled; }
|
|
||||||
void updateCollider(std::shared_ptr<BasePart>);
|
|
||||||
};
|
|
||||||
|
|
||||||
// // Provides internal implementation-specific values from the raycast result
|
|
||||||
// struct RaycastResultInternal {
|
|
||||||
// rp::decimal hitFraction;
|
|
||||||
// rp::Collider* collider;
|
|
||||||
// };
|
|
||||||
|
|
||||||
struct RaycastResult {
|
|
||||||
Vector3 worldPoint;
|
|
||||||
Vector3 worldNormal;
|
|
||||||
PhysRigidBody body;
|
|
||||||
nullable std::shared_ptr<BasePart> hitPart;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum FilterResult {
|
|
||||||
TARGET, // The object is captured
|
|
||||||
BLOCK, // The object blocks any objects behind it, but is not captured
|
|
||||||
PASS, // The object is transparent, ignore it
|
|
||||||
};
|
|
||||||
|
|
||||||
class BasePart;
|
|
||||||
typedef std::function<FilterResult(std::shared_ptr<BasePart>)> RaycastFilter;
|
|
||||||
|
|
||||||
class BroadPhaseLayerInterface : public JPH::BroadPhaseLayerInterface {
|
|
||||||
uint GetNumBroadPhaseLayers() const override;
|
|
||||||
JPH::BroadPhaseLayer GetBroadPhaseLayer(JPH::ObjectLayer inLayer) const override;
|
|
||||||
const char * GetBroadPhaseLayerName(JPH::BroadPhaseLayer inLayer) const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ObjectBroadPhaseFilter : public JPH::ObjectVsBroadPhaseLayerFilter {
|
|
||||||
bool ShouldCollide(JPH::ObjectLayer inLayer1, JPH::BroadPhaseLayer inLayer2) const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ObjectLayerPairFilter : public JPH::ObjectLayerPairFilter {
|
|
||||||
bool ShouldCollide(JPH::ObjectLayer inLayer1, JPH::ObjectLayer inLayer2) const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PhysWorld : public std::enable_shared_from_this<PhysWorld> {
|
|
||||||
BroadPhaseLayerInterface broadPhaseLayerInterface;
|
|
||||||
ObjectBroadPhaseFilter objectBroadPhasefilter;
|
|
||||||
ObjectLayerPairFilter objectLayerPairFilter;
|
|
||||||
JPH::PhysicsSystem worldImpl;
|
|
||||||
std::list<std::shared_ptr<BasePart>> simulatedBodies;
|
|
||||||
|
|
||||||
public:
|
|
||||||
PhysWorld();
|
|
||||||
~PhysWorld();
|
|
||||||
|
|
||||||
void step(float deltaTime);
|
|
||||||
|
|
||||||
void addBody(std::shared_ptr<BasePart>);
|
|
||||||
void removeBody(std::shared_ptr<BasePart>);
|
|
||||||
|
|
||||||
PhysJoint createJoint(PhysJointInfo& type, std::shared_ptr<BasePart> part0, std::shared_ptr<BasePart> part1);
|
|
||||||
void destroyJoint(PhysJoint joint);
|
|
||||||
|
|
||||||
inline const std::list<std::shared_ptr<BasePart>>& getSimulatedBodies() { return simulatedBodies; }
|
|
||||||
void syncBodyProperties(std::shared_ptr<BasePart>);
|
|
||||||
std::optional<const RaycastResult> castRay(Vector3 point, Vector3 rotation, float maxLength, std::optional<RaycastFilter> filter, unsigned short categoryMaskBits);
|
|
||||||
};
|
|
||||||
|
|
||||||
void physicsInit();
|
|
||||||
void physicsDeinit();
|
|
|
@ -2968,7 +2968,7 @@ static float OUTLINE_VERTICES[] = {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static float CYLINDER_CHEAP_VERTICES[] = {
|
static float CYLINDER_VERTICES[] = {
|
||||||
// positions // normals // texture coords
|
// positions // normals // texture coords
|
||||||
|
|
||||||
0.0, -0.5, 0.5, 0.2588, -0.9659, -0.0, 1.0, 0.5,
|
0.0, -0.5, 0.5, 0.2588, -0.9659, -0.0, 1.0, 0.5,
|
||||||
|
@ -3106,391 +3106,11 @@ static float CYLINDER_CHEAP_VERTICES[] = {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static float CYLINDER_VERTICES[] = {
|
|
||||||
// positions // normals // texture coords
|
|
||||||
|
|
||||||
0.5, 0.0, -0.5, -0.0, -0.0, -1.0, 1.0, 0.5,
|
|
||||||
0.5, 0.09754499999999999, -0.4903925, -0.0, 0.1951, -0.9808, 0.96875, 0.5,
|
|
||||||
-0.5, 0.0, -0.5, -0.0, -0.0, -1.0, 1.0, 1.0,
|
|
||||||
0.5, 0.09754499999999999, -0.4903925, -0.0, 0.1951, -0.9808, 0.96875, 0.5,
|
|
||||||
0.5, 0.1913415, -0.46194, -0.0, 0.3827, -0.9239, 0.9375, 0.5,
|
|
||||||
-0.5, 0.09754499999999999, -0.4903925, -0.0, 0.1951, -0.9808, 0.96875, 1.0,
|
|
||||||
0.5, 0.1913415, -0.46194, -0.0, 0.3827, -0.9239, 0.9375, 0.5,
|
|
||||||
0.5, 0.277785, -0.41573499999999997, -0.0, 0.5556, -0.8315, 0.90625, 0.5,
|
|
||||||
-0.5, 0.1913415, -0.46194, -0.0, 0.3827, -0.9239, 0.9375, 1.0,
|
|
||||||
0.5, 0.277785, -0.41573499999999997, -0.0, 0.5556, -0.8315, 0.90625, 0.5,
|
|
||||||
0.5, 0.3535535, -0.3535535000000001, -0.0, 0.7071, -0.7071, 0.875, 0.5,
|
|
||||||
-0.5, 0.277785, -0.41573499999999997, -0.0, 0.5556, -0.8315, 0.90625, 1.0,
|
|
||||||
0.5, 0.3535535, -0.3535535000000001, -0.0, 0.7071, -0.7071, 0.875, 0.5,
|
|
||||||
0.5, 0.415735, -0.27778499999999995, -0.0, 0.8315, -0.5556, 0.84375, 0.5,
|
|
||||||
-0.5, 0.3535535, -0.3535535000000001, -0.0, 0.7071, -0.7071, 0.875, 1.0,
|
|
||||||
0.5, 0.415735, -0.27778499999999995, -0.0, 0.8315, -0.5556, 0.84375, 0.5,
|
|
||||||
0.5, 0.46194, -0.19134150000000005, -0.0, 0.9239, -0.3827, 0.8125, 0.5,
|
|
||||||
-0.5, 0.415735, -0.27778499999999995, -0.0, 0.8315, -0.5556, 0.84375, 1.0,
|
|
||||||
0.5, 0.46194, -0.19134150000000005, -0.0, 0.9239, -0.3827, 0.8125, 0.5,
|
|
||||||
0.5, 0.4903925, -0.09754499999999999, -0.0, 0.9808, -0.1951, 0.78125, 0.5,
|
|
||||||
-0.5, 0.4619395, -0.19134150000000005, -0.0, 0.9239, -0.3827, 0.8125, 1.0,
|
|
||||||
0.5, 0.4903925, -0.09754499999999999, -0.0, 0.9808, -0.1951, 0.78125, 0.5,
|
|
||||||
0.5, 0.5, 0.0, -0.0, 1.0, -0.0, 0.75, 0.5,
|
|
||||||
-0.5, 0.4903925, -0.09754499999999999, -0.0, 0.9808, -0.1951, 0.78125, 1.0,
|
|
||||||
0.5, 0.5, 0.0, -0.0, 1.0, -0.0, 0.75, 0.5,
|
|
||||||
0.5, 0.4903925, 0.09754499999999999, -0.0, 0.9808, 0.1951, 0.71875, 0.5,
|
|
||||||
-0.5, 0.5, 0.0, -0.0, 1.0, -0.0, 0.75, 1.0,
|
|
||||||
0.5, 0.4903925, 0.09754499999999999, -0.0, 0.9808, 0.1951, 0.71875, 0.5,
|
|
||||||
0.5, 0.46194, 0.1913415, -0.0, 0.9239, 0.3827, 0.6875, 0.5,
|
|
||||||
-0.5, 0.4903925, 0.09754499999999999, -0.0, 0.9808, 0.1951, 0.71875, 1.0,
|
|
||||||
0.5, 0.46194, 0.1913415, -0.0, 0.9239, 0.3827, 0.6875, 0.5,
|
|
||||||
0.5, 0.415735, 0.277785, -0.0, 0.8315, 0.5556, 0.65625, 0.5,
|
|
||||||
-0.5, 0.4619395, 0.1913415, -0.0, 0.9239, 0.3827, 0.6875, 1.0,
|
|
||||||
0.5, 0.415735, 0.277785, -0.0, 0.8315, 0.5556, 0.65625, 0.5,
|
|
||||||
0.5, 0.3535535, 0.3535535, -0.0, 0.7071, 0.7071, 0.625, 0.5,
|
|
||||||
-0.5, 0.415735, 0.277785, -0.0, 0.8315, 0.5556, 0.65625, 1.0,
|
|
||||||
0.5, 0.3535535, 0.3535535, -0.0, 0.7071, 0.7071, 0.625, 0.5,
|
|
||||||
0.5, 0.277785, 0.415735, -0.0, 0.5556, 0.8315, 0.59375, 0.5,
|
|
||||||
-0.5, 0.3535535, 0.3535535, -0.0, 0.7071, 0.7071, 0.625, 1.0,
|
|
||||||
0.5, 0.277785, 0.415735, -0.0, 0.5556, 0.8315, 0.59375, 0.5,
|
|
||||||
0.5, 0.1913415, 0.46194, -0.0, 0.3827, 0.9239, 0.5625, 0.5,
|
|
||||||
-0.5, 0.277785, 0.415735, -0.0, 0.5556, 0.8315, 0.59375, 1.0,
|
|
||||||
0.5, 0.1913415, 0.46194, -0.0, 0.3827, 0.9239, 0.5625, 0.5,
|
|
||||||
0.5, 0.09754499999999999, 0.4903925, -0.0, 0.1951, 0.9808, 0.53125, 0.5,
|
|
||||||
-0.5, 0.1913415, 0.46194, -0.0, 0.3827, 0.9239, 0.5625, 1.0,
|
|
||||||
0.5, 0.09754499999999999, 0.4903925, -0.0, 0.1951, 0.9808, 0.53125, 0.5,
|
|
||||||
0.5, 0.0, 0.5, -0.0, -0.0, 1.0, 0.5, 0.5,
|
|
||||||
-0.5, 0.09754499999999999, 0.4903925, -0.0, 0.1951, 0.9808, 0.53125, 1.0,
|
|
||||||
0.5, 0.0, 0.5, -0.0, -0.0, 1.0, 0.5, 0.5,
|
|
||||||
0.5, -0.09754499999999999, 0.4903925, -0.0, -0.1951, 0.9808, 0.46875, 0.5,
|
|
||||||
-0.5, 0.0, 0.5, -0.0, -0.0, 1.0, 0.5, 1.0,
|
|
||||||
0.5, -0.09754499999999999, 0.4903925, -0.0, -0.1951, 0.9808, 0.46875, 0.5,
|
|
||||||
0.5, -0.19134150000000005, 0.46194, -0.0, -0.3827, 0.9239, 0.4375, 0.5,
|
|
||||||
-0.5, -0.09754499999999999, 0.4903925, -0.0, -0.1951, 0.9808, 0.46875, 1.0,
|
|
||||||
0.5, -0.19134150000000005, 0.46194, -0.0, -0.3827, 0.9239, 0.4375, 0.5,
|
|
||||||
0.5, -0.27778499999999995, 0.415735, -0.0, -0.5556, 0.8315, 0.40625, 0.5,
|
|
||||||
-0.5, -0.19134150000000005, 0.46194, -0.0, -0.3827, 0.9239, 0.4375, 1.0,
|
|
||||||
0.5, -0.27778499999999995, 0.415735, -0.0, -0.5556, 0.8315, 0.40625, 0.5,
|
|
||||||
0.5, -0.3535535000000001, 0.3535535, -0.0, -0.7071, 0.7071, 0.375, 0.5,
|
|
||||||
-0.5, -0.27778499999999995, 0.415735, -0.0, -0.5556, 0.8315, 0.40625, 1.0,
|
|
||||||
0.5, -0.3535535000000001, 0.3535535, -0.0, -0.7071, 0.7071, 0.375, 0.5,
|
|
||||||
0.5, -0.41573499999999997, 0.277785, -0.0, -0.8315, 0.5556, 0.34375, 0.5,
|
|
||||||
-0.5, -0.3535535000000001, 0.3535535, -0.0, -0.7071, 0.7071, 0.375, 1.0,
|
|
||||||
0.5, -0.41573499999999997, 0.277785, -0.0, -0.8315, 0.5556, 0.34375, 0.5,
|
|
||||||
0.5, -0.46193949999999995, 0.1913415, -0.0, -0.9239, 0.3827, 0.3125, 0.5,
|
|
||||||
-0.5, -0.41573499999999997, 0.277785, -0.0, -0.8315, 0.5556, 0.34375, 1.0,
|
|
||||||
0.5, -0.46193949999999995, 0.1913415, -0.0, -0.9239, 0.3827, 0.3125, 0.5,
|
|
||||||
0.5, -0.4903925, 0.09754499999999999, -0.0, -0.9808, 0.1951, 0.28125, 0.5,
|
|
||||||
-0.5, -0.46194, 0.1913415, -0.0, -0.9239, 0.3827, 0.3125, 1.0,
|
|
||||||
0.5, -0.4903925, 0.09754499999999999, -0.0, -0.9808, 0.1951, 0.28125, 0.5,
|
|
||||||
0.5, -0.5, 0.0, -0.0, -1.0, -0.0, 0.25, 0.5,
|
|
||||||
-0.5, -0.4903925, 0.09754499999999999, -0.0, -0.9808, 0.1951, 0.28125, 1.0,
|
|
||||||
0.5, -0.5, 0.0, -0.0, -1.0, -0.0, 0.25, 0.5,
|
|
||||||
0.5, -0.4903925, -0.09754499999999999, -0.0, -0.9808, -0.1951, 0.21875, 0.5,
|
|
||||||
-0.5, -0.5, 0.0, -0.0, -1.0, -0.0, 0.25, 1.0,
|
|
||||||
0.5, -0.4903925, -0.09754499999999999, -0.0, -0.9808, -0.1951, 0.21875, 0.5,
|
|
||||||
0.5, -0.46193949999999995, -0.19134150000000005, -0.0, -0.9239, -0.3827, 0.1875, 0.5,
|
|
||||||
-0.5, -0.4903925, -0.09754499999999999, -0.0, -0.9808, -0.1951, 0.21875, 1.0,
|
|
||||||
0.5, -0.46193949999999995, -0.19134150000000005, -0.0, -0.9239, -0.3827, 0.1875, 0.5,
|
|
||||||
0.5, -0.41573499999999997, -0.27778499999999995, -0.0, -0.8315, -0.5556, 0.15625, 0.5,
|
|
||||||
-0.5, -0.46194, -0.19134150000000005, -0.0, -0.9239, -0.3827, 0.1875, 1.0,
|
|
||||||
0.5, -0.41573499999999997, -0.27778499999999995, -0.0, -0.8315, -0.5556, 0.15625, 0.5,
|
|
||||||
0.5, -0.3535535000000001, -0.3535535000000001, -0.0, -0.7071, -0.7071, 0.125, 0.5,
|
|
||||||
-0.5, -0.41573499999999997, -0.27778499999999995, -0.0, -0.8315, -0.5556, 0.15625, 1.0,
|
|
||||||
0.5, -0.3535535000000001, -0.3535535000000001, -0.0, -0.7071, -0.7071, 0.125, 0.5,
|
|
||||||
0.5, -0.27778499999999995, -0.41573499999999997, -0.0, -0.5556, -0.8315, 0.09375, 0.5,
|
|
||||||
-0.5, -0.3535535000000001, -0.3535535000000001, -0.0, -0.7071, -0.7071, 0.125, 1.0,
|
|
||||||
0.5, -0.27778499999999995, -0.41573499999999997, -0.0, -0.5556, -0.8315, 0.09375, 0.5,
|
|
||||||
0.5, -0.19134150000000005, -0.46194, -0.0, -0.3827, -0.9239, 0.0625, 0.5,
|
|
||||||
-0.5, -0.27778499999999995, -0.41573499999999997, -0.0, -0.5556, -0.8315, 0.09375, 1.0,
|
|
||||||
-0.5, 0.1913415, -0.46194, -1.0, -0.0, -0.0, 0.341844, 0.471731,
|
|
||||||
-0.5, 0.4619395, 0.1913415, -1.0, -0.0, -0.0, 0.471731, 0.158156,
|
|
||||||
-0.5, -0.19134150000000005, 0.46194, -1.0, -0.0, -0.0, 0.158156, 0.028269,
|
|
||||||
0.5, -0.19134150000000005, -0.46194, -0.0, -0.3827, -0.9239, 0.0625, 0.5,
|
|
||||||
0.5, -0.09754499999999999, -0.4903925, -0.0, -0.1951, -0.9808, 0.03125, 0.5,
|
|
||||||
-0.5, -0.19134150000000005, -0.46194, -0.0, -0.3827, -0.9239, 0.0625, 1.0,
|
|
||||||
0.5, -0.09754499999999999, -0.4903925, -0.0, -0.1951, -0.9808, 0.03125, 0.5,
|
|
||||||
0.5, 0.0, -0.5, -0.0, -0.0, -1.0, 0.0, 0.5,
|
|
||||||
-0.5, -0.09754499999999999, -0.4903925, -0.0, -0.1951, -0.9808, 0.03125, 1.0,
|
|
||||||
0.5, -0.09754499999999999, -0.4903925, 1.0, -0.0, -0.0, 0.703178, 0.485388,
|
|
||||||
0.5, -0.4903925, 0.09754499999999999, 1.0, -0.0, -0.0, 0.514612, 0.203178,
|
|
||||||
0.5, 0.09754499999999999, 0.4903925, 1.0, -0.0, -0.0, 0.796822, 0.014612,
|
|
||||||
0.5, 0.09754499999999999, -0.4903925, -0.0, 0.1951, -0.9808, 0.96875, 0.5,
|
|
||||||
-0.5, 0.09754499999999999, -0.4903925, -0.0, 0.1951, -0.9808, 0.96875, 1.0,
|
|
||||||
-0.5, 0.0, -0.5, -0.0, -0.0, -1.0, 1.0, 1.0,
|
|
||||||
0.5, 0.1913415, -0.46194, -0.0, 0.3827, -0.9239, 0.9375, 0.5,
|
|
||||||
-0.5, 0.1913415, -0.46194, -0.0, 0.3827, -0.9239, 0.9375, 1.0,
|
|
||||||
-0.5, 0.09754499999999999, -0.4903925, -0.0, 0.1951, -0.9808, 0.96875, 1.0,
|
|
||||||
0.5, 0.277785, -0.41573499999999997, -0.0, 0.5556, -0.8315, 0.90625, 0.5,
|
|
||||||
-0.5, 0.277785, -0.41573499999999997, -0.0, 0.5556, -0.8315, 0.90625, 1.0,
|
|
||||||
-0.5, 0.1913415, -0.46194, -0.0, 0.3827, -0.9239, 0.9375, 1.0,
|
|
||||||
0.5, 0.3535535, -0.3535535000000001, -0.0, 0.7071, -0.7071, 0.875, 0.5,
|
|
||||||
-0.5, 0.3535535, -0.3535535000000001, -0.0, 0.7071, -0.7071, 0.875, 1.0,
|
|
||||||
-0.5, 0.277785, -0.41573499999999997, -0.0, 0.5556, -0.8315, 0.90625, 1.0,
|
|
||||||
0.5, 0.415735, -0.27778499999999995, -0.0, 0.8315, -0.5556, 0.84375, 0.5,
|
|
||||||
-0.5, 0.415735, -0.27778499999999995, -0.0, 0.8315, -0.5556, 0.84375, 1.0,
|
|
||||||
-0.5, 0.3535535, -0.3535535000000001, -0.0, 0.7071, -0.7071, 0.875, 1.0,
|
|
||||||
0.5, 0.46194, -0.19134150000000005, -0.0, 0.9239, -0.3827, 0.8125, 0.5,
|
|
||||||
-0.5, 0.4619395, -0.19134150000000005, -0.0, 0.9239, -0.3827, 0.8125, 1.0,
|
|
||||||
-0.5, 0.415735, -0.27778499999999995, -0.0, 0.8315, -0.5556, 0.84375, 1.0,
|
|
||||||
0.5, 0.4903925, -0.09754499999999999, -0.0, 0.9808, -0.1951, 0.78125, 0.5,
|
|
||||||
-0.5, 0.4903925, -0.09754499999999999, -0.0, 0.9808, -0.1951, 0.78125, 1.0,
|
|
||||||
-0.5, 0.4619395, -0.19134150000000005, -0.0, 0.9239, -0.3827, 0.8125, 1.0,
|
|
||||||
0.5, 0.5, 0.0, -0.0, 1.0, -0.0, 0.75, 0.5,
|
|
||||||
-0.5, 0.5, 0.0, -0.0, 1.0, -0.0, 0.75, 1.0,
|
|
||||||
-0.5, 0.4903925, -0.09754499999999999, -0.0, 0.9808, -0.1951, 0.78125, 1.0,
|
|
||||||
0.5, 0.4903925, 0.09754499999999999, -0.0, 0.9808, 0.1951, 0.71875, 0.5,
|
|
||||||
-0.5, 0.4903925, 0.09754499999999999, -0.0, 0.9808, 0.1951, 0.71875, 1.0,
|
|
||||||
-0.5, 0.5, 0.0, -0.0, 1.0, -0.0, 0.75, 1.0,
|
|
||||||
0.5, 0.46194, 0.1913415, -0.0, 0.9239, 0.3827, 0.6875, 0.5,
|
|
||||||
-0.5, 0.4619395, 0.1913415, -0.0, 0.9239, 0.3827, 0.6875, 1.0,
|
|
||||||
-0.5, 0.4903925, 0.09754499999999999, -0.0, 0.9808, 0.1951, 0.71875, 1.0,
|
|
||||||
0.5, 0.415735, 0.277785, -0.0, 0.8315, 0.5556, 0.65625, 0.5,
|
|
||||||
-0.5, 0.415735, 0.277785, -0.0, 0.8315, 0.5556, 0.65625, 1.0,
|
|
||||||
-0.5, 0.4619395, 0.1913415, -0.0, 0.9239, 0.3827, 0.6875, 1.0,
|
|
||||||
0.5, 0.3535535, 0.3535535, -0.0, 0.7071, 0.7071, 0.625, 0.5,
|
|
||||||
-0.5, 0.3535535, 0.3535535, -0.0, 0.7071, 0.7071, 0.625, 1.0,
|
|
||||||
-0.5, 0.415735, 0.277785, -0.0, 0.8315, 0.5556, 0.65625, 1.0,
|
|
||||||
0.5, 0.277785, 0.415735, -0.0, 0.5556, 0.8315, 0.59375, 0.5,
|
|
||||||
-0.5, 0.277785, 0.415735, -0.0, 0.5556, 0.8315, 0.59375, 1.0,
|
|
||||||
-0.5, 0.3535535, 0.3535535, -0.0, 0.7071, 0.7071, 0.625, 1.0,
|
|
||||||
0.5, 0.1913415, 0.46194, -0.0, 0.3827, 0.9239, 0.5625, 0.5,
|
|
||||||
-0.5, 0.1913415, 0.46194, -0.0, 0.3827, 0.9239, 0.5625, 1.0,
|
|
||||||
-0.5, 0.277785, 0.415735, -0.0, 0.5556, 0.8315, 0.59375, 1.0,
|
|
||||||
0.5, 0.09754499999999999, 0.4903925, -0.0, 0.1951, 0.9808, 0.53125, 0.5,
|
|
||||||
-0.5, 0.09754499999999999, 0.4903925, -0.0, 0.1951, 0.9808, 0.53125, 1.0,
|
|
||||||
-0.5, 0.1913415, 0.46194, -0.0, 0.3827, 0.9239, 0.5625, 1.0,
|
|
||||||
0.5, 0.0, 0.5, -0.0, -0.0, 1.0, 0.5, 0.5,
|
|
||||||
-0.5, 0.0, 0.5, -0.0, -0.0, 1.0, 0.5, 1.0,
|
|
||||||
-0.5, 0.09754499999999999, 0.4903925, -0.0, 0.1951, 0.9808, 0.53125, 1.0,
|
|
||||||
0.5, -0.09754499999999999, 0.4903925, -0.0, -0.1951, 0.9808, 0.46875, 0.5,
|
|
||||||
-0.5, -0.09754499999999999, 0.4903925, -0.0, -0.1951, 0.9808, 0.46875, 1.0,
|
|
||||||
-0.5, 0.0, 0.5, -0.0, -0.0, 1.0, 0.5, 1.0,
|
|
||||||
0.5, -0.19134150000000005, 0.46194, -0.0, -0.3827, 0.9239, 0.4375, 0.5,
|
|
||||||
-0.5, -0.19134150000000005, 0.46194, -0.0, -0.3827, 0.9239, 0.4375, 1.0,
|
|
||||||
-0.5, -0.09754499999999999, 0.4903925, -0.0, -0.1951, 0.9808, 0.46875, 1.0,
|
|
||||||
0.5, -0.27778499999999995, 0.415735, -0.0, -0.5556, 0.8315, 0.40625, 0.5,
|
|
||||||
-0.5, -0.27778499999999995, 0.415735, -0.0, -0.5556, 0.8315, 0.40625, 1.0,
|
|
||||||
-0.5, -0.19134150000000005, 0.46194, -0.0, -0.3827, 0.9239, 0.4375, 1.0,
|
|
||||||
0.5, -0.3535535000000001, 0.3535535, -0.0, -0.7071, 0.7071, 0.375, 0.5,
|
|
||||||
-0.5, -0.3535535000000001, 0.3535535, -0.0, -0.7071, 0.7071, 0.375, 1.0,
|
|
||||||
-0.5, -0.27778499999999995, 0.415735, -0.0, -0.5556, 0.8315, 0.40625, 1.0,
|
|
||||||
0.5, -0.41573499999999997, 0.277785, -0.0, -0.8315, 0.5556, 0.34375, 0.5,
|
|
||||||
-0.5, -0.41573499999999997, 0.277785, -0.0, -0.8315, 0.5556, 0.34375, 1.0,
|
|
||||||
-0.5, -0.3535535000000001, 0.3535535, -0.0, -0.7071, 0.7071, 0.375, 1.0,
|
|
||||||
0.5, -0.46193949999999995, 0.1913415, -0.0, -0.9239, 0.3827, 0.3125, 0.5,
|
|
||||||
-0.5, -0.46194, 0.1913415, -0.0, -0.9239, 0.3827, 0.3125, 1.0,
|
|
||||||
-0.5, -0.41573499999999997, 0.277785, -0.0, -0.8315, 0.5556, 0.34375, 1.0,
|
|
||||||
0.5, -0.4903925, 0.09754499999999999, -0.0, -0.9808, 0.1951, 0.28125, 0.5,
|
|
||||||
-0.5, -0.4903925, 0.09754499999999999, -0.0, -0.9808, 0.1951, 0.28125, 1.0,
|
|
||||||
-0.5, -0.46194, 0.1913415, -0.0, -0.9239, 0.3827, 0.3125, 1.0,
|
|
||||||
0.5, -0.5, 0.0, -0.0, -1.0, -0.0, 0.25, 0.5,
|
|
||||||
-0.5, -0.5, 0.0, -0.0, -1.0, -0.0, 0.25, 1.0,
|
|
||||||
-0.5, -0.4903925, 0.09754499999999999, -0.0, -0.9808, 0.1951, 0.28125, 1.0,
|
|
||||||
0.5, -0.4903925, -0.09754499999999999, -0.0, -0.9808, -0.1951, 0.21875, 0.5,
|
|
||||||
-0.5, -0.4903925, -0.09754499999999999, -0.0, -0.9808, -0.1951, 0.21875, 1.0,
|
|
||||||
-0.5, -0.5, 0.0, -0.0, -1.0, -0.0, 0.25, 1.0,
|
|
||||||
0.5, -0.46193949999999995, -0.19134150000000005, -0.0, -0.9239, -0.3827, 0.1875, 0.5,
|
|
||||||
-0.5, -0.46194, -0.19134150000000005, -0.0, -0.9239, -0.3827, 0.1875, 1.0,
|
|
||||||
-0.5, -0.4903925, -0.09754499999999999, -0.0, -0.9808, -0.1951, 0.21875, 1.0,
|
|
||||||
0.5, -0.41573499999999997, -0.27778499999999995, -0.0, -0.8315, -0.5556, 0.15625, 0.5,
|
|
||||||
-0.5, -0.41573499999999997, -0.27778499999999995, -0.0, -0.8315, -0.5556, 0.15625, 1.0,
|
|
||||||
-0.5, -0.46194, -0.19134150000000005, -0.0, -0.9239, -0.3827, 0.1875, 1.0,
|
|
||||||
0.5, -0.3535535000000001, -0.3535535000000001, -0.0, -0.7071, -0.7071, 0.125, 0.5,
|
|
||||||
-0.5, -0.3535535000000001, -0.3535535000000001, -0.0, -0.7071, -0.7071, 0.125, 1.0,
|
|
||||||
-0.5, -0.41573499999999997, -0.27778499999999995, -0.0, -0.8315, -0.5556, 0.15625, 1.0,
|
|
||||||
0.5, -0.27778499999999995, -0.41573499999999997, -0.0, -0.5556, -0.8315, 0.09375, 0.5,
|
|
||||||
-0.5, -0.27778499999999995, -0.41573499999999997, -0.0, -0.5556, -0.8315, 0.09375, 1.0,
|
|
||||||
-0.5, -0.3535535000000001, -0.3535535000000001, -0.0, -0.7071, -0.7071, 0.125, 1.0,
|
|
||||||
0.5, -0.19134150000000005, -0.46194, -0.0, -0.3827, -0.9239, 0.0625, 0.5,
|
|
||||||
-0.5, -0.19134150000000005, -0.46194, -0.0, -0.3827, -0.9239, 0.0625, 1.0,
|
|
||||||
-0.5, -0.27778499999999995, -0.41573499999999997, -0.0, -0.5556, -0.8315, 0.09375, 1.0,
|
|
||||||
-0.5, 0.0, -0.5, -1.0, -0.0, -0.0, 0.25, 0.49,
|
|
||||||
-0.5, 0.09754499999999999, -0.4903925, -1.0, -0.0, -0.0, 0.296822, 0.485388,
|
|
||||||
-0.5, 0.1913415, -0.46194, -1.0, -0.0, -0.0, 0.341844, 0.471731,
|
|
||||||
-0.5, 0.1913415, -0.46194, -1.0, -0.0, -0.0, 0.341844, 0.471731,
|
|
||||||
-0.5, -0.09754499999999999, -0.4903925, -1.0, -0.0, -0.0, 0.203178, 0.485388,
|
|
||||||
-0.5, 0.0, -0.5, -1.0, -0.0, -0.0, 0.25, 0.49,
|
|
||||||
-0.5, 0.1913415, -0.46194, -1.0, -0.0, -0.0, 0.341844, 0.471731,
|
|
||||||
-0.5, -0.19134150000000005, -0.46194, -1.0, -0.0, -0.0, 0.158156, 0.471731,
|
|
||||||
-0.5, -0.09754499999999999, -0.4903925, -1.0, -0.0, -0.0, 0.203178, 0.485388,
|
|
||||||
-0.5, -0.3535535000000001, -0.3535535000000001, -1.0, -0.0, -0.0, 0.080294, 0.419706,
|
|
||||||
-0.5, -0.27778499999999995, -0.41573499999999997, -1.0, -0.0, -0.0, 0.116663, 0.449553,
|
|
||||||
-0.5, -0.19134150000000005, -0.46194, -1.0, -0.0, -0.0, 0.158156, 0.471731,
|
|
||||||
-0.5, -0.46194, -0.19134150000000005, -1.0, -0.0, -0.0, 0.028269, 0.341844,
|
|
||||||
-0.5, -0.41573499999999997, -0.27778499999999995, -1.0, -0.0, -0.0, 0.050447, 0.383337,
|
|
||||||
-0.5, -0.3535535000000001, -0.3535535000000001, -1.0, -0.0, -0.0, 0.080294, 0.419706,
|
|
||||||
-0.5, -0.5, 0.0, -1.0, -0.0, -0.0, 0.01, 0.25,
|
|
||||||
-0.5, -0.4903925, -0.09754499999999999, -1.0, -0.0, -0.0, 0.014612, 0.296822,
|
|
||||||
-0.5, -0.46194, -0.19134150000000005, -1.0, -0.0, -0.0, 0.028269, 0.341844,
|
|
||||||
-0.5, -0.46194, -0.19134150000000005, -1.0, -0.0, -0.0, 0.028269, 0.341844,
|
|
||||||
-0.5, -0.4903925, 0.09754499999999999, -1.0, -0.0, -0.0, 0.014612, 0.203178,
|
|
||||||
-0.5, -0.5, 0.0, -1.0, -0.0, -0.0, 0.01, 0.25,
|
|
||||||
-0.5, -0.46194, -0.19134150000000005, -1.0, -0.0, -0.0, 0.028269, 0.341844,
|
|
||||||
-0.5, -0.46194, 0.1913415, -1.0, -0.0, -0.0, 0.028269, 0.158156,
|
|
||||||
-0.5, -0.4903925, 0.09754499999999999, -1.0, -0.0, -0.0, 0.014612, 0.203178,
|
|
||||||
-0.5, -0.3535535000000001, 0.3535535, -1.0, -0.0, -0.0, 0.080294, 0.080294,
|
|
||||||
-0.5, -0.41573499999999997, 0.277785, -1.0, -0.0, -0.0, 0.050447, 0.116663,
|
|
||||||
-0.5, -0.46194, 0.1913415, -1.0, -0.0, -0.0, 0.028269, 0.158156,
|
|
||||||
-0.5, -0.19134150000000005, 0.46194, -1.0, -0.0, -0.0, 0.158156, 0.028269,
|
|
||||||
-0.5, -0.27778499999999995, 0.415735, -1.0, -0.0, -0.0, 0.116663, 0.050447,
|
|
||||||
-0.5, -0.3535535000000001, 0.3535535, -1.0, -0.0, -0.0, 0.080294, 0.080294,
|
|
||||||
-0.5, 0.1913415, 0.46194, -1.0, -0.0, -0.0, 0.341844, 0.028269,
|
|
||||||
-0.5, -0.09754499999999999, 0.4903925, -1.0, -0.0, -0.0, 0.203178, 0.014612,
|
|
||||||
-0.5, -0.19134150000000005, 0.46194, -1.0, -0.0, -0.0, 0.158156, 0.028269,
|
|
||||||
-0.5, 0.1913415, 0.46194, -1.0, -0.0, -0.0, 0.341844, 0.028269,
|
|
||||||
-0.5, 0.0, 0.5, -1.0, -0.0, -0.0, 0.25, 0.01,
|
|
||||||
-0.5, -0.09754499999999999, 0.4903925, -1.0, -0.0, -0.0, 0.203178, 0.014612,
|
|
||||||
-0.5, 0.1913415, 0.46194, -1.0, -0.0, -0.0, 0.341844, 0.028269,
|
|
||||||
-0.5, 0.09754499999999999, 0.4903925, -1.0, -0.0, -0.0, 0.296822, 0.014612,
|
|
||||||
-0.5, 0.0, 0.5, -1.0, -0.0, -0.0, 0.25, 0.01,
|
|
||||||
-0.5, 0.3535535, 0.3535535, -1.0, -0.0, -0.0, 0.419706, 0.080294,
|
|
||||||
-0.5, 0.277785, 0.415735, -1.0, -0.0, -0.0, 0.383337, 0.050447,
|
|
||||||
-0.5, 0.1913415, 0.46194, -1.0, -0.0, -0.0, 0.341844, 0.028269,
|
|
||||||
-0.5, 0.4619395, 0.1913415, -1.0, -0.0, -0.0, 0.471731, 0.158156,
|
|
||||||
-0.5, 0.415735, 0.277785, -1.0, -0.0, -0.0, 0.449553, 0.116663,
|
|
||||||
-0.5, 0.3535535, 0.3535535, -1.0, -0.0, -0.0, 0.419706, 0.080294,
|
|
||||||
-0.5, 0.4619395, -0.19134150000000005, -1.0, -0.0, -0.0, 0.471731, 0.341844,
|
|
||||||
-0.5, 0.4903925, 0.09754499999999999, -1.0, -0.0, -0.0, 0.485388, 0.203178,
|
|
||||||
-0.5, 0.4619395, 0.1913415, -1.0, -0.0, -0.0, 0.471731, 0.158156,
|
|
||||||
-0.5, 0.4619395, -0.19134150000000005, -1.0, -0.0, -0.0, 0.471731, 0.341844,
|
|
||||||
-0.5, 0.5, 0.0, -1.0, -0.0, -0.0, 0.49, 0.25,
|
|
||||||
-0.5, 0.4903925, 0.09754499999999999, -1.0, -0.0, -0.0, 0.485388, 0.203178,
|
|
||||||
-0.5, 0.4619395, -0.19134150000000005, -1.0, -0.0, -0.0, 0.471731, 0.341844,
|
|
||||||
-0.5, 0.4903925, -0.09754499999999999, -1.0, -0.0, -0.0, 0.485388, 0.296822,
|
|
||||||
-0.5, 0.5, 0.0, -1.0, -0.0, -0.0, 0.49, 0.25,
|
|
||||||
-0.5, 0.3535535, -0.3535535000000001, -1.0, -0.0, -0.0, 0.419706, 0.419706,
|
|
||||||
-0.5, 0.415735, -0.27778499999999995, -1.0, -0.0, -0.0, 0.449553, 0.383337,
|
|
||||||
-0.5, 0.4619395, -0.19134150000000005, -1.0, -0.0, -0.0, 0.471731, 0.341844,
|
|
||||||
-0.5, 0.1913415, -0.46194, -1.0, -0.0, -0.0, 0.341844, 0.471731,
|
|
||||||
-0.5, 0.277785, -0.41573499999999997, -1.0, -0.0, -0.0, 0.383337, 0.449553,
|
|
||||||
-0.5, 0.3535535, -0.3535535000000001, -1.0, -0.0, -0.0, 0.419706, 0.419706,
|
|
||||||
-0.5, 0.1913415, -0.46194, -1.0, -0.0, -0.0, 0.341844, 0.471731,
|
|
||||||
-0.5, -0.3535535000000001, -0.3535535000000001, -1.0, -0.0, -0.0, 0.080294, 0.419706,
|
|
||||||
-0.5, -0.19134150000000005, -0.46194, -1.0, -0.0, -0.0, 0.158156, 0.471731,
|
|
||||||
-0.5, 0.1913415, -0.46194, -1.0, -0.0, -0.0, 0.341844, 0.471731,
|
|
||||||
-0.5, -0.46194, -0.19134150000000005, -1.0, -0.0, -0.0, 0.028269, 0.341844,
|
|
||||||
-0.5, -0.3535535000000001, -0.3535535000000001, -1.0, -0.0, -0.0, 0.080294, 0.419706,
|
|
||||||
-0.5, -0.46194, -0.19134150000000005, -1.0, -0.0, -0.0, 0.028269, 0.341844,
|
|
||||||
-0.5, -0.3535535000000001, 0.3535535, -1.0, -0.0, -0.0, 0.080294, 0.080294,
|
|
||||||
-0.5, -0.46194, 0.1913415, -1.0, -0.0, -0.0, 0.028269, 0.158156,
|
|
||||||
-0.5, -0.46194, -0.19134150000000005, -1.0, -0.0, -0.0, 0.028269, 0.341844,
|
|
||||||
-0.5, -0.19134150000000005, 0.46194, -1.0, -0.0, -0.0, 0.158156, 0.028269,
|
|
||||||
-0.5, -0.3535535000000001, 0.3535535, -1.0, -0.0, -0.0, 0.080294, 0.080294,
|
|
||||||
-0.5, -0.19134150000000005, 0.46194, -1.0, -0.0, -0.0, 0.158156, 0.028269,
|
|
||||||
-0.5, 0.3535535, 0.3535535, -1.0, -0.0, -0.0, 0.419706, 0.080294,
|
|
||||||
-0.5, 0.1913415, 0.46194, -1.0, -0.0, -0.0, 0.341844, 0.028269,
|
|
||||||
-0.5, -0.19134150000000005, 0.46194, -1.0, -0.0, -0.0, 0.158156, 0.028269,
|
|
||||||
-0.5, 0.4619395, 0.1913415, -1.0, -0.0, -0.0, 0.471731, 0.158156,
|
|
||||||
-0.5, 0.3535535, 0.3535535, -1.0, -0.0, -0.0, 0.419706, 0.080294,
|
|
||||||
-0.5, 0.4619395, 0.1913415, -1.0, -0.0, -0.0, 0.471731, 0.158156,
|
|
||||||
-0.5, 0.3535535, -0.3535535000000001, -1.0, -0.0, -0.0, 0.419706, 0.419706,
|
|
||||||
-0.5, 0.4619395, -0.19134150000000005, -1.0, -0.0, -0.0, 0.471731, 0.341844,
|
|
||||||
-0.5, 0.4619395, 0.1913415, -1.0, -0.0, -0.0, 0.471731, 0.158156,
|
|
||||||
-0.5, 0.1913415, -0.46194, -1.0, -0.0, -0.0, 0.341844, 0.471731,
|
|
||||||
-0.5, 0.3535535, -0.3535535000000001, -1.0, -0.0, -0.0, 0.419706, 0.419706,
|
|
||||||
-0.5, -0.19134150000000005, 0.46194, -1.0, -0.0, -0.0, 0.158156, 0.028269,
|
|
||||||
-0.5, -0.46194, -0.19134150000000005, -1.0, -0.0, -0.0, 0.028269, 0.341844,
|
|
||||||
-0.5, 0.1913415, -0.46194, -1.0, -0.0, -0.0, 0.341844, 0.471731,
|
|
||||||
0.5, -0.09754499999999999, -0.4903925, -0.0, -0.1951, -0.9808, 0.03125, 0.5,
|
|
||||||
-0.5, -0.09754499999999999, -0.4903925, -0.0, -0.1951, -0.9808, 0.03125, 1.0,
|
|
||||||
-0.5, -0.19134150000000005, -0.46194, -0.0, -0.3827, -0.9239, 0.0625, 1.0,
|
|
||||||
0.5, 0.0, -0.5, -0.0, -0.0, -1.0, 0.0, 0.5,
|
|
||||||
-0.5, 0.0, -0.5, -0.0, -0.0, -1.0, 0.0, 1.0,
|
|
||||||
-0.5, -0.09754499999999999, -0.4903925, -0.0, -0.1951, -0.9808, 0.03125, 1.0,
|
|
||||||
0.5, 0.09754499999999999, -0.4903925, 1.0, -0.0, -0.0, 0.796822, 0.485388,
|
|
||||||
0.5, 0.0, -0.5, 1.0, -0.0, -0.0, 0.75, 0.49,
|
|
||||||
0.5, -0.09754499999999999, -0.4903925, 1.0, -0.0, -0.0, 0.703178, 0.485388,
|
|
||||||
0.5, 0.277785, -0.41573499999999997, 1.0, -0.0, -0.0, 0.883337, 0.449553,
|
|
||||||
0.5, 0.1913415, -0.46194, 1.0, -0.0, -0.0, 0.841844, 0.471731,
|
|
||||||
0.5, 0.09754499999999999, -0.4903925, 1.0, -0.0, -0.0, 0.796822, 0.485388,
|
|
||||||
0.5, 0.415735, -0.27778499999999995, 1.0, -0.0, -0.0, 0.949553, 0.383337,
|
|
||||||
0.5, 0.3535535, -0.3535535000000001, 1.0, -0.0, -0.0, 0.919706, 0.419706,
|
|
||||||
0.5, 0.277785, -0.41573499999999997, 1.0, -0.0, -0.0, 0.883337, 0.449553,
|
|
||||||
0.5, 0.4903925, -0.09754499999999999, 1.0, -0.0, -0.0, 0.985388, 0.296822,
|
|
||||||
0.5, 0.46194, -0.19134150000000005, 1.0, -0.0, -0.0, 0.971731, 0.341844,
|
|
||||||
0.5, 0.415735, -0.27778499999999995, 1.0, -0.0, -0.0, 0.949553, 0.383337,
|
|
||||||
0.5, 0.4903925, 0.09754499999999999, 1.0, -0.0, -0.0, 0.985388, 0.203178,
|
|
||||||
0.5, 0.5, 0.0, 1.0, -0.0, -0.0, 0.99, 0.25,
|
|
||||||
0.5, 0.4903925, -0.09754499999999999, 1.0, -0.0, -0.0, 0.985388, 0.296822,
|
|
||||||
0.5, 0.415735, 0.277785, 1.0, -0.0, -0.0, 0.949553, 0.116663,
|
|
||||||
0.5, 0.46194, 0.1913415, 1.0, -0.0, -0.0, 0.971731, 0.158156,
|
|
||||||
0.5, 0.4903925, 0.09754499999999999, 1.0, -0.0, -0.0, 0.985388, 0.203178,
|
|
||||||
0.5, 0.277785, 0.415735, 1.0, -0.0, -0.0, 0.883337, 0.050447,
|
|
||||||
0.5, 0.3535535, 0.3535535, 1.0, -0.0, -0.0, 0.919706, 0.080294,
|
|
||||||
0.5, 0.415735, 0.277785, 1.0, -0.0, -0.0, 0.949553, 0.116663,
|
|
||||||
0.5, 0.09754499999999999, 0.4903925, 1.0, -0.0, -0.0, 0.796822, 0.014612,
|
|
||||||
0.5, 0.1913415, 0.46194, 1.0, -0.0, -0.0, 0.841844, 0.028269,
|
|
||||||
0.5, 0.277785, 0.415735, 1.0, -0.0, -0.0, 0.883337, 0.050447,
|
|
||||||
0.5, -0.09754499999999999, 0.4903925, 1.0, -0.0, -0.0, 0.703178, 0.014612,
|
|
||||||
0.5, 0.0, 0.5, 1.0, -0.0, -0.0, 0.75, 0.01,
|
|
||||||
0.5, 0.09754499999999999, 0.4903925, 1.0, -0.0, -0.0, 0.796822, 0.014612,
|
|
||||||
0.5, -0.27778499999999995, 0.415735, 1.0, -0.0, -0.0, 0.616663, 0.050447,
|
|
||||||
0.5, -0.19134150000000005, 0.46194, 1.0, -0.0, -0.0, 0.658156, 0.028269,
|
|
||||||
0.5, -0.09754499999999999, 0.4903925, 1.0, -0.0, -0.0, 0.703178, 0.014612,
|
|
||||||
0.5, -0.41573499999999997, 0.277785, 1.0, -0.0, -0.0, 0.550447, 0.116663,
|
|
||||||
0.5, -0.3535535000000001, 0.3535535, 1.0, -0.0, -0.0, 0.580294, 0.080294,
|
|
||||||
0.5, -0.27778499999999995, 0.415735, 1.0, -0.0, -0.0, 0.616663, 0.050447,
|
|
||||||
0.5, -0.4903925, 0.09754499999999999, 1.0, -0.0, -0.0, 0.514612, 0.203178,
|
|
||||||
0.5, -0.46193949999999995, 0.1913415, 1.0, -0.0, -0.0, 0.528269, 0.158156,
|
|
||||||
0.5, -0.41573499999999997, 0.277785, 1.0, -0.0, -0.0, 0.550447, 0.116663,
|
|
||||||
0.5, -0.4903925, -0.09754499999999999, 1.0, -0.0, -0.0, 0.514612, 0.296822,
|
|
||||||
0.5, -0.5, 0.0, 1.0, -0.0, -0.0, 0.51, 0.25,
|
|
||||||
0.5, -0.4903925, 0.09754499999999999, 1.0, -0.0, -0.0, 0.514612, 0.203178,
|
|
||||||
0.5, -0.41573499999999997, -0.27778499999999995, 1.0, -0.0, -0.0, 0.550447, 0.383337,
|
|
||||||
0.5, -0.46193949999999995, -0.19134150000000005, 1.0, -0.0, -0.0, 0.528269, 0.341844,
|
|
||||||
0.5, -0.4903925, -0.09754499999999999, 1.0, -0.0, -0.0, 0.514612, 0.296822,
|
|
||||||
0.5, -0.27778499999999995, -0.41573499999999997, 1.0, -0.0, -0.0, 0.616663, 0.449553,
|
|
||||||
0.5, -0.3535535000000001, -0.3535535000000001, 1.0, -0.0, -0.0, 0.580294, 0.419706,
|
|
||||||
0.5, -0.41573499999999997, -0.27778499999999995, 1.0, -0.0, -0.0, 0.550447, 0.383337,
|
|
||||||
0.5, -0.09754499999999999, -0.4903925, 1.0, -0.0, -0.0, 0.703178, 0.485388,
|
|
||||||
0.5, -0.19134150000000005, -0.46194, 1.0, -0.0, -0.0, 0.658156, 0.471731,
|
|
||||||
0.5, -0.27778499999999995, -0.41573499999999997, 1.0, -0.0, -0.0, 0.616663, 0.449553,
|
|
||||||
0.5, 0.4903925, -0.09754499999999999, 1.0, -0.0, -0.0, 0.985388, 0.296822,
|
|
||||||
0.5, 0.09754499999999999, -0.4903925, 1.0, -0.0, -0.0, 0.796822, 0.485388,
|
|
||||||
0.5, -0.09754499999999999, -0.4903925, 1.0, -0.0, -0.0, 0.703178, 0.485388,
|
|
||||||
0.5, 0.4903925, -0.09754499999999999, 1.0, -0.0, -0.0, 0.985388, 0.296822,
|
|
||||||
0.5, 0.277785, -0.41573499999999997, 1.0, -0.0, -0.0, 0.883337, 0.449553,
|
|
||||||
0.5, 0.09754499999999999, -0.4903925, 1.0, -0.0, -0.0, 0.796822, 0.485388,
|
|
||||||
0.5, 0.4903925, -0.09754499999999999, 1.0, -0.0, -0.0, 0.985388, 0.296822,
|
|
||||||
0.5, 0.415735, -0.27778499999999995, 1.0, -0.0, -0.0, 0.949553, 0.383337,
|
|
||||||
0.5, 0.277785, -0.41573499999999997, 1.0, -0.0, -0.0, 0.883337, 0.449553,
|
|
||||||
0.5, 0.09754499999999999, 0.4903925, 1.0, -0.0, -0.0, 0.796822, 0.014612,
|
|
||||||
0.5, 0.4903925, 0.09754499999999999, 1.0, -0.0, -0.0, 0.985388, 0.203178,
|
|
||||||
0.5, 0.4903925, -0.09754499999999999, 1.0, -0.0, -0.0, 0.985388, 0.296822,
|
|
||||||
0.5, 0.09754499999999999, 0.4903925, 1.0, -0.0, -0.0, 0.796822, 0.014612,
|
|
||||||
0.5, 0.415735, 0.277785, 1.0, -0.0, -0.0, 0.949553, 0.116663,
|
|
||||||
0.5, 0.4903925, 0.09754499999999999, 1.0, -0.0, -0.0, 0.985388, 0.203178,
|
|
||||||
0.5, 0.09754499999999999, 0.4903925, 1.0, -0.0, -0.0, 0.796822, 0.014612,
|
|
||||||
0.5, 0.277785, 0.415735, 1.0, -0.0, -0.0, 0.883337, 0.050447,
|
|
||||||
0.5, 0.415735, 0.277785, 1.0, -0.0, -0.0, 0.949553, 0.116663,
|
|
||||||
0.5, -0.4903925, 0.09754499999999999, 1.0, -0.0, -0.0, 0.514612, 0.203178,
|
|
||||||
0.5, -0.09754499999999999, 0.4903925, 1.0, -0.0, -0.0, 0.703178, 0.014612,
|
|
||||||
0.5, 0.09754499999999999, 0.4903925, 1.0, -0.0, -0.0, 0.796822, 0.014612,
|
|
||||||
0.5, -0.4903925, 0.09754499999999999, 1.0, -0.0, -0.0, 0.514612, 0.203178,
|
|
||||||
0.5, -0.27778499999999995, 0.415735, 1.0, -0.0, -0.0, 0.616663, 0.050447,
|
|
||||||
0.5, -0.09754499999999999, 0.4903925, 1.0, -0.0, -0.0, 0.703178, 0.014612,
|
|
||||||
0.5, -0.4903925, 0.09754499999999999, 1.0, -0.0, -0.0, 0.514612, 0.203178,
|
|
||||||
0.5, -0.41573499999999997, 0.277785, 1.0, -0.0, -0.0, 0.550447, 0.116663,
|
|
||||||
0.5, -0.27778499999999995, 0.415735, 1.0, -0.0, -0.0, 0.616663, 0.050447,
|
|
||||||
0.5, -0.09754499999999999, -0.4903925, 1.0, -0.0, -0.0, 0.703178, 0.485388,
|
|
||||||
0.5, -0.4903925, -0.09754499999999999, 1.0, -0.0, -0.0, 0.514612, 0.296822,
|
|
||||||
0.5, -0.4903925, 0.09754499999999999, 1.0, -0.0, -0.0, 0.514612, 0.203178,
|
|
||||||
0.5, -0.09754499999999999, -0.4903925, 1.0, -0.0, -0.0, 0.703178, 0.485388,
|
|
||||||
0.5, -0.41573499999999997, -0.27778499999999995, 1.0, -0.0, -0.0, 0.550447, 0.383337,
|
|
||||||
0.5, -0.4903925, -0.09754499999999999, 1.0, -0.0, -0.0, 0.514612, 0.296822,
|
|
||||||
0.5, -0.09754499999999999, -0.4903925, 1.0, -0.0, -0.0, 0.703178, 0.485388,
|
|
||||||
0.5, -0.27778499999999995, -0.41573499999999997, 1.0, -0.0, -0.0, 0.616663, 0.449553,
|
|
||||||
0.5, -0.41573499999999997, -0.27778499999999995, 1.0, -0.0, -0.0, 0.550447, 0.383337,
|
|
||||||
0.5, 0.09754499999999999, 0.4903925, 1.0, -0.0, -0.0, 0.796822, 0.014612,
|
|
||||||
0.5, 0.4903925, -0.09754499999999999, 1.0, -0.0, -0.0, 0.985388, 0.296822,
|
|
||||||
0.5, -0.09754499999999999, -0.4903925, 1.0, -0.0, -0.0, 0.703178, 0.485388,
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
Mesh* CUBE_MESH;
|
Mesh* CUBE_MESH;
|
||||||
Mesh* WEDGE_MESH;
|
Mesh* WEDGE_MESH;
|
||||||
Mesh* SPHERE_MESH;
|
Mesh* SPHERE_MESH;
|
||||||
Mesh* ARROW_MESH;
|
Mesh* ARROW_MESH;
|
||||||
Mesh* OUTLINE_MESH;
|
Mesh* OUTLINE_MESH;
|
||||||
Mesh* CYLINDER_CHEAP_MESH;
|
|
||||||
Mesh* CYLINDER_MESH;
|
Mesh* CYLINDER_MESH;
|
||||||
|
|
||||||
void initMeshes() {
|
void initMeshes() {
|
||||||
|
@ -3499,7 +3119,6 @@ void initMeshes() {
|
||||||
SPHERE_MESH = new Mesh(sizeof(SPHERE_VERTICES) / sizeof(float) / 8, SPHERE_VERTICES);
|
SPHERE_MESH = new Mesh(sizeof(SPHERE_VERTICES) / sizeof(float) / 8, SPHERE_VERTICES);
|
||||||
ARROW_MESH = new Mesh(sizeof(ARROW_VERTICES) / sizeof(float) / 8, ARROW_VERTICES);
|
ARROW_MESH = new Mesh(sizeof(ARROW_VERTICES) / sizeof(float) / 8, ARROW_VERTICES);
|
||||||
OUTLINE_MESH = new Mesh(sizeof(OUTLINE_VERTICES) / sizeof(float) / 8, OUTLINE_VERTICES);
|
OUTLINE_MESH = new Mesh(sizeof(OUTLINE_VERTICES) / sizeof(float) / 8, OUTLINE_VERTICES);
|
||||||
CYLINDER_CHEAP_MESH = new Mesh(sizeof(CYLINDER_CHEAP_VERTICES) / sizeof(float) / 8, CYLINDER_CHEAP_VERTICES);
|
|
||||||
CYLINDER_MESH = new Mesh(sizeof(CYLINDER_VERTICES) / sizeof(float) / 8, CYLINDER_VERTICES);
|
CYLINDER_MESH = new Mesh(sizeof(CYLINDER_VERTICES) / sizeof(float) / 8, CYLINDER_VERTICES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,5 @@ extern Mesh* SPHERE_MESH;
|
||||||
extern Mesh* ARROW_MESH;
|
extern Mesh* ARROW_MESH;
|
||||||
extern Mesh* OUTLINE_MESH;
|
extern Mesh* OUTLINE_MESH;
|
||||||
extern Mesh* CYLINDER_MESH;
|
extern Mesh* CYLINDER_MESH;
|
||||||
extern Mesh* CYLINDER_CHEAP_MESH;
|
|
||||||
|
|
||||||
void initMeshes();
|
void initMeshes();
|
|
@ -5,7 +5,6 @@
|
||||||
#include <glm/ext/matrix_clip_space.hpp>
|
#include <glm/ext/matrix_clip_space.hpp>
|
||||||
#include <glm/ext/matrix_float4x4.hpp>
|
#include <glm/ext/matrix_float4x4.hpp>
|
||||||
#include <glm/ext/matrix_transform.hpp>
|
#include <glm/ext/matrix_transform.hpp>
|
||||||
#include <glm/ext/scalar_constants.hpp>
|
|
||||||
#include <glm/ext/vector_float3.hpp>
|
#include <glm/ext/vector_float3.hpp>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtc/quaternion.hpp>
|
#include <glm/gtc/quaternion.hpp>
|
||||||
|
@ -138,7 +137,6 @@ static void renderPart(std::shared_ptr<BasePart> part) {
|
||||||
shader->set("normalMatrix", normalMatrix);
|
shader->set("normalMatrix", normalMatrix);
|
||||||
shader->set("texScale", size);
|
shader->set("texScale", size);
|
||||||
shader->set("transparency", part->transparency);
|
shader->set("transparency", part->transparency);
|
||||||
shader->set("reflectance", part->reflectance);
|
|
||||||
|
|
||||||
shader->set("surfaces[" + std::to_string(NormalId::Right) + "]", (int)part->rightSurface);
|
shader->set("surfaces[" + std::to_string(NormalId::Right) + "]", (int)part->rightSurface);
|
||||||
shader->set("surfaces[" + std::to_string(NormalId::Top) + "]", (int)part->topSurface);
|
shader->set("surfaces[" + std::to_string(NormalId::Top) + "]", (int)part->topSurface);
|
||||||
|
@ -158,10 +156,6 @@ static void renderPart(std::shared_ptr<BasePart> part) {
|
||||||
glFrontFace(GL_CW);
|
glFrontFace(GL_CW);
|
||||||
CUBE_MESH->bind();
|
CUBE_MESH->bind();
|
||||||
glDrawArrays(GL_TRIANGLES, 0, CUBE_MESH->vertexCount);
|
glDrawArrays(GL_TRIANGLES, 0, CUBE_MESH->vertexCount);
|
||||||
} else if (shape == PartType::Cylinder) {
|
|
||||||
glFrontFace(GL_CW);
|
|
||||||
CYLINDER_MESH->bind();
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, CYLINDER_MESH->vertexCount);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,15 +183,12 @@ void renderParts() {
|
||||||
shader->set("numPointLights", 0);
|
shader->set("numPointLights", 0);
|
||||||
studsTexture->activate(0);
|
studsTexture->activate(0);
|
||||||
shader->set("studs", 0);
|
shader->set("studs", 0);
|
||||||
skyboxTexture->activate(1);
|
|
||||||
shader->set("skybox", 1);
|
|
||||||
|
|
||||||
// Pre-calculate the normal matrix for the shader
|
// Pre-calculate the normal matrix for the shader
|
||||||
|
|
||||||
// Pass in the camera position
|
// Pass in the camera position
|
||||||
shader->set("viewPos", camera.cameraPos);
|
shader->set("viewPos", camera.cameraPos);
|
||||||
|
|
||||||
|
|
||||||
// Sort by nearest
|
// Sort by nearest
|
||||||
std::map<float, std::shared_ptr<BasePart>> sorted;
|
std::map<float, std::shared_ptr<BasePart>> sorted;
|
||||||
for (auto it = gWorkspace()->GetDescendantsStart(); it != gWorkspace()->GetDescendantsEnd(); it++) {
|
for (auto it = gWorkspace()->GetDescendantsStart(); it != gWorkspace()->GetDescendantsEnd(); it++) {
|
||||||
|
@ -264,8 +255,8 @@ void renderSurfaceExtras() {
|
||||||
model = glm::scale(model, glm::vec3(0.4,0.4,0.4));
|
model = glm::scale(model, glm::vec3(0.4,0.4,0.4));
|
||||||
ghostShader->set("model", model);
|
ghostShader->set("model", model);
|
||||||
|
|
||||||
CYLINDER_CHEAP_MESH->bind();
|
CYLINDER_MESH->bind();
|
||||||
glDrawArrays(GL_TRIANGLES, 0, CYLINDER_CHEAP_MESH->vertexCount);
|
glDrawArrays(GL_TRIANGLES, 0, CYLINDER_MESH->vertexCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ Skybox::Skybox(std::array<std::string, 6> faces, unsigned int format) {
|
||||||
|
|
||||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, format, width, height, 0, format,
|
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, format, width, height, 0, format,
|
||||||
GL_UNSIGNED_BYTE, data);
|
GL_UNSIGNED_BYTE, data);
|
||||||
glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
|
|
||||||
stbi_image_free(data);
|
stbi_image_free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +31,7 @@ Skybox::Skybox(std::array<std::string, 6> faces, unsigned int format) {
|
||||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||||
|
|
||||||
// Interpolation
|
// Interpolation
|
||||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,5 +41,5 @@ Skybox::~Skybox() {
|
||||||
|
|
||||||
void Skybox::activate(unsigned int textureIdx) {
|
void Skybox::activate(unsigned int textureIdx) {
|
||||||
glActiveTexture(GL_TEXTURE0 + textureIdx);
|
glActiveTexture(GL_TEXTURE0 + textureIdx);
|
||||||
glBindTexture(GL_TEXTURE_CUBE_MAP, this->ID);
|
glBindTexture(GL_TEXTURE_2D, this->ID);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "physics/world.h"
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QLocale>
|
#include <QLocale>
|
||||||
#include <QTranslator>
|
#include <QTranslator>
|
||||||
|
@ -19,7 +18,7 @@ ma_engine miniaudio;
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
Logger::init();
|
Logger::init();
|
||||||
physicsInit();
|
|
||||||
// Has to happen before Qt application initializes or we get an error in WASAPI initialization
|
// Has to happen before Qt application initializes or we get an error in WASAPI initialization
|
||||||
ma_result res = ma_engine_init(NULL, &miniaudio);
|
ma_result res = ma_engine_init(NULL, &miniaudio);
|
||||||
if (res != MA_SUCCESS) {
|
if (res != MA_SUCCESS) {
|
||||||
|
@ -42,7 +41,6 @@ int main(int argc, char *argv[])
|
||||||
int result = a.exec();
|
int result = a.exec();
|
||||||
|
|
||||||
ma_engine_uninit(&miniaudio);
|
ma_engine_uninit(&miniaudio);
|
||||||
physicsDeinit();
|
|
||||||
Logger::finish();
|
Logger::finish();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "objects/pvinstance.h"
|
#include "objects/pvinstance.h"
|
||||||
#include "objects/service/selection.h"
|
#include "objects/service/selection.h"
|
||||||
#include "partassembly.h"
|
#include "partassembly.h"
|
||||||
|
#include "physics/util.h"
|
||||||
#include "rendering/renderer.h"
|
#include "rendering/renderer.h"
|
||||||
#include "rendering/shader.h"
|
#include "rendering/shader.h"
|
||||||
#include "datatypes/variant.h"
|
#include "datatypes/variant.h"
|
||||||
|
@ -147,10 +148,10 @@ void MainGLWidget::handleObjectDrag(QMouseEvent* evt) {
|
||||||
|
|
||||||
if (!rayHit) return;
|
if (!rayHit) return;
|
||||||
|
|
||||||
CFrame targetFrame = rayHit->hitPart->cframe;
|
CFrame targetFrame = partFromBody(rayHit->body)->cframe;
|
||||||
Vector3 surfaceNormal = targetFrame.Inverse().Rotation() * rayHit->worldNormal;
|
Vector3 surfaceNormal = targetFrame.Inverse().Rotation() * rayHit->worldNormal;
|
||||||
Vector3 inverseSurfaceNormal = Vector3::ONE - surfaceNormal.Abs();
|
Vector3 inverseSurfaceNormal = Vector3::ONE - surfaceNormal.Abs();
|
||||||
glm::vec3 partSize = rayHit->hitPart->size;
|
glm::vec3 partSize = partFromBody(rayHit->body)->size;
|
||||||
Vector3 tFormedHitPos = targetFrame * ((targetFrame.Inverse() * initialHitPos) * inverseSurfaceNormal);
|
Vector3 tFormedHitPos = targetFrame * ((targetFrame.Inverse() * initialHitPos) * inverseSurfaceNormal);
|
||||||
Vector3 tFormedInitialPos = targetFrame * ((targetFrame.Inverse() * initialFrame.Position()) * inverseSurfaceNormal);
|
Vector3 tFormedInitialPos = targetFrame * ((targetFrame.Inverse() * initialFrame.Position()) * inverseSurfaceNormal);
|
||||||
Vector3 vec = rayHit->worldPoint + (tFormedInitialPos - tFormedHitPos);
|
Vector3 vec = rayHit->worldPoint + (tFormedInitialPos - tFormedHitPos);
|
||||||
|
@ -322,7 +323,7 @@ void MainGLWidget::handleRotationalTransform(QMouseEvent* evt) {
|
||||||
|
|
||||||
std::optional<HandleFace> MainGLWidget::raycastHandle(glm::vec3 pointDir) {
|
std::optional<HandleFace> MainGLWidget::raycastHandle(glm::vec3 pointDir) {
|
||||||
if (!editorToolHandles.active) return std::nullopt;
|
if (!editorToolHandles.active) return std::nullopt;
|
||||||
return ::raycastHandle(camera.cameraPos, glm::normalize(pointDir) * 50000.f);
|
return ::raycastHandle(rp3d::Ray(glmToRp(camera.cameraPos), glmToRp(glm::normalize(pointDir)) * 50000));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainGLWidget::handleCursorChange(QMouseEvent* evt) {
|
void MainGLWidget::handleCursorChange(QMouseEvent* evt) {
|
||||||
|
@ -337,7 +338,7 @@ void MainGLWidget::handleCursorChange(QMouseEvent* evt) {
|
||||||
};
|
};
|
||||||
|
|
||||||
std::optional<const RaycastResult> rayHit = gWorkspace()->CastRayNearest(camera.cameraPos, pointDir, 50000);
|
std::optional<const RaycastResult> rayHit = gWorkspace()->CastRayNearest(camera.cameraPos, pointDir, 50000);
|
||||||
if (rayHit && !rayHit->hitPart->locked) {
|
if (rayHit && !partFromBody(rayHit->body)->locked) {
|
||||||
setCursor(Qt::OpenHandCursor);
|
setCursor(Qt::OpenHandCursor);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -403,17 +404,17 @@ void MainGLWidget::mousePressEvent(QMouseEvent* evt) {
|
||||||
// raycast part
|
// raycast part
|
||||||
std::shared_ptr<Selection> selection = gDataModel->GetService<Selection>();
|
std::shared_ptr<Selection> selection = gDataModel->GetService<Selection>();
|
||||||
std::optional<const RaycastResult> rayHit = gWorkspace()->CastRayNearest(camera.cameraPos, pointDir, 50000);
|
std::optional<const RaycastResult> rayHit = gWorkspace()->CastRayNearest(camera.cameraPos, pointDir, 50000);
|
||||||
if (!rayHit || !rayHit->hitPart) { selection->Set({}); return; }
|
if (!rayHit || !partFromBody(rayHit->body)) { selection->Set({}); return; }
|
||||||
std::shared_ptr<BasePart> part = rayHit->hitPart;
|
std::shared_ptr<BasePart> part = partFromBody(rayHit->body);
|
||||||
if (part->locked) { selection->Set({}); return; }
|
if (part->locked) { selection->Set({}); return; }
|
||||||
|
|
||||||
std::shared_ptr<PVInstance> selObject = part;
|
std::shared_ptr<PVInstance> selObject = part;
|
||||||
|
|
||||||
// Traverse to the root model
|
// Traverse to the root model
|
||||||
if (~evt->modifiers() & Qt::AltModifier) {
|
if (~evt->modifiers() & Qt::AltModifier) {
|
||||||
nullable std::shared_ptr<Instance> nextParent = selObject->GetParent();
|
std::optional<std::shared_ptr<Instance>> nextParent = selObject->GetParent();
|
||||||
while (nextParent && nextParent->IsA("Model")) {
|
while (nextParent.value() && nextParent.value()->IsA("Model")) {
|
||||||
selObject = std::dynamic_pointer_cast<PVInstance>(nextParent); nextParent = selObject->GetParent();
|
selObject = std::dynamic_pointer_cast<PVInstance>(nextParent.value()); nextParent = selObject->GetParent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,6 @@
|
||||||
#include "undohistory.h"
|
#include "undohistory.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <QToolButton>
|
|
||||||
#include <QSettings>
|
|
||||||
#include <qclipboard.h>
|
#include <qclipboard.h>
|
||||||
#include <qevent.h>
|
#include <qevent.h>
|
||||||
#include <qglobal.h>
|
#include <qglobal.h>
|
||||||
|
@ -29,9 +27,11 @@
|
||||||
#include <qtextcursor.h>
|
#include <qtextcursor.h>
|
||||||
#include <qtextedit.h>
|
#include <qtextedit.h>
|
||||||
#include <miniaudio.h>
|
#include <miniaudio.h>
|
||||||
#include <qtoolbutton.h>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <fstream>
|
|
||||||
|
#ifdef _NDEBUG
|
||||||
|
#define NDEBUG
|
||||||
|
#endif
|
||||||
|
|
||||||
bool worldSpaceTransforms = false;
|
bool worldSpaceTransforms = false;
|
||||||
|
|
||||||
|
@ -67,8 +67,6 @@ MainWindow::MainWindow(QWidget *parent)
|
||||||
: QMainWindow(parent)
|
: QMainWindow(parent)
|
||||||
, ui(new Ui::MainWindow)
|
, ui(new Ui::MainWindow)
|
||||||
{
|
{
|
||||||
loadState();
|
|
||||||
|
|
||||||
gDataModel->Init();
|
gDataModel->Init();
|
||||||
|
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
@ -104,28 +102,6 @@ MainWindow::MainWindow(QWidget *parent)
|
||||||
|
|
||||||
connectActionHandlers();
|
connectActionHandlers();
|
||||||
|
|
||||||
// Add open recents menu
|
|
||||||
refreshRecentsMenu();
|
|
||||||
for (QObject* child : ui->fileTools->children()) {
|
|
||||||
if (auto toolButton = dynamic_cast<QToolButton*>(child)) {
|
|
||||||
if (toolButton->defaultAction() != ui->actionOpen) continue;
|
|
||||||
|
|
||||||
// https://stackoverflow.com/a/12283957/16255372
|
|
||||||
// https://stackoverflow.com/a/5365184/16255372
|
|
||||||
|
|
||||||
toolButton->setMenu(recentsMenu);
|
|
||||||
toolButton->setPopupMode(QToolButton::MenuButtonPopup);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add open recents dropdown to file menu
|
|
||||||
auto actions = ui->menuFile->actions();
|
|
||||||
for (int i = 0; i < actions.size(); i++) {
|
|
||||||
if (actions[i] != ui->actionOpen) continue;
|
|
||||||
|
|
||||||
ui->menuFile->insertMenu((i+1) < actions.size() ? actions[i+1] : nullptr, recentsMenu);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ui->explorerView->Init(ui);
|
// ui->explorerView->Init(ui);
|
||||||
placeDocument = new PlaceDocument(this);
|
placeDocument = new PlaceDocument(this);
|
||||||
placeDocument->setAttribute(Qt::WA_DeleteOnClose, true);
|
placeDocument->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||||
|
@ -146,22 +122,9 @@ MainWindow::MainWindow(QWidget *parent)
|
||||||
});
|
});
|
||||||
|
|
||||||
setUpCommandBar();
|
setUpCommandBar();
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
// https://stackoverflow.com/a/17631703/16255372
|
|
||||||
// Add shortcut for reloading most recent file
|
|
||||||
QAction* reloadMostRecent = new QAction();
|
|
||||||
reloadMostRecent->setShortcut(Qt::Key_R | Qt::CTRL);
|
|
||||||
connect(reloadMostRecent, &QAction::triggered, [this, reloadMostRecent]() {
|
|
||||||
recentsMenu->actions()[0]->trigger();
|
|
||||||
removeAction(reloadMostRecent);
|
|
||||||
});
|
|
||||||
addAction(reloadMostRecent);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::closeEvent(QCloseEvent* evt) {
|
void MainWindow::closeEvent(QCloseEvent* evt) {
|
||||||
saveState();
|
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
// Ask if the user wants to save their changes
|
// Ask if the user wants to save their changes
|
||||||
// https://stackoverflow.com/a/33890731
|
// https://stackoverflow.com/a/33890731
|
||||||
|
@ -184,64 +147,6 @@ void MainWindow::closeEvent(QCloseEvent* evt) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::refreshRecentsMenu() {
|
|
||||||
if (!recentsMenu) recentsMenu = new QMenu();
|
|
||||||
|
|
||||||
recentsMenu->setTitle("Recent files...");
|
|
||||||
|
|
||||||
recentsMenu->clear(); // Actions not shown in any other menu are automatically deleted
|
|
||||||
for (QString item : recentFiles) {
|
|
||||||
QAction* itemAction = new QAction();
|
|
||||||
itemAction->setText(item.split('/').last());
|
|
||||||
recentsMenu->addAction(itemAction);
|
|
||||||
|
|
||||||
connect(itemAction, &QAction::triggered, [item, this]{
|
|
||||||
if (!QFile::exists(item)) {
|
|
||||||
QMessageBox::warning(this, "File not found", "The file '" + item + "' could not longer be found at that location.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<DataModel> newModel = DataModel::LoadFromFile(item.toStdString());
|
|
||||||
editModeDataModel = newModel;
|
|
||||||
gDataModel = newModel;
|
|
||||||
newModel->Init();
|
|
||||||
ui->explorerView->updateRoot(newModel);
|
|
||||||
|
|
||||||
// Reset running state
|
|
||||||
placeDocument->setRunState(RUN_STOPPED);
|
|
||||||
undoManager.Reset();
|
|
||||||
updateToolbars();
|
|
||||||
pushRecentFile(item);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (recentsMenu->isEmpty()) {
|
|
||||||
QAction* emptyAction = new QAction("No recents");
|
|
||||||
emptyAction->setEnabled(false);
|
|
||||||
recentsMenu->addAction(emptyAction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::loadState() {
|
|
||||||
QSettings settings("openblocks");
|
|
||||||
recentFiles = settings.value("recentFiles").toStringList();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::saveState() {
|
|
||||||
QSettings settings("openblocks");
|
|
||||||
settings.setValue("recentFiles", recentFiles);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::pushRecentFile(QString file) {
|
|
||||||
// https://www.walletfox.com/course/qtopenrecentfiles.php
|
|
||||||
recentFiles.removeAll(file);
|
|
||||||
recentFiles.prepend(file);
|
|
||||||
while (recentFiles.size() > 10) recentFiles.removeLast();
|
|
||||||
|
|
||||||
refreshRecentsMenu();
|
|
||||||
saveState();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::setUpCommandBar() {
|
void MainWindow::setUpCommandBar() {
|
||||||
CommandEdit* commandEdit;
|
CommandEdit* commandEdit;
|
||||||
QToolBar* commandBar = ui->commandBar;
|
QToolBar* commandBar = ui->commandBar;
|
||||||
|
@ -375,7 +280,6 @@ void MainWindow::connectActionHandlers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
editModeDataModel->SaveToFile(path);
|
editModeDataModel->SaveToFile(path);
|
||||||
if (path) pushRecentFile(QString::fromStdString(path.value()));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(ui->actionSaveAs, &QAction::triggered, this, [&]() {
|
connect(ui->actionSaveAs, &QAction::triggered, this, [&]() {
|
||||||
|
@ -383,7 +287,6 @@ void MainWindow::connectActionHandlers() {
|
||||||
if (!path || path == "") return;
|
if (!path || path == "") return;
|
||||||
|
|
||||||
editModeDataModel->SaveToFile(path);
|
editModeDataModel->SaveToFile(path);
|
||||||
if (path) pushRecentFile(QString::fromStdString(path.value()));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(ui->actionOpen, &QAction::triggered, this, [&]() {
|
connect(ui->actionOpen, &QAction::triggered, this, [&]() {
|
||||||
|
@ -404,7 +307,6 @@ void MainWindow::connectActionHandlers() {
|
||||||
placeDocument->setRunState(RUN_STOPPED);
|
placeDocument->setRunState(RUN_STOPPED);
|
||||||
undoManager.Reset();
|
undoManager.Reset();
|
||||||
updateToolbars();
|
updateToolbars();
|
||||||
if (path) pushRecentFile(QString::fromStdString(path.value()));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(ui->actionDelete, &QAction::triggered, this, [&]() {
|
connect(ui->actionDelete, &QAction::triggered, this, [&]() {
|
||||||
|
@ -412,8 +314,8 @@ void MainWindow::connectActionHandlers() {
|
||||||
std::shared_ptr<Selection> selection = gDataModel->GetService<Selection>();
|
std::shared_ptr<Selection> selection = gDataModel->GetService<Selection>();
|
||||||
for (std::weak_ptr<Instance> inst : selection->Get()) {
|
for (std::weak_ptr<Instance> inst : selection->Get()) {
|
||||||
if (inst.expired()) continue;
|
if (inst.expired()) continue;
|
||||||
historyState.push_back(UndoStateInstanceRemoved { inst.lock(), inst.lock()->GetParent() });
|
historyState.push_back(UndoStateInstanceRemoved { inst.lock(), inst.lock()->GetParent().value() });
|
||||||
inst.lock()->SetParent(nullptr);
|
inst.lock()->SetParent(std::nullopt);
|
||||||
}
|
}
|
||||||
selection->Set({});
|
selection->Set({});
|
||||||
historyState.push_back(UndoStateSelectionChanged {selection->Get(), {}});
|
historyState.push_back(UndoStateSelectionChanged {selection->Get(), {}});
|
||||||
|
@ -442,9 +344,9 @@ void MainWindow::connectActionHandlers() {
|
||||||
std::shared_ptr<Selection> selection = gDataModel->GetService<Selection>();
|
std::shared_ptr<Selection> selection = gDataModel->GetService<Selection>();
|
||||||
for (std::weak_ptr<Instance> inst : selection->Get()) {
|
for (std::weak_ptr<Instance> inst : selection->Get()) {
|
||||||
if (inst.expired()) continue;
|
if (inst.expired()) continue;
|
||||||
historyState.push_back(UndoStateInstanceRemoved { inst.lock(), inst.lock()->GetParent() });
|
historyState.push_back(UndoStateInstanceRemoved { inst.lock(), inst.lock()->GetParent().value() });
|
||||||
inst.lock()->Serialize(rootDoc);
|
inst.lock()->Serialize(rootDoc);
|
||||||
inst.lock()->SetParent(nullptr);
|
inst.lock()->SetParent(std::nullopt);
|
||||||
}
|
}
|
||||||
selection->Set({});
|
selection->Set({});
|
||||||
historyState.push_back(UndoStateSelectionChanged {selection->Get(), {}});
|
historyState.push_back(UndoStateSelectionChanged {selection->Get(), {}});
|
||||||
|
@ -511,8 +413,8 @@ void MainWindow::connectActionHandlers() {
|
||||||
bool done = false;
|
bool done = false;
|
||||||
std::shared_ptr<Selection> selection = gDataModel->GetService<Selection>();
|
std::shared_ptr<Selection> selection = gDataModel->GetService<Selection>();
|
||||||
for (auto object : selection->Get()) {
|
for (auto object : selection->Get()) {
|
||||||
if (!firstParent && object->GetParent() != nullptr) firstParent = object->GetParent();
|
if (firstParent == nullptr && object->GetParent().has_value()) firstParent = object->GetParent().value();
|
||||||
historyState.push_back(UndoStateInstanceReparented { object, object->GetParent(), model });
|
historyState.push_back(UndoStateInstanceReparented { object, object->GetParent().value(), model });
|
||||||
object->SetParent(model);
|
object->SetParent(model);
|
||||||
done = true;
|
done = true;
|
||||||
}
|
}
|
||||||
|
@ -544,13 +446,13 @@ void MainWindow::connectActionHandlers() {
|
||||||
done = true;
|
done = true;
|
||||||
|
|
||||||
for (auto object : model->GetChildren()) {
|
for (auto object : model->GetChildren()) {
|
||||||
historyState.push_back(UndoStateInstanceReparented { object, object->GetParent(), model->GetParent() });
|
historyState.push_back(UndoStateInstanceReparented { object, object->GetParent().value(), model->GetParent().value() });
|
||||||
object->SetParent(model->GetParent());
|
object->SetParent(model->GetParent());
|
||||||
newSelection.push_back(object);
|
newSelection.push_back(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
historyState.push_back(UndoStateInstanceRemoved { model, model->GetParent() });
|
historyState.push_back(UndoStateInstanceRemoved { model, model->GetParent().value() });
|
||||||
model->SetParent(nullptr);
|
model->SetParent(std::nullopt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!done)
|
if (!done)
|
||||||
|
|
|
@ -65,17 +65,9 @@ public:
|
||||||
|
|
||||||
Ui::MainWindow *ui;
|
Ui::MainWindow *ui;
|
||||||
|
|
||||||
QMenu* recentsMenu = nullptr;
|
|
||||||
QStringList recentFiles;
|
|
||||||
void refreshRecentsMenu();
|
|
||||||
void pushRecentFile(QString);
|
|
||||||
|
|
||||||
void loadState();
|
|
||||||
void saveState();
|
|
||||||
|
|
||||||
friend PlaceDocument;
|
friend PlaceDocument;
|
||||||
private:
|
private:
|
||||||
PlaceDocument* placeDocument = nullptr;
|
PlaceDocument* placeDocument;
|
||||||
|
|
||||||
void setUpCommandBar();
|
void setUpCommandBar();
|
||||||
void connectActionHandlers();
|
void connectActionHandlers();
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>1100</width>
|
<width>1050</width>
|
||||||
<height>750</height>
|
<height>750</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
|
|
@ -18,24 +18,24 @@ ExplorerModel::ExplorerModel(std::shared_ptr<Instance> dataRoot, QWidget *parent
|
||||||
: QAbstractItemModel(parent)
|
: QAbstractItemModel(parent)
|
||||||
, rootItem(dataRoot) {
|
, rootItem(dataRoot) {
|
||||||
// TODO: Don't use lambdas and handlers like that
|
// TODO: Don't use lambdas and handlers like that
|
||||||
hierarchyPreUpdateHandler = [&](std::shared_ptr<Instance> object, nullable std::shared_ptr<Instance> oldParent, nullable std::shared_ptr<Instance> newParent) {
|
hierarchyPreUpdateHandler = [&](std::shared_ptr<Instance> object, std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent) {
|
||||||
if (oldParent) {
|
if (oldParent.has_value()) {
|
||||||
auto children = oldParent->GetChildren();
|
auto children = oldParent.value()->GetChildren();
|
||||||
size_t idx = std::find(children.begin(), children.end(), object) - children.begin();
|
size_t idx = std::find(children.begin(), children.end(), object) - children.begin();
|
||||||
beginRemoveRows(toIndex(oldParent), idx, idx);
|
beginRemoveRows(toIndex(oldParent.value()), idx, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newParent) {
|
if (newParent.has_value()) {
|
||||||
size_t size = newParent->GetChildren().size();
|
size_t size = newParent.value()->GetChildren().size();
|
||||||
beginInsertRows(toIndex(newParent), size, size);
|
beginInsertRows(toIndex(newParent.value()), size, size);
|
||||||
} else {
|
} else {
|
||||||
// TODO:
|
// TODO:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
hierarchyPostUpdateHandler = [&](std::shared_ptr<Instance> object, nullable std::shared_ptr<Instance> oldParent, nullable std::shared_ptr<Instance> newParent) {
|
hierarchyPostUpdateHandler = [&](std::shared_ptr<Instance> object, std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent) {
|
||||||
if (newParent) endInsertRows();
|
if (newParent.has_value()) endInsertRows();
|
||||||
if (oldParent) endRemoveRows();
|
if (oldParent.has_value()) endRemoveRows();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,22 +49,16 @@ QModelIndex ExplorerModel::index(int row, int column, const QModelIndex &parent)
|
||||||
? static_cast<Instance*>(parent.internalPointer())
|
? static_cast<Instance*>(parent.internalPointer())
|
||||||
: rootItem.get();
|
: rootItem.get();
|
||||||
|
|
||||||
#ifdef NDEBUG
|
|
||||||
if (parentItem->GetChildren().size() >= (size_t)row && !(parentItem->GetChildren()[row]->GetClass()->flags & INSTANCE_HIDDEN))
|
if (parentItem->GetChildren().size() >= (size_t)row && !(parentItem->GetChildren()[row]->GetClass()->flags & INSTANCE_HIDDEN))
|
||||||
return createIndex(row, column, parentItem->GetChildren()[row].get());
|
return createIndex(row, column, parentItem->GetChildren()[row].get());
|
||||||
#else
|
|
||||||
// Don't hide in debug builds
|
|
||||||
if (parentItem->GetChildren().size() >= (size_t)row)
|
|
||||||
return createIndex(row, column, parentItem->GetChildren()[row].get());
|
|
||||||
#endif
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex ExplorerModel::toIndex(std::shared_ptr<Instance> item) {
|
QModelIndex ExplorerModel::toIndex(std::shared_ptr<Instance> item) {
|
||||||
if (item == rootItem || !item->GetParent())
|
if (item == rootItem || !item->GetParent().has_value())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
std::shared_ptr<Instance> parentItem = item->GetParent();
|
std::shared_ptr<Instance> parentItem = item->GetParent().value();
|
||||||
// Check above ensures this item is not root, so value() must be valid
|
// Check above ensures this item is not root, so value() must be valid
|
||||||
for (size_t i = 0; i < parentItem->GetChildren().size(); i++)
|
for (size_t i = 0; i < parentItem->GetChildren().size(); i++)
|
||||||
if (parentItem->GetChildren()[i] == item)
|
if (parentItem->GetChildren()[i] == item)
|
||||||
|
@ -82,13 +76,13 @@ QModelIndex ExplorerModel::parent(const QModelIndex &index) const {
|
||||||
|
|
||||||
Instance* childItem = static_cast<Instance*>(index.internalPointer());
|
Instance* childItem = static_cast<Instance*>(index.internalPointer());
|
||||||
// NORISK: The parent must exist if the child was obtained from it during this frame
|
// NORISK: The parent must exist if the child was obtained from it during this frame
|
||||||
std::shared_ptr<Instance> parentItem = childItem->GetParent();
|
std::shared_ptr<Instance> parentItem = childItem->GetParent().value();
|
||||||
|
|
||||||
if (parentItem == rootItem)
|
if (parentItem == rootItem)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
// Check above ensures this item is not root, so value() must be valid
|
// Check above ensures this item is not root, so value() must be valid
|
||||||
std::shared_ptr<Instance> parentParent = parentItem->GetParent();
|
std::shared_ptr<Instance> parentParent = parentItem->GetParent().value();
|
||||||
for (size_t i = 0; i < parentParent->GetChildren().size(); i++)
|
for (size_t i = 0; i < parentParent->GetChildren().size(); i++)
|
||||||
if (parentParent->GetChildren()[i] == parentItem)
|
if (parentParent->GetChildren()[i] == parentItem)
|
||||||
return createIndex(i, 0, parentItem.get());
|
return createIndex(i, 0, parentItem.get());
|
||||||
|
@ -103,15 +97,7 @@ int ExplorerModel::rowCount(const QModelIndex &parent) const {
|
||||||
? static_cast<Instance*>(parent.internalPointer())
|
? static_cast<Instance*>(parent.internalPointer())
|
||||||
: rootItem.get();
|
: rootItem.get();
|
||||||
|
|
||||||
#ifdef NDEBUG
|
|
||||||
// Trim trailing hidden items as they make the branches look weird
|
|
||||||
int count = parentItem->GetChildren().size();
|
|
||||||
while (count > 0 && parentItem->GetChildren()[count-1]->GetClass()->flags & INSTANCE_HIDDEN) count--;
|
|
||||||
return count;
|
|
||||||
#else
|
|
||||||
// Don't hide in debug builds
|
|
||||||
return parentItem->GetChildren().size();
|
return parentItem->GetChildren().size();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ExplorerModel::columnCount(const QModelIndex &parent) const {
|
int ExplorerModel::columnCount(const QModelIndex &parent) const {
|
||||||
|
@ -237,7 +223,7 @@ bool ExplorerModel::dropMimeData(const QMimeData *data, Qt::DropAction action, i
|
||||||
UndoState historyState;
|
UndoState historyState;
|
||||||
std::shared_ptr<Instance> parentInst = fromIndex(parent);
|
std::shared_ptr<Instance> parentInst = fromIndex(parent);
|
||||||
for (std::shared_ptr<Instance> instance : slot->instances) {
|
for (std::shared_ptr<Instance> instance : slot->instances) {
|
||||||
historyState.push_back(UndoStateInstanceReparented { instance, instance->GetParent(), parentInst });
|
historyState.push_back(UndoStateInstanceReparented { instance, instance->GetParent().value_or(nullptr), parentInst });
|
||||||
instance->SetParent(parentInst);
|
instance->SetParent(parentInst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -333,11 +333,11 @@ void PropertiesView::drawBranches(QPainter *painter, const QRect &rect, const QM
|
||||||
QTreeWidget::drawBranches(painter, rect, index);
|
QTreeWidget::drawBranches(painter, rect, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PropertiesView::setSelected(nullable std::shared_ptr<Instance> instance) {
|
void PropertiesView::setSelected(std::optional<std::shared_ptr<Instance>> instance) {
|
||||||
clear();
|
clear();
|
||||||
currentInstance = {};
|
currentInstance = {};
|
||||||
if (!instance) return;
|
if (!instance) return;
|
||||||
std::shared_ptr<Instance> inst = instance;
|
std::shared_ptr<Instance> inst = instance.value();
|
||||||
currentInstance = inst;
|
currentInstance = inst;
|
||||||
|
|
||||||
std::map<PropertyCategory, QTreeWidgetItem*> propertyCategories;
|
std::map<PropertyCategory, QTreeWidgetItem*> propertyCategories;
|
||||||
|
|
|
@ -31,5 +31,5 @@ public:
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
void setSelected(nullable std::shared_ptr<Instance> instance);
|
void setSelected(std::optional<std::shared_ptr<Instance>> instance);
|
||||||
};
|
};
|
|
@ -23,6 +23,36 @@
|
||||||
#include "objects/service/selection.h"
|
#include "objects/service/selection.h"
|
||||||
#include "timeutil.h"
|
#include "timeutil.h"
|
||||||
|
|
||||||
|
class PlaceDocumentPhysicsWorker {
|
||||||
|
public:
|
||||||
|
std::mutex sync;
|
||||||
|
std::thread thread;
|
||||||
|
std::condition_variable runningCond;
|
||||||
|
bool running = false;
|
||||||
|
bool quit = false;
|
||||||
|
|
||||||
|
PlaceDocumentPhysicsWorker() : thread(&PlaceDocumentPhysicsWorker::doWork, this) {}
|
||||||
|
private:
|
||||||
|
tu_time_t lastTime = tu_clock_micros();
|
||||||
|
void doWork() {
|
||||||
|
do {
|
||||||
|
tu_time_t deltaTime = tu_clock_micros() - lastTime;
|
||||||
|
lastTime = tu_clock_micros();
|
||||||
|
|
||||||
|
// First frame is always empty
|
||||||
|
if (deltaTime > 100) {
|
||||||
|
gWorkspace()->PhysicsStep(float(deltaTime)/1'000'000);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::microseconds(16'667 - deltaTime));
|
||||||
|
|
||||||
|
std::unique_lock lock(sync);
|
||||||
|
runningCond.wait(lock, [&]{ return running || quit; });
|
||||||
|
lock.unlock();
|
||||||
|
} while (!quit);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
PlaceDocument::PlaceDocument(QWidget* parent):
|
PlaceDocument::PlaceDocument(QWidget* parent):
|
||||||
QMdiSubWindow(parent) {
|
QMdiSubWindow(parent) {
|
||||||
placeWidget = new MainGLWidget;
|
placeWidget = new MainGLWidget;
|
||||||
|
@ -32,15 +62,29 @@ PlaceDocument::PlaceDocument(QWidget* parent):
|
||||||
|
|
||||||
_runState = RUN_STOPPED;
|
_runState = RUN_STOPPED;
|
||||||
updateSelectionListeners(gDataModel->GetService<Selection>());
|
updateSelectionListeners(gDataModel->GetService<Selection>());
|
||||||
|
|
||||||
|
worker = new PlaceDocumentPhysicsWorker();
|
||||||
}
|
}
|
||||||
|
|
||||||
PlaceDocument::~PlaceDocument() {
|
PlaceDocument::~PlaceDocument() {
|
||||||
|
worker->quit = true;
|
||||||
|
worker->runningCond.notify_all();
|
||||||
|
worker->thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlaceDocument::updatePhysicsWorker() {
|
||||||
|
{
|
||||||
|
std::lock_guard lock(worker->sync);
|
||||||
|
worker->running = _runState == RUN_RUNNING;
|
||||||
|
}
|
||||||
|
worker->runningCond.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlaceDocument::setRunState(RunState newState) {
|
void PlaceDocument::setRunState(RunState newState) {
|
||||||
if (newState == RUN_RUNNING && _runState != RUN_RUNNING) {
|
if (newState == RUN_RUNNING && _runState != RUN_RUNNING) {
|
||||||
if (_runState == RUN_PAUSED) {
|
if (_runState == RUN_PAUSED) {
|
||||||
_runState = RUN_RUNNING;
|
_runState = RUN_RUNNING;
|
||||||
|
updatePhysicsWorker();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,13 +99,12 @@ void PlaceDocument::setRunState(RunState newState) {
|
||||||
} else if (newState == RUN_STOPPED) {
|
} else if (newState == RUN_STOPPED) {
|
||||||
_runState = RUN_STOPPED;
|
_runState = RUN_STOPPED;
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
printf("DataModel stopped. Remaning use counts (should be 1): %ld\n", gDataModel.use_count());
|
|
||||||
#endif
|
|
||||||
// TODO: GC: Check to make sure gDataModel gets properly garbage collected prior to this
|
// TODO: GC: Check to make sure gDataModel gets properly garbage collected prior to this
|
||||||
gDataModel = editModeDataModel;
|
gDataModel = editModeDataModel;
|
||||||
updateSelectionListeners(gDataModel->GetService<Selection>());
|
updateSelectionListeners(gDataModel->GetService<Selection>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updatePhysicsWorker();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlaceDocument::updateSelectionListeners(std::shared_ptr<Selection> selection) {
|
void PlaceDocument::updateSelectionListeners(std::shared_ptr<Selection> selection) {
|
||||||
|
@ -73,7 +116,7 @@ void PlaceDocument::updateSelectionListeners(std::shared_ptr<Selection> selectio
|
||||||
selectionConnection = selection->SelectionChanged->Connect([selection, mainWnd](std::vector<Variant> _){
|
selectionConnection = selection->SelectionChanged->Connect([selection, mainWnd](std::vector<Variant> _){
|
||||||
// Update properties
|
// Update properties
|
||||||
if (selection->Get().size() != 1)
|
if (selection->Get().size() != 1)
|
||||||
mainWnd->ui->propertiesView->setSelected(nullptr);
|
mainWnd->ui->propertiesView->setSelected(std::nullopt);
|
||||||
else
|
else
|
||||||
mainWnd->ui->propertiesView->setSelected(selection->Get()[0]);
|
mainWnd->ui->propertiesView->setSelected(selection->Get()[0]);
|
||||||
|
|
||||||
|
@ -87,6 +130,7 @@ void PlaceDocument::closeEvent(QCloseEvent *closeEvent) {
|
||||||
closeEvent->ignore();
|
closeEvent->ignore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<BasePart> shit;
|
||||||
void PlaceDocument::timerEvent(QTimerEvent* evt) {
|
void PlaceDocument::timerEvent(QTimerEvent* evt) {
|
||||||
if (evt->timerId() != timer.timerId()) {
|
if (evt->timerId() != timer.timerId()) {
|
||||||
QWidget::timerEvent(evt);
|
QWidget::timerEvent(evt);
|
||||||
|
@ -96,7 +140,7 @@ void PlaceDocument::timerEvent(QTimerEvent* evt) {
|
||||||
placeWidget->repaint();
|
placeWidget->repaint();
|
||||||
placeWidget->updateCycle();
|
placeWidget->updateCycle();
|
||||||
gDataModel->GetService<ScriptContext>()->RunSleepingThreads();
|
gDataModel->GetService<ScriptContext>()->RunSleepingThreads();
|
||||||
if (_runState == RUN_RUNNING) gDataModel->GetService<Workspace>()->PhysicsStep(0.033);
|
gDataModel->GetService<Workspace>()->ProcessContactEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
class Selection;
|
class Selection;
|
||||||
|
class PlaceDocumentPhysicsWorker;
|
||||||
|
|
||||||
enum RunState {
|
enum RunState {
|
||||||
RUN_STOPPED,
|
RUN_STOPPED,
|
||||||
|
@ -24,10 +25,14 @@ class PlaceDocument : public QMdiSubWindow {
|
||||||
QBasicTimer timer;
|
QBasicTimer timer;
|
||||||
RunState _runState;
|
RunState _runState;
|
||||||
|
|
||||||
|
PlaceDocumentPhysicsWorker* worker;
|
||||||
|
|
||||||
std::weak_ptr<SignalConnection> selectionConnection;
|
std::weak_ptr<SignalConnection> selectionConnection;
|
||||||
|
|
||||||
void timerEvent(QTimerEvent*) override;
|
void timerEvent(QTimerEvent*) override;
|
||||||
void updateSelectionListeners(std::shared_ptr<Selection>);
|
void updateSelectionListeners(std::shared_ptr<Selection>);
|
||||||
|
|
||||||
|
void updatePhysicsWorker();
|
||||||
public:
|
public:
|
||||||
MainGLWidget* placeWidget;
|
MainGLWidget* placeWidget;
|
||||||
PlaceDocument(QWidget* parent = nullptr);
|
PlaceDocument(QWidget* parent = nullptr);
|
||||||
|
|
|
@ -27,7 +27,7 @@ void UndoHistory::Undo() {
|
||||||
// The old value used to be valid, so it still should be...
|
// The old value used to be valid, so it still should be...
|
||||||
v->affectedInstance->SetProperty(v->property, v->oldValue).expect();
|
v->affectedInstance->SetProperty(v->property, v->oldValue).expect();
|
||||||
} else if (auto v = std::get_if<UndoStateInstanceCreated>(&change)) {
|
} else if (auto v = std::get_if<UndoStateInstanceCreated>(&change)) {
|
||||||
v->instance->SetParent(nullptr);
|
v->instance->SetParent(std::nullopt);
|
||||||
} else if (auto v = std::get_if<UndoStateInstanceRemoved>(&change)) {
|
} else if (auto v = std::get_if<UndoStateInstanceRemoved>(&change)) {
|
||||||
v->instance->SetParent(v->oldParent);
|
v->instance->SetParent(v->oldParent);
|
||||||
} else if (auto v = std::get_if<UndoStateInstanceReparented>(&change)) {
|
} else if (auto v = std::get_if<UndoStateInstanceReparented>(&change)) {
|
||||||
|
@ -57,7 +57,7 @@ void UndoHistory::Redo() {
|
||||||
} else if (auto v = std::get_if<UndoStateInstanceCreated>(&change)) {
|
} else if (auto v = std::get_if<UndoStateInstanceCreated>(&change)) {
|
||||||
v->instance->SetParent(v->newParent);
|
v->instance->SetParent(v->newParent);
|
||||||
} else if (auto v = std::get_if<UndoStateInstanceRemoved>(&change)) {
|
} else if (auto v = std::get_if<UndoStateInstanceRemoved>(&change)) {
|
||||||
v->instance->SetParent(nullptr);
|
v->instance->SetParent(std::nullopt);
|
||||||
} else if (auto v = std::get_if<UndoStateInstanceReparented>(&change)) {
|
} else if (auto v = std::get_if<UndoStateInstanceReparented>(&change)) {
|
||||||
v->instance->SetParent(v->newParent);
|
v->instance->SetParent(v->newParent);
|
||||||
} else if (auto v = std::get_if<UndoStateSelectionChanged>(&change)) {
|
} else if (auto v = std::get_if<UndoStateSelectionChanged>(&change)) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue