Compare commits
No commits in common. "b80eb03f9d61f2de2c017fbb9173b8aebb2a528b" and "50f1466fe223e1dd0985d00b1d468870dfe1b543" have entirely different histories.
b80eb03f9d
...
50f1466fe2
78 changed files with 177 additions and 2213 deletions
11
.clangd
Normal file
11
.clangd
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
CompileFlags: # Tweak the parse settings, example directory given to show format
|
||||||
|
Add:
|
||||||
|
- "--include-directory=../../src"
|
||||||
|
- "--include-directory=../src"
|
||||||
|
- "--include-directory=./editor_autogen/include"
|
||||||
|
- "--include-directory=../.."
|
||||||
|
- "--include-directory=/usr/include/qt6/QtWidgets"
|
||||||
|
- "--include-directory=/usr/include/qt6/QtOpenGLWidgets"
|
||||||
|
- "--include-directory=/usr/include/qt6"
|
||||||
|
- "--include-directory=/usr/include/qt6/QtGui"
|
||||||
|
- "--include-directory=/usr/include/qt6/QtCore"
|
9
.gitignore
vendored
9
.gitignore
vendored
|
@ -9,11 +9,4 @@ Makefile
|
||||||
.lupdate/
|
.lupdate/
|
||||||
*.pro.user*
|
*.pro.user*
|
||||||
CMakeLists.txt.user*
|
CMakeLists.txt.user*
|
||||||
*_autogen/
|
*_autogen/
|
||||||
|
|
||||||
# Clangd
|
|
||||||
/compile_commands.json
|
|
||||||
/.cache
|
|
||||||
|
|
||||||
# Gdb
|
|
||||||
.gdb_history
|
|
|
@ -7,8 +7,44 @@ set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin )
|
||||||
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
|
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
|
||||||
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib )
|
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib )
|
||||||
|
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
SET(BASEPATH "${CMAKE_SOURCE_DIR}")
|
||||||
|
include_directories("${BASEPATH}")
|
||||||
|
include_directories("src")
|
||||||
|
|
||||||
add_subdirectory(core)
|
find_package(OpenGL REQUIRED COMPONENTS OpenGL)
|
||||||
add_subdirectory(client)
|
|
||||||
add_subdirectory(editor)
|
find_package(SDL2 REQUIRED)
|
||||||
|
include_directories(${SDL2_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
find_package(GLEW REQUIRED)
|
||||||
|
include_directories(${GLEW_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
find_package(GLUT REQUIRED)
|
||||||
|
include_directories(${GLUT_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
find_package(glfw3 REQUIRED)
|
||||||
|
find_package(OpenGL)
|
||||||
|
find_package(glm CONFIG REQUIRED)
|
||||||
|
find_package(assimp REQUIRED)
|
||||||
|
find_package(ReactPhysics3D REQUIRED)
|
||||||
|
find_package(pugixml REQUIRED)
|
||||||
|
|
||||||
|
# PkgConfig packages
|
||||||
|
# find_package(PkgConfig REQUIRED)
|
||||||
|
# pkg_check_modules(PUGIXML REQUIRED pugixml)
|
||||||
|
|
||||||
|
file(MAKE_DIRECTORY bin)
|
||||||
|
|
||||||
|
include_directories("include")
|
||||||
|
|
||||||
|
file(GLOB_RECURSE SOURCES "src/*.cpp" "src/*.h")
|
||||||
|
add_library(openblocks ${SOURCES})
|
||||||
|
set_target_properties(openblocks PROPERTIES OUTPUT_NAME "openblocks")
|
||||||
|
target_link_libraries(openblocks ${SDL2_LIBRARIES} ${GLEW_LIBRARIES} ${GLUT_LIBRARIES} ${PUGIXML_LIBRARIES} OpenGL::GL OpenGL::GLU glfw glm::glm assimp ReactPhysics3D::ReactPhysics3D pugixml::pugixml)
|
||||||
|
|
||||||
|
# add_executable(client "client/src/main.cpp" $<TARGET_OBJECTS:openblocks>)
|
||||||
|
# include_directories("src")
|
||||||
|
# target_link_libraries(client ${SDL2_LIBRARIES} ${GLEW_LIBRARIES} ${GLUT_LIBRARIES} OpenGL::GL OpenGL::GLU glfw glm::glm assimp ReactPhysics3D::ReactPhysics3D)
|
||||||
|
|
||||||
|
add_subdirectory("client")
|
||||||
|
add_subdirectory("editor")
|
Binary file not shown.
Before Width: | Height: | Size: 868 B |
Binary file not shown.
Before Width: | Height: | Size: 836 B |
Binary file not shown.
Before Width: | Height: | Size: 865 B |
|
@ -1,109 +0,0 @@
|
||||||
#version 330 core
|
|
||||||
|
|
||||||
// Implements the Phong lighting model with respect to materials and lighting materials
|
|
||||||
|
|
||||||
// Structs
|
|
||||||
|
|
||||||
struct Material {
|
|
||||||
vec3 diffuse;
|
|
||||||
vec3 specular;
|
|
||||||
float shininess;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DirLight {
|
|
||||||
vec3 direction;
|
|
||||||
vec3 ambient;
|
|
||||||
vec3 diffuse;
|
|
||||||
vec3 specular;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PointLight {
|
|
||||||
vec3 position;
|
|
||||||
// vec3 direction;
|
|
||||||
vec3 ambient;
|
|
||||||
vec3 diffuse;
|
|
||||||
vec3 specular;
|
|
||||||
|
|
||||||
float constant;
|
|
||||||
float linear;
|
|
||||||
float quadratic;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// I/O
|
|
||||||
|
|
||||||
in vec3 vPos;
|
|
||||||
in vec3 vNormal;
|
|
||||||
in vec2 vTexCoords;
|
|
||||||
|
|
||||||
out vec4 FragColor;
|
|
||||||
|
|
||||||
#define NR_POINT_LIGHTS 4
|
|
||||||
|
|
||||||
uniform vec3 viewPos;
|
|
||||||
uniform PointLight pointLights[NR_POINT_LIGHTS];
|
|
||||||
uniform int numPointLights;
|
|
||||||
uniform DirLight sunLight;
|
|
||||||
uniform Material material;
|
|
||||||
|
|
||||||
// Functions
|
|
||||||
|
|
||||||
vec3 calculateDirectionalLight(DirLight light);
|
|
||||||
vec3 calculatePointLight(PointLight light);
|
|
||||||
|
|
||||||
|
|
||||||
// Main
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vec3 result = vec3(0.0);
|
|
||||||
|
|
||||||
result += calculateDirectionalLight(sunLight);
|
|
||||||
|
|
||||||
for (int i = 0; i < numPointLights; i++) {
|
|
||||||
result += calculatePointLight(pointLights[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
FragColor = vec4(result, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 calculateDirectionalLight(DirLight light) {
|
|
||||||
// Calculate diffuse
|
|
||||||
vec3 norm = normalize(vNormal);
|
|
||||||
vec3 lightDir = normalize(-light.direction);
|
|
||||||
float diff = max(dot(norm, lightDir), 0.0);
|
|
||||||
|
|
||||||
// Calculate specular
|
|
||||||
vec3 viewDir = normalize(viewPos - vPos);
|
|
||||||
vec3 reflectDir = reflect(-lightDir, norm);
|
|
||||||
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
|
|
||||||
|
|
||||||
vec3 ambient = light.ambient * material.diffuse;
|
|
||||||
vec3 diffuse = light.diffuse * diff * material.diffuse;
|
|
||||||
vec3 specular = light.specular * spec * material.specular;
|
|
||||||
|
|
||||||
return (ambient + diffuse + specular);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 calculatePointLight(PointLight light) {
|
|
||||||
// Calculate ambient light
|
|
||||||
|
|
||||||
// Calculate diffuse light
|
|
||||||
vec3 norm = normalize(vNormal);
|
|
||||||
vec3 lightDir = normalize(light.position - vPos);
|
|
||||||
float diff = max(dot(norm, lightDir), 0.0);
|
|
||||||
|
|
||||||
// Calculate specular
|
|
||||||
vec3 viewDir = normalize(viewPos - vPos);
|
|
||||||
vec3 reflectDir = reflect(-lightDir, norm);
|
|
||||||
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
|
|
||||||
|
|
||||||
// Calculate attenuation
|
|
||||||
float distance = length(light.position - vPos);
|
|
||||||
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
|
|
||||||
|
|
||||||
vec3 ambient = light.ambient * material.diffuse;
|
|
||||||
vec3 diffuse = light.diffuse * diff * material.diffuse;
|
|
||||||
vec3 specular = light.specular * spec * material.specular;
|
|
||||||
|
|
||||||
return (ambient + diffuse + specular) * attenuation;
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
#version 330 core
|
|
||||||
layout (location = 0) in vec3 aPos;
|
|
||||||
layout (location = 1) in vec3 aNormal;
|
|
||||||
layout (location = 2) in vec2 aTexCoords;
|
|
||||||
|
|
||||||
out vec3 vPos;
|
|
||||||
out vec3 vNormal;
|
|
||||||
out vec2 vTexCoords;
|
|
||||||
|
|
||||||
uniform mat4 model;
|
|
||||||
uniform mat3 normalMatrix;
|
|
||||||
uniform mat4 view;
|
|
||||||
uniform mat4 projection;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
gl_Position = projection * view * model * vec4(aPos, 1.0);
|
|
||||||
vPos = vec3(model * vec4(aPos, 1.0));
|
|
||||||
vNormal = normalMatrix * aNormal;
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
#version 330 core
|
|
||||||
|
|
||||||
// I/O
|
|
||||||
|
|
||||||
out vec4 FragColor;
|
|
||||||
|
|
||||||
uniform vec3 aColor;
|
|
||||||
|
|
||||||
// Main
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
FragColor = vec4(aColor, 1);
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
#version 330 core
|
|
||||||
layout (location = 0) in vec3 aPos;
|
|
||||||
|
|
||||||
out vec3 vPos;
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
gl_Position = vec4(aPos, 1.0);
|
|
||||||
}
|
|
|
@ -53,7 +53,6 @@ uniform int numPointLights;
|
||||||
uniform DirLight sunLight;
|
uniform DirLight sunLight;
|
||||||
uniform Material material;
|
uniform Material material;
|
||||||
uniform sampler2DArray studs;
|
uniform sampler2DArray studs;
|
||||||
uniform float transparency;
|
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
|
|
||||||
|
@ -73,7 +72,7 @@ void main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 studPx = texture(studs, vec3(vTexCoords, vSurfaceZ));
|
vec4 studPx = texture(studs, vec3(vTexCoords, vSurfaceZ));
|
||||||
FragColor = vec4(mix(result, vec3(studPx), studPx.w), 1-transparency);
|
FragColor = vec4(mix(result, vec3(studPx), studPx.w), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 calculateDirectionalLight(DirLight light) {
|
vec3 calculateDirectionalLight(DirLight light) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
find_package(glfw3 REQUIRED)
|
|
||||||
|
|
||||||
add_executable(client "src/main.cpp")
|
add_executable(client "src/main.cpp" $<TARGET_OBJECTS:openblocks>)
|
||||||
target_link_libraries(client PRIVATE openblocks glfw)
|
include_directories("../src")
|
||||||
|
target_link_libraries(client ${SDL2_LIBRARIES} ${GLEW_LIBRARIES} ${GLUT_LIBRARIES} OpenGL::GL OpenGL::GLU glfw glm::glm assimp ReactPhysics3D::ReactPhysics3D pugixml::pugixml)
|
|
@ -1,24 +0,0 @@
|
||||||
find_package(OpenGL REQUIRED COMPONENTS OpenGL)
|
|
||||||
|
|
||||||
find_package(SDL2 REQUIRED)
|
|
||||||
include_directories(${SDL2_INCLUDE_DIRS})
|
|
||||||
|
|
||||||
find_package(GLEW REQUIRED)
|
|
||||||
include_directories(${GLEW_INCLUDE_DIRS})
|
|
||||||
|
|
||||||
find_package(GLUT REQUIRED)
|
|
||||||
include_directories(${GLUT_INCLUDE_DIRS})
|
|
||||||
|
|
||||||
find_package(OpenGL)
|
|
||||||
find_package(glm CONFIG REQUIRED)
|
|
||||||
# find_package(assimp REQUIRED)
|
|
||||||
find_package(ReactPhysics3D REQUIRED)
|
|
||||||
find_package(pugixml REQUIRED)
|
|
||||||
|
|
||||||
file(MAKE_DIRECTORY bin)
|
|
||||||
|
|
||||||
file(GLOB_RECURSE SOURCES "src/*.cpp" "src/*.h")
|
|
||||||
add_library(openblocks ${SOURCES})
|
|
||||||
set_target_properties(openblocks PROPERTIES OUTPUT_NAME "openblocks")
|
|
||||||
target_link_libraries(openblocks ${SDL2_LIBRARIES} ${GLEW_LIBRARIES} ${GLUT_LIBRARIES} OpenGL::GL OpenGL::GLU ReactPhysics3D::ReactPhysics3D pugixml::pugixml)
|
|
||||||
target_include_directories(openblocks PUBLIC "src" "../include")
|
|
|
@ -1,103 +0,0 @@
|
||||||
#include "math_helper.h"
|
|
||||||
|
|
||||||
#define CMP_EPSILON 0.00001
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
glm::vec3 p = p_p1 - p_p0;
|
|
||||||
glm::vec3 q = p_q1 - p_q0;
|
|
||||||
glm::vec3 r = p_p0 - p_q0;
|
|
||||||
|
|
||||||
float a = glm::dot(p, p);
|
|
||||||
float b = glm::dot(p, q);
|
|
||||||
float c = glm::dot(q, q);
|
|
||||||
float d = glm::dot(p, r);
|
|
||||||
float e = glm::dot(q, r);
|
|
||||||
|
|
||||||
float s = 0.0f;
|
|
||||||
float t = 0.0f;
|
|
||||||
|
|
||||||
float det = a * c - b * b;
|
|
||||||
if (det > CMP_EPSILON) {
|
|
||||||
// Non-parallel segments
|
|
||||||
float bte = b * e;
|
|
||||||
float ctd = c * d;
|
|
||||||
|
|
||||||
if (bte <= ctd) {
|
|
||||||
// s <= 0.0f
|
|
||||||
if (e <= 0.0f) {
|
|
||||||
// t <= 0.0f
|
|
||||||
s = (-d >= a ? 1 : (-d > 0.0f ? -d / a : 0.0f));
|
|
||||||
t = 0.0f;
|
|
||||||
} else if (e < c) {
|
|
||||||
// 0.0f < t < 1
|
|
||||||
s = 0.0f;
|
|
||||||
t = e / c;
|
|
||||||
} else {
|
|
||||||
// t >= 1
|
|
||||||
s = (b - d >= a ? 1 : (b - d > 0.0f ? (b - d) / a : 0.0f));
|
|
||||||
t = 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// s > 0.0f
|
|
||||||
s = bte - ctd;
|
|
||||||
if (s >= det) {
|
|
||||||
// s >= 1
|
|
||||||
if (b + e <= 0.0f) {
|
|
||||||
// t <= 0.0f
|
|
||||||
s = (-d <= 0.0f ? 0.0f : (-d < a ? -d / a : 1));
|
|
||||||
t = 0.0f;
|
|
||||||
} else if (b + e < c) {
|
|
||||||
// 0.0f < t < 1
|
|
||||||
s = 1;
|
|
||||||
t = (b + e) / c;
|
|
||||||
} else {
|
|
||||||
// t >= 1
|
|
||||||
s = (b - d <= 0.0f ? 0.0f : (b - d < a ? (b - d) / a : 1));
|
|
||||||
t = 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 0.0f < s < 1
|
|
||||||
float ate = a * e;
|
|
||||||
float btd = b * d;
|
|
||||||
|
|
||||||
if (ate <= btd) {
|
|
||||||
// t <= 0.0f
|
|
||||||
s = (-d <= 0.0f ? 0.0f : (-d >= a ? 1 : -d / a));
|
|
||||||
t = 0.0f;
|
|
||||||
} else {
|
|
||||||
// t > 0.0f
|
|
||||||
t = ate - btd;
|
|
||||||
if (t >= det) {
|
|
||||||
// t >= 1
|
|
||||||
s = (b - d <= 0.0f ? 0.0f : (b - d >= a ? 1 : (b - d) / a));
|
|
||||||
t = 1;
|
|
||||||
} else {
|
|
||||||
// 0.0f < t < 1
|
|
||||||
s /= det;
|
|
||||||
t /= det;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Parallel segments
|
|
||||||
if (e <= 0.0f) {
|
|
||||||
s = (-d <= 0.0f ? 0.0f : (-d >= a ? 1 : -d / a));
|
|
||||||
t = 0.0f;
|
|
||||||
} else if (e >= c) {
|
|
||||||
s = (b - d <= 0.0f ? 0.0f : (b - d >= a ? 1 : (b - d) / a));
|
|
||||||
t = 1;
|
|
||||||
} else {
|
|
||||||
s = 0.0f;
|
|
||||||
t = e / c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
r_ps = (1 - s) * p_p0 + s * p_p1;
|
|
||||||
r_qt = (1 - t) * p_q0 + t * p_q1;
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
|
|
||||||
// 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);
|
|
|
@ -1,90 +0,0 @@
|
||||||
#include "handles.h"
|
|
||||||
#include "common.h"
|
|
||||||
#include "datatypes/cframe.h"
|
|
||||||
#include "datatypes/vector.h"
|
|
||||||
#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::XNeg(1, glm::vec3(-1,0,0));
|
|
||||||
HandleFace HandleFace::YPos(2, glm::vec3(0,1,0));
|
|
||||||
HandleFace HandleFace::YNeg(3, glm::vec3(0,-1,0));
|
|
||||||
HandleFace HandleFace::ZPos(4, glm::vec3(0,0,1));
|
|
||||||
HandleFace HandleFace::ZNeg(5, glm::vec3(0,0,-1));
|
|
||||||
std::array<HandleFace, 6> HandleFace::Faces { HandleFace::XPos, HandleFace::XNeg, HandleFace::YPos, HandleFace::YNeg, HandleFace::ZPos, HandleFace::ZNeg };
|
|
||||||
|
|
||||||
// Shitty solution
|
|
||||||
static rp3d::PhysicsCommon common;
|
|
||||||
static rp3d::PhysicsWorld* world = common.createPhysicsWorld();
|
|
||||||
|
|
||||||
const InstanceType Handles::TYPE = {
|
|
||||||
.super = &Instance::TYPE,
|
|
||||||
.className = "Handles",
|
|
||||||
// .constructor = &Workspace::Create,
|
|
||||||
// .explorerIcon = "",
|
|
||||||
};
|
|
||||||
|
|
||||||
const InstanceType* Handles::GetClass() {
|
|
||||||
return &TYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
Handles::Handles(): Instance(&TYPE) {
|
|
||||||
}
|
|
||||||
|
|
||||||
Data::CFrame Handles::GetCFrameOfHandle(HandleFace face) {
|
|
||||||
if (!adornee.has_value() || adornee->expired()) return Data::CFrame(glm::vec3(0,0,0), (Data::Vector3)glm::vec3(0,0,0));
|
|
||||||
|
|
||||||
Data::CFrame localFrame = worldMode ? Data::CFrame::IDENTITY + adornee->lock()->position() : adornee->lock()->cframe;
|
|
||||||
|
|
||||||
// We don't want this to align with local * face.normal, or else we have problems.
|
|
||||||
glm::vec3 upAxis(0, 0, 1);
|
|
||||||
if (glm::abs(glm::dot(glm::vec3(localFrame.Rotation() * face.normal), upAxis)) > 0.9999f)
|
|
||||||
upAxis = glm::vec3(0, 1, 0);
|
|
||||||
|
|
||||||
Data::Vector3 handlePos = localFrame * ((2.f + adornee->lock()->size * 0.5f) * face.normal);
|
|
||||||
Data::CFrame cframe(handlePos, handlePos + localFrame.Rotation() * face.normal, upAxis);
|
|
||||||
|
|
||||||
return cframe;
|
|
||||||
}
|
|
||||||
|
|
||||||
Data::CFrame Handles::PartCFrameFromHandlePos(HandleFace face, Data::Vector3 newPos) {
|
|
||||||
if (!adornee.has_value() || adornee->expired()) return Data::CFrame(glm::vec3(0,0,0), (Data::Vector3)glm::vec3(0,0,0));
|
|
||||||
|
|
||||||
Data::CFrame localFrame = worldMode ? Data::CFrame::IDENTITY + adornee->lock()->position() : adornee->lock()->cframe;
|
|
||||||
Data::CFrame inverseFrame = localFrame.Inverse();
|
|
||||||
|
|
||||||
Data::Vector3 handlePos = localFrame * ((2.f + adornee->lock()->size * 0.5f) * face.normal);
|
|
||||||
|
|
||||||
// glm::vec3 localPos = inverseFrame * newPos;
|
|
||||||
glm::vec3 newPartPos = newPos - localFrame.Rotation() * ((2.f + adornee->lock()->size * 0.5f) * face.normal);
|
|
||||||
return adornee->lock()->cframe.Rotation() + newPartPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<HandleFace> Handles::RaycastHandle(rp3d::Ray ray) {
|
|
||||||
for (HandleFace face : HandleFace::Faces) {
|
|
||||||
Data::CFrame cframe = GetCFrameOfHandle(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(Data::CFrame::IDENTITY + cframe.Position());
|
|
||||||
body->addCollider(common.createBoxShape(cframe.Rotation() * Data::Vector3(HandleSize(face) / 2.f)), rp3d::Transform::identity());
|
|
||||||
|
|
||||||
rp3d::RaycastInfo info;
|
|
||||||
if (body->raycast(ray, info)) {
|
|
||||||
world->destroyRigidBody(body);
|
|
||||||
return face;
|
|
||||||
}
|
|
||||||
|
|
||||||
world->destroyRigidBody(body);
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
Data::Vector3 Handles::HandleSize(HandleFace face) {
|
|
||||||
if (handlesType == HandlesType::MoveHandles)
|
|
||||||
return glm::vec3(0.5f, 0.5f, 2.f);
|
|
||||||
return glm::vec3(1,1,1);
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "base.h"
|
|
||||||
#include "datatypes/cframe.h"
|
|
||||||
#include "objects/base/service.h"
|
|
||||||
#include "objects/part.h"
|
|
||||||
#include <array>
|
|
||||||
#include <memory>
|
|
||||||
#include <reactphysics3d/body/RigidBody.h>
|
|
||||||
|
|
||||||
class HandleFace {
|
|
||||||
HandleFace(int index, glm::vec3 normal) : index(index), normal(normal){}
|
|
||||||
|
|
||||||
public:
|
|
||||||
int index;
|
|
||||||
glm::vec3 normal;
|
|
||||||
|
|
||||||
static HandleFace XPos;
|
|
||||||
static HandleFace XNeg;
|
|
||||||
static HandleFace YPos;
|
|
||||||
static HandleFace YNeg;
|
|
||||||
static HandleFace ZPos;
|
|
||||||
static HandleFace ZNeg;
|
|
||||||
static std::array<HandleFace, 6> Faces;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum HandlesType {
|
|
||||||
MoveHandles,
|
|
||||||
ScaleHandles,
|
|
||||||
RotateHandles,
|
|
||||||
};
|
|
||||||
|
|
||||||
class Handles : public Instance {
|
|
||||||
public:
|
|
||||||
const static InstanceType TYPE;
|
|
||||||
|
|
||||||
bool active;
|
|
||||||
std::optional<std::weak_ptr<Part>> adornee;
|
|
||||||
HandlesType handlesType;
|
|
||||||
|
|
||||||
// inline std::optional<std::weak_ptr<Part>> GetAdornee() { return adornee; }
|
|
||||||
// inline void SetAdornee(std::optional<std::weak_ptr<Part>> newAdornee) { this->adornee = newAdornee; updateAdornee(); };
|
|
||||||
|
|
||||||
Handles();
|
|
||||||
|
|
||||||
// World-space handles vs local-space handles
|
|
||||||
bool worldMode = false;
|
|
||||||
Data::CFrame GetCFrameOfHandle(HandleFace face);
|
|
||||||
Data::CFrame PartCFrameFromHandlePos(HandleFace face, Data::Vector3 newPos);
|
|
||||||
Data::Vector3 HandleSize(HandleFace face);
|
|
||||||
std::optional<HandleFace> RaycastHandle(rp3d::Ray ray);
|
|
||||||
|
|
||||||
static inline std::shared_ptr<Handles> New() { return std::make_shared<Handles>(); };
|
|
||||||
virtual const InstanceType* GetClass() override;
|
|
||||||
};
|
|
File diff suppressed because it is too large
Load diff
|
@ -14,6 +14,8 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets LinguistTools)
|
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets LinguistTools)
|
||||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets LinguistTools)
|
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets LinguistTools)
|
||||||
|
|
||||||
|
include_directories("../src")
|
||||||
|
|
||||||
set(TS_FILES editor_en_US.ts)
|
set(TS_FILES editor_en_US.ts)
|
||||||
|
|
||||||
set(PROJECT_SOURCES
|
set(PROJECT_SOURCES
|
||||||
|
@ -38,6 +40,7 @@ if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
|
||||||
qt_add_executable(editor
|
qt_add_executable(editor
|
||||||
MANUAL_FINALIZATION
|
MANUAL_FINALIZATION
|
||||||
${PROJECT_SOURCES}
|
${PROJECT_SOURCES}
|
||||||
|
$<TARGET_OBJECTS:openblocks>
|
||||||
)
|
)
|
||||||
# Define target properties for Android with Qt 6 as:
|
# Define target properties for Android with Qt 6 as:
|
||||||
# set_property(TARGET editor APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
|
# set_property(TARGET editor APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
|
||||||
|
@ -56,14 +59,14 @@ else()
|
||||||
add_executable(editor
|
add_executable(editor
|
||||||
${PROJECT_SOURCES}
|
${PROJECT_SOURCES}
|
||||||
mainglwidget.h mainglwidget.cpp
|
mainglwidget.h mainglwidget.cpp
|
||||||
|
$<TARGET_OBJECTS:openblocks>
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
|
qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_include_directories(editor PUBLIC "../core/src" "../include")
|
target_link_libraries(editor PRIVATE Qt${QT_VERSION_MAJOR}::Widgets ${SDL2_LIBRARIES} ${GLEW_LIBRARIES} ${GLUT_LIBRARIES} OpenGL::GL OpenGL::GLU glfw glm::glm assimp ReactPhysics3D::ReactPhysics3D pugixml::pugixml)
|
||||||
target_link_libraries(editor PRIVATE openblocks Qt${QT_VERSION_MAJOR}::Widgets)
|
|
||||||
|
|
||||||
# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
|
# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
|
||||||
# If you are developing for iOS or macOS you should consider setting an
|
# If you are developing for iOS or macOS you should consider setting an
|
||||||
|
|
|
@ -1 +1,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
enum SelectedTool {
|
||||||
|
SELECT,
|
||||||
|
MOVE,
|
||||||
|
SCALE,
|
||||||
|
ROTATE,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern SelectedTool selectedTool;
|
|
@ -2,22 +2,15 @@
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <glm/common.hpp>
|
|
||||||
#include <glm/ext/matrix_projection.hpp>
|
#include <glm/ext/matrix_projection.hpp>
|
||||||
#include <glm/ext/matrix_transform.hpp>
|
|
||||||
#include <glm/ext/vector_float3.hpp>
|
#include <glm/ext/vector_float3.hpp>
|
||||||
#include <glm/geometric.hpp>
|
#include <glm/geometric.hpp>
|
||||||
#include <glm/gtc/round.hpp>
|
|
||||||
#include <glm/matrix.hpp>
|
#include <glm/matrix.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <reactphysics3d/collision/RaycastInfo.h>
|
#include <reactphysics3d/collision/RaycastInfo.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "datatypes/cframe.h"
|
|
||||||
#include "editorcommon.h"
|
|
||||||
#include "mainwindow.h"
|
|
||||||
#include "objects/handles.h"
|
|
||||||
#include "physics/util.h"
|
#include "physics/util.h"
|
||||||
#include "qcursor.h"
|
#include "qcursor.h"
|
||||||
#include "qevent.h"
|
#include "qevent.h"
|
||||||
|
@ -28,11 +21,8 @@
|
||||||
#include "camera.h"
|
#include "camera.h"
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "rendering/shader.h"
|
|
||||||
|
|
||||||
#include "mainglwidget.h"
|
#include "mainglwidget.h"
|
||||||
#include "../core/src/rendering/defaultmeshes.h"
|
|
||||||
#include "math_helper.h"
|
|
||||||
|
|
||||||
MainGLWidget::MainGLWidget(QWidget* parent): QOpenGLWidget(parent) {
|
MainGLWidget::MainGLWidget(QWidget* parent): QOpenGLWidget(parent) {
|
||||||
setFocusPolicy(Qt::FocusPolicy::ClickFocus);
|
setFocusPolicy(Qt::FocusPolicy::ClickFocus);
|
||||||
|
@ -55,12 +45,6 @@ void MainGLWidget::resizeGL(int w, int h) {
|
||||||
setViewport(w, h);
|
setViewport(w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec2 firstPoint;
|
|
||||||
glm::vec2 secondPoint;
|
|
||||||
|
|
||||||
extern std::optional<std::weak_ptr<Part>> draggingObject;
|
|
||||||
extern std::optional<HandleFace> draggingHandle;
|
|
||||||
extern Shader* shader;
|
|
||||||
void MainGLWidget::paintGL() {
|
void MainGLWidget::paintGL() {
|
||||||
::render(NULL);
|
::render(NULL);
|
||||||
}
|
}
|
||||||
|
@ -78,9 +62,8 @@ void MainGLWidget::handleCameraRotate(QMouseEvent* evt) {
|
||||||
|
|
||||||
bool isMouseDragging = false;
|
bool isMouseDragging = false;
|
||||||
std::optional<std::weak_ptr<Part>> draggingObject;
|
std::optional<std::weak_ptr<Part>> draggingObject;
|
||||||
std::optional<HandleFace> draggingHandle;
|
|
||||||
void MainGLWidget::handleObjectDrag(QMouseEvent* evt) {
|
void MainGLWidget::handleObjectDrag(QMouseEvent* evt) {
|
||||||
if (!isMouseDragging || !draggingObject) return;
|
if (!isMouseDragging) return;
|
||||||
|
|
||||||
QPoint position = evt->pos();
|
QPoint position = evt->pos();
|
||||||
|
|
||||||
|
@ -96,107 +79,17 @@ void MainGLWidget::handleObjectDrag(QMouseEvent* evt) {
|
||||||
syncPartPhysics(draggingObject->lock());
|
syncPartPhysics(draggingObject->lock());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline glm::vec3 vec3fy(glm::vec4 vec) {
|
|
||||||
return vec / vec.w;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPoint lastPoint;
|
|
||||||
void MainGLWidget::handleHandleDrag(QMouseEvent* evt) {
|
|
||||||
QPoint cLastPoint = lastPoint;
|
|
||||||
lastPoint = evt->pos();
|
|
||||||
|
|
||||||
if (!isMouseDragging || !draggingHandle || !editorToolHandles->adornee || !editorToolHandles->active) return;
|
|
||||||
|
|
||||||
QPoint position = evt->pos();
|
|
||||||
|
|
||||||
auto part = editorToolHandles->adornee->lock();
|
|
||||||
|
|
||||||
// This was actually quite a difficult problem to solve, managing to get the handle to go underneath the cursor
|
|
||||||
|
|
||||||
glm::vec3 pointDir = camera.getScreenDirection(glm::vec2(position.x(), position.y()), glm::vec2(width(), height()));
|
|
||||||
pointDir = glm::normalize(pointDir);
|
|
||||||
|
|
||||||
Data::CFrame handleCFrame = editorToolHandles->GetCFrameOfHandle(draggingHandle.value());
|
|
||||||
|
|
||||||
// Current frame. Identity frame if worldMode == true, selected object's frame if worldMode == false
|
|
||||||
Data::CFrame frame = editorToolHandles->worldMode ? Data::CFrame::IDENTITY + part->position() : part->cframe.Rotation();
|
|
||||||
|
|
||||||
// Segment from axis stretching -4096 to +4096 rel to handle's position
|
|
||||||
glm::vec3 axisSegment0 = handleCFrame.Position() + (-handleCFrame.LookVector() * 4096.0f);
|
|
||||||
glm::vec3 axisSegment1 = handleCFrame.Position() + (-handleCFrame.LookVector() * -4096.0f);
|
|
||||||
|
|
||||||
// Segment from camera stretching 4096 forward
|
|
||||||
glm::vec3 mouseSegment0 = camera.cameraPos;
|
|
||||||
glm::vec3 mouseSegment1 = camera.cameraPos + pointDir * 4096.0f;
|
|
||||||
|
|
||||||
// Closest point on the axis segment between the two segments
|
|
||||||
glm::vec3 handlePoint, rb;
|
|
||||||
get_closest_points_between_segments(axisSegment0, axisSegment1, mouseSegment0, mouseSegment1, handlePoint, rb);
|
|
||||||
|
|
||||||
// Find new part position
|
|
||||||
glm::vec3 centerPoint = editorToolHandles->PartCFrameFromHandlePos(draggingHandle.value(), handlePoint).Position();
|
|
||||||
|
|
||||||
// Apply snapping in the current frame
|
|
||||||
glm::vec3 diff = centerPoint - (glm::vec3)editorToolHandles->adornee->lock()->position();
|
|
||||||
if (snappingFactor()) diff = frame * (glm::round(glm::vec3(frame.Inverse() * diff) / snappingFactor()) * snappingFactor());
|
|
||||||
|
|
||||||
switch (mainWindow()->selectedTool) {
|
|
||||||
case SelectedTool::SELECT: break;
|
|
||||||
case SelectedTool::MOVE: {
|
|
||||||
// Add difference
|
|
||||||
editorToolHandles->adornee->lock()->cframe = editorToolHandles->adornee->lock()->cframe + diff;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case SelectedTool::SCALE: {
|
|
||||||
// Find local difference
|
|
||||||
glm::vec3 localDiff = frame.Inverse() * diff;
|
|
||||||
// Find outwarwd difference
|
|
||||||
localDiff = localDiff * glm::sign(draggingHandle->normal);
|
|
||||||
|
|
||||||
// Add local difference to size
|
|
||||||
part->size += localDiff;
|
|
||||||
|
|
||||||
// If ctrl is not pressed, offset the part by half the size difference to keep the other bound where it was originally
|
|
||||||
if (!(evt->modifiers() & Qt::ControlModifier))
|
|
||||||
part->cframe = part->cframe + diff * 0.5f;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case SelectedTool::ROTATE: {
|
|
||||||
// TODO: Implement rotation
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
|
|
||||||
syncPartPhysics(std::dynamic_pointer_cast<Part>(editorToolHandles->adornee->lock()));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<HandleFace> MainGLWidget::raycastHandle(glm::vec3 pointDir) {
|
|
||||||
if (!editorToolHandles->adornee.has_value() || !editorToolHandles->active) return std::nullopt;
|
|
||||||
return editorToolHandles->RaycastHandle(rp3d::Ray(glmToRp(camera.cameraPos), glmToRp(glm::normalize(pointDir)) * 50000));
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainGLWidget::handleCursorChange(QMouseEvent* evt) {
|
void MainGLWidget::handleCursorChange(QMouseEvent* evt) {
|
||||||
QPoint position = evt->pos();
|
QPoint position = evt->pos();
|
||||||
|
|
||||||
glm::vec3 pointDir = camera.getScreenDirection(glm::vec2(position.x(), position.y()), glm::vec2(width(), height()));
|
glm::vec3 pointDir = camera.getScreenDirection(glm::vec2(position.x(), position.y()), glm::vec2(width(), height()));
|
||||||
|
|
||||||
if (raycastHandle(pointDir)) {
|
|
||||||
setCursor(Qt::OpenHandCursor);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::optional<const RaycastResult> rayHit = castRayNearest(camera.cameraPos, pointDir, 50000);
|
std::optional<const RaycastResult> rayHit = castRayNearest(camera.cameraPos, pointDir, 50000);
|
||||||
if (rayHit && partFromBody(rayHit->body)->name != "Baseplate") {
|
setCursor((rayHit && partFromBody(rayHit->body)->name != "Baseplate") ? Qt::OpenHandCursor : Qt::ArrowCursor);
|
||||||
setCursor(Qt::OpenHandCursor);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setCursor(Qt::ArrowCursor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainGLWidget::mouseMoveEvent(QMouseEvent* evt) {
|
void MainGLWidget::mouseMoveEvent(QMouseEvent* evt) {
|
||||||
handleCameraRotate(evt);
|
handleCameraRotate(evt);
|
||||||
handleObjectDrag(evt);
|
handleObjectDrag(evt);
|
||||||
handleHandleDrag(evt);
|
|
||||||
handleCursorChange(evt);
|
handleCursorChange(evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,15 +105,6 @@ void MainGLWidget::mousePressEvent(QMouseEvent* evt) {
|
||||||
QPoint position = evt->pos();
|
QPoint position = evt->pos();
|
||||||
|
|
||||||
glm::vec3 pointDir = camera.getScreenDirection(glm::vec2(position.x(), position.y()), glm::vec2(width(), height()));
|
glm::vec3 pointDir = camera.getScreenDirection(glm::vec2(position.x(), position.y()), glm::vec2(width(), height()));
|
||||||
// raycast handles
|
|
||||||
auto handle = raycastHandle(pointDir);
|
|
||||||
if (handle.has_value()) {
|
|
||||||
isMouseDragging = true;
|
|
||||||
draggingHandle = handle;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// raycast part
|
|
||||||
std::optional<const RaycastResult> rayHit = castRayNearest(camera.cameraPos, pointDir, 50000);
|
std::optional<const RaycastResult> rayHit = castRayNearest(camera.cameraPos, pointDir, 50000);
|
||||||
if (!rayHit || !partFromBody(rayHit->body)) return;
|
if (!rayHit || !partFromBody(rayHit->body)) return;
|
||||||
std::shared_ptr<Part> part = partFromBody(rayHit->body);
|
std::shared_ptr<Part> part = partFromBody(rayHit->body);
|
||||||
|
@ -244,7 +128,6 @@ void MainGLWidget::mouseReleaseEvent(QMouseEvent* evt) {
|
||||||
isMouseRightDragging = false;
|
isMouseRightDragging = false;
|
||||||
isMouseDragging = false;
|
isMouseDragging = false;
|
||||||
draggingObject = std::nullopt;
|
draggingObject = std::nullopt;
|
||||||
draggingHandle = std::nullopt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int moveZ = 0;
|
static int moveZ = 0;
|
||||||
|
@ -283,17 +166,4 @@ void MainGLWidget::keyPressEvent(QKeyEvent* evt) {
|
||||||
void MainGLWidget::keyReleaseEvent(QKeyEvent* evt) {
|
void MainGLWidget::keyReleaseEvent(QKeyEvent* evt) {
|
||||||
if (evt->key() == Qt::Key_W || evt->key() == Qt::Key_S) moveZ = 0;
|
if (evt->key() == Qt::Key_W || evt->key() == Qt::Key_S) moveZ = 0;
|
||||||
else if (evt->key() == Qt::Key_A || evt->key() == Qt::Key_D) moveX = 0;
|
else if (evt->key() == Qt::Key_A || evt->key() == Qt::Key_D) moveX = 0;
|
||||||
}
|
|
||||||
|
|
||||||
MainWindow* MainGLWidget::mainWindow() {
|
|
||||||
return dynamic_cast<MainWindow*>(window());
|
|
||||||
}
|
|
||||||
|
|
||||||
float MainGLWidget::snappingFactor() {
|
|
||||||
switch (mainWindow()->snappingMode) {
|
|
||||||
case GridSnappingMode::SNAP_1_STUD: return 1;
|
|
||||||
case GridSnappingMode::SNAP_05_STUDS: return 0.5;
|
|
||||||
case GridSnappingMode::SNAP_OFF: return 0;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
|
@ -1,15 +1,12 @@
|
||||||
#ifndef MAINGLWIDGET_H
|
#ifndef MAINGLWIDGET_H
|
||||||
#define MAINGLWIDGET_H
|
#define MAINGLWIDGET_H
|
||||||
|
|
||||||
#include "mainwindow.h"
|
|
||||||
#include "objects/part.h"
|
#include "objects/part.h"
|
||||||
#include "qevent.h"
|
#include "qevent.h"
|
||||||
#include <QOpenGLWidget>
|
#include <QOpenGLWidget>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class HandleFace;
|
|
||||||
|
|
||||||
class MainGLWidget : public QOpenGLWidget {
|
class MainGLWidget : public QOpenGLWidget {
|
||||||
public:
|
public:
|
||||||
MainGLWidget(QWidget *parent = nullptr);
|
MainGLWidget(QWidget *parent = nullptr);
|
||||||
|
@ -23,18 +20,13 @@ protected:
|
||||||
|
|
||||||
void handleCameraRotate(QMouseEvent* evt);
|
void handleCameraRotate(QMouseEvent* evt);
|
||||||
void handleObjectDrag(QMouseEvent* evt);
|
void handleObjectDrag(QMouseEvent* evt);
|
||||||
void handleHandleDrag(QMouseEvent* evt);
|
|
||||||
void handleCursorChange(QMouseEvent* evt);
|
void handleCursorChange(QMouseEvent* evt);
|
||||||
std::optional<HandleFace> raycastHandle(glm::vec3 pointDir);
|
|
||||||
|
|
||||||
void mouseMoveEvent(QMouseEvent* evt) override;
|
void mouseMoveEvent(QMouseEvent* evt) override;
|
||||||
void mousePressEvent(QMouseEvent* evt) override;
|
void mousePressEvent(QMouseEvent* evt) override;
|
||||||
void mouseReleaseEvent(QMouseEvent* evt) override;
|
void mouseReleaseEvent(QMouseEvent* evt) override;
|
||||||
void keyPressEvent(QKeyEvent* evt) override;
|
void keyPressEvent(QKeyEvent* evt) override;
|
||||||
void keyReleaseEvent(QKeyEvent* evt) override;
|
void keyReleaseEvent(QKeyEvent* evt) override;
|
||||||
|
|
||||||
MainWindow* mainWindow();
|
|
||||||
float snappingFactor();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MAINGLWIDGET_H
|
#endif // MAINGLWIDGET_H
|
||||||
|
|
|
@ -10,14 +10,12 @@
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QTreeView>
|
#include <QTreeView>
|
||||||
#include <QAbstractItemView>
|
#include <QAbstractItemView>
|
||||||
#include <memory>
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "editorcommon.h"
|
#include "editorcommon.h"
|
||||||
#include "objects/base/instance.h"
|
#include "objects/base/instance.h"
|
||||||
#include "objects/datamodel.h"
|
#include "objects/datamodel.h"
|
||||||
#include "objects/handles.h"
|
|
||||||
#include "physics/simulation.h"
|
#include "physics/simulation.h"
|
||||||
#include "objects/part.h"
|
#include "objects/part.h"
|
||||||
#include "qfiledialog.h"
|
#include "qfiledialog.h"
|
||||||
|
@ -25,6 +23,8 @@
|
||||||
#include "qobject.h"
|
#include "qobject.h"
|
||||||
#include "qsysinfo.h"
|
#include "qsysinfo.h"
|
||||||
|
|
||||||
|
SelectedTool selectedTool;
|
||||||
|
|
||||||
bool simulationPlaying = false;
|
bool simulationPlaying = false;
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget *parent)
|
MainWindow::MainWindow(QWidget *parent)
|
||||||
|
@ -39,18 +39,11 @@ MainWindow::MainWindow(QWidget *parent)
|
||||||
|
|
||||||
ConnectSelectionChangeHandler();
|
ConnectSelectionChangeHandler();
|
||||||
|
|
||||||
connect(ui->actionToolSelect, &QAction::triggered, this, [&]() { selectedTool = SelectedTool::SELECT; updateToolbars(); });
|
connect(ui->actionToolSelect, &QAction::triggered, this, [&]() { selectedTool = SelectedTool::SELECT; updateSelectedTool(); });
|
||||||
connect(ui->actionToolMove, &QAction::triggered, this, [&](bool state) { selectedTool = state ? SelectedTool::MOVE : SelectedTool::SELECT; updateToolbars(); });
|
connect(ui->actionToolMove, &QAction::triggered, this, [&](bool state) { selectedTool = state ? SelectedTool::MOVE : SelectedTool::SELECT; updateSelectedTool(); });
|
||||||
connect(ui->actionToolScale, &QAction::triggered, this, [&](bool state) { selectedTool = state ? SelectedTool::SCALE : SelectedTool::SELECT; updateToolbars(); });
|
connect(ui->actionToolScale, &QAction::triggered, this, [&](bool state) { selectedTool = state ? SelectedTool::SCALE : SelectedTool::SELECT; updateSelectedTool(); });
|
||||||
connect(ui->actionToolRotate, &QAction::triggered, this, [&](bool state) { selectedTool = state ? SelectedTool::ROTATE : SelectedTool::SELECT; updateToolbars(); });
|
connect(ui->actionToolRotate, &QAction::triggered, this, [&](bool state) { selectedTool = state ? SelectedTool::ROTATE : SelectedTool::SELECT; updateSelectedTool(); });
|
||||||
ui->actionToolSelect->setChecked(true);
|
ui->actionToolSelect->setChecked(true);
|
||||||
selectedTool = SelectedTool::SELECT;
|
|
||||||
|
|
||||||
connect(ui->actionGridSnap1, &QAction::triggered, this, [&]() { snappingMode = GridSnappingMode::SNAP_1_STUD; updateToolbars(); });
|
|
||||||
connect(ui->actionGridSnap05, &QAction::triggered, this, [&]() { snappingMode = GridSnappingMode::SNAP_05_STUDS; updateToolbars(); });
|
|
||||||
connect(ui->actionGridSnapOff, &QAction::triggered, this, [&]() { snappingMode = GridSnappingMode::SNAP_OFF; updateToolbars(); });
|
|
||||||
ui->actionGridSnap1->setChecked(true);
|
|
||||||
snappingMode = GridSnappingMode::SNAP_1_STUD;
|
|
||||||
|
|
||||||
connect(ui->actionToggleSimulation, &QAction::triggered, this, [&]() {
|
connect(ui->actionToggleSimulation, &QAction::triggered, this, [&]() {
|
||||||
simulationPlaying = !simulationPlaying;
|
simulationPlaying = !simulationPlaying;
|
||||||
|
@ -85,24 +78,6 @@ MainWindow::MainWindow(QWidget *parent)
|
||||||
ConnectSelectionChangeHandler();
|
ConnectSelectionChangeHandler();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update handles
|
|
||||||
addSelectionListener([&](auto oldSelection, auto newSelection, bool fromExplorer) {
|
|
||||||
editorToolHandles->adornee = std::nullopt;
|
|
||||||
if (newSelection.size() == 0) return;
|
|
||||||
InstanceRef inst = newSelection[0].lock();
|
|
||||||
if (inst->GetClass() != &Part::TYPE) return;
|
|
||||||
|
|
||||||
editorToolHandles->adornee = std::dynamic_pointer_cast<Part>(inst);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update properties
|
|
||||||
addSelectionListener([&](auto oldSelection, auto newSelection, bool fromExplorer) {
|
|
||||||
if (newSelection.size() == 0) return;
|
|
||||||
if (newSelection.size() > 1)
|
|
||||||
ui->propertiesView->setSelected(std::nullopt);
|
|
||||||
ui->propertiesView->setSelected(newSelection[0].lock());
|
|
||||||
});
|
|
||||||
|
|
||||||
// ui->explorerView->Init(ui);
|
// ui->explorerView->Init(ui);
|
||||||
|
|
||||||
simulationInit();
|
simulationInit();
|
||||||
|
@ -120,7 +95,7 @@ MainWindow::MainWindow(QWidget *parent)
|
||||||
|
|
||||||
workspace()->AddChild(ui->mainWidget->lastPart = Part::New({
|
workspace()->AddChild(ui->mainWidget->lastPart = Part::New({
|
||||||
.position = glm::vec3(0),
|
.position = glm::vec3(0),
|
||||||
.rotation = glm::vec3(0.5, 2, 1),
|
.rotation = glm::vec3(0),
|
||||||
.size = glm::vec3(4, 1.2, 2),
|
.size = glm::vec3(4, 1.2, 2),
|
||||||
.color = glm::vec3(0.639216f, 0.635294f, 0.647059f),
|
.color = glm::vec3(0.639216f, 0.635294f, 0.647059f),
|
||||||
}));
|
}));
|
||||||
|
@ -128,14 +103,14 @@ MainWindow::MainWindow(QWidget *parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::ConnectSelectionChangeHandler() {
|
void MainWindow::ConnectSelectionChangeHandler() {
|
||||||
// connect(ui->explorerView->selectionModel(), &QItemSelectionModel::selectionChanged, this, [&](const QItemSelection &selected, const QItemSelection &deselected) {
|
connect(ui->explorerView->selectionModel(), &QItemSelectionModel::selectionChanged, this, [&](const QItemSelection &selected, const QItemSelection &deselected) {
|
||||||
// if (selected.count() == 0) return;
|
if (selected.count() == 0) return;
|
||||||
|
|
||||||
// std::optional<InstanceRef> inst = selected.count() == 0 ? std::nullopt
|
std::optional<InstanceRef> inst = selected.count() == 0 ? std::nullopt
|
||||||
// : std::make_optional(((Instance*)selected.indexes()[0].internalPointer())->shared_from_this());
|
: std::make_optional(((Instance*)selected.indexes()[0].internalPointer())->shared_from_this());
|
||||||
|
|
||||||
// ui->propertiesView->setSelected(inst);
|
ui->propertiesView->setSelected(inst);
|
||||||
// });
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::chrono::time_point lastTime = std::chrono::steady_clock::now();
|
static std::chrono::time_point lastTime = std::chrono::steady_clock::now();
|
||||||
|
@ -154,25 +129,11 @@ void MainWindow::timerEvent(QTimerEvent* evt) {
|
||||||
ui->mainWidget->updateCycle();
|
ui->mainWidget->updateCycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::updateToolbars() {
|
void MainWindow::updateSelectedTool() {
|
||||||
ui->actionToolSelect->setChecked(selectedTool == SelectedTool::SELECT);
|
ui->actionToolSelect->setChecked(selectedTool == SelectedTool::SELECT);
|
||||||
ui->actionToolMove->setChecked(selectedTool == SelectedTool::MOVE);
|
ui->actionToolMove->setChecked(selectedTool == SelectedTool::MOVE);
|
||||||
ui->actionToolScale->setChecked(selectedTool == SelectedTool::SCALE);
|
ui->actionToolScale->setChecked(selectedTool == SelectedTool::SCALE);
|
||||||
ui->actionToolRotate->setChecked(selectedTool == SelectedTool::ROTATE);
|
ui->actionToolRotate->setChecked(selectedTool == SelectedTool::ROTATE);
|
||||||
|
|
||||||
ui->actionGridSnap1->setChecked(snappingMode == GridSnappingMode::SNAP_1_STUD);
|
|
||||||
ui->actionGridSnap05->setChecked(snappingMode == GridSnappingMode::SNAP_05_STUDS);
|
|
||||||
ui->actionGridSnapOff->setChecked(snappingMode == GridSnappingMode::SNAP_OFF);
|
|
||||||
|
|
||||||
// editorToolHandles->worldMode = false;
|
|
||||||
if (selectedTool == SelectedTool::MOVE) editorToolHandles->worldMode = true;
|
|
||||||
if (selectedTool == SelectedTool::SCALE) editorToolHandles->worldMode = false;
|
|
||||||
editorToolHandles->active = selectedTool != SelectedTool::SELECT;
|
|
||||||
editorToolHandles->handlesType =
|
|
||||||
selectedTool == SelectedTool::MOVE ? HandlesType::MoveHandles
|
|
||||||
: selectedTool == SelectedTool::SCALE ? HandlesType::ScaleHandles
|
|
||||||
: selectedTool == SelectedTool::ROTATE ? HandlesType::RotateHandles
|
|
||||||
: HandlesType::ScaleHandles;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow()
|
MainWindow::~MainWindow()
|
||||||
|
|
|
@ -8,19 +8,6 @@
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
|
|
||||||
enum SelectedTool {
|
|
||||||
SELECT,
|
|
||||||
MOVE,
|
|
||||||
SCALE,
|
|
||||||
ROTATE,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum GridSnappingMode {
|
|
||||||
SNAP_1_STUD,
|
|
||||||
SNAP_05_STUDS,
|
|
||||||
SNAP_OFF,
|
|
||||||
};
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class MainWindow;
|
class MainWindow;
|
||||||
|
@ -35,14 +22,11 @@ public:
|
||||||
MainWindow(QWidget *parent = nullptr);
|
MainWindow(QWidget *parent = nullptr);
|
||||||
~MainWindow();
|
~MainWindow();
|
||||||
|
|
||||||
SelectedTool selectedTool;
|
|
||||||
GridSnappingMode snappingMode;
|
|
||||||
|
|
||||||
Ui::MainWindow *ui;
|
Ui::MainWindow *ui;
|
||||||
private:
|
private:
|
||||||
QBasicTimer timer;
|
QBasicTimer timer;
|
||||||
|
|
||||||
void updateToolbars();
|
void updateSelectedTool();
|
||||||
void timerEvent(QTimerEvent*) override;
|
void timerEvent(QTimerEvent*) override;
|
||||||
void ConnectSelectionChangeHandler();
|
void ConnectSelectionChangeHandler();
|
||||||
};
|
};
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>1027</width>
|
<width>1027</width>
|
||||||
<height>22</height>
|
<height>29</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QMenu" name="menuFile">
|
<widget class="QMenu" name="menuFile">
|
||||||
|
@ -115,10 +115,6 @@
|
||||||
<addaction name="actionToolScale"/>
|
<addaction name="actionToolScale"/>
|
||||||
<addaction name="actionToolRotate"/>
|
<addaction name="actionToolRotate"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionGridSnap1"/>
|
|
||||||
<addaction name="actionGridSnap05"/>
|
|
||||||
<addaction name="actionGridSnapOff"/>
|
|
||||||
<addaction name="separator"/>
|
|
||||||
<addaction name="actionToggleSimulation"/>
|
<addaction name="actionToggleSimulation"/>
|
||||||
</widget>
|
</widget>
|
||||||
<action name="actionAddPart">
|
<action name="actionAddPart">
|
||||||
|
@ -261,60 +257,6 @@
|
||||||
<string>F5</string>
|
<string>F5</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionGridSnap1">
|
|
||||||
<property name="checkable">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="icon">
|
|
||||||
<iconset>
|
|
||||||
<normaloff>assets/icons/editor/snap1.png</normaloff>assets/icons/editor/snap1.png</iconset>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>1-Stud Snapping</string>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Set grid snapping to 1 stud</string>
|
|
||||||
</property>
|
|
||||||
<property name="menuRole">
|
|
||||||
<enum>QAction::MenuRole::NoRole</enum>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionGridSnap05">
|
|
||||||
<property name="checkable">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="icon">
|
|
||||||
<iconset>
|
|
||||||
<normaloff>assets/icons/editor/snap05.png</normaloff>assets/icons/editor/snap05.png</iconset>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>1/2-Stud Snapping</string>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Set grid snapping to 1/2 studs</string>
|
|
||||||
</property>
|
|
||||||
<property name="menuRole">
|
|
||||||
<enum>QAction::MenuRole::NoRole</enum>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionGridSnapOff">
|
|
||||||
<property name="checkable">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="icon">
|
|
||||||
<iconset>
|
|
||||||
<normaloff>assets/icons/editor/snapoff.png</normaloff>assets/icons/editor/snapoff.png</iconset>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>No Grid Snapping</string>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Turn grid snapping off</string>
|
|
||||||
</property>
|
|
||||||
<property name="menuRole">
|
|
||||||
<enum>QAction::MenuRole::NoRole</enum>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
#include "qabstractitemmodel.h"
|
#include "qabstractitemmodel.h"
|
||||||
#include "qaction.h"
|
#include "qaction.h"
|
||||||
#include "qnamespace.h"
|
#include "qnamespace.h"
|
||||||
#include <qitemselectionmodel.h>
|
|
||||||
|
|
||||||
ExplorerView::ExplorerView(QWidget* parent):
|
ExplorerView::ExplorerView(QWidget* parent):
|
||||||
QTreeView(parent),
|
QTreeView(parent),
|
||||||
|
@ -33,23 +32,7 @@ ExplorerView::ExplorerView(QWidget* parent):
|
||||||
contextMenu.exec(this->viewport()->mapToGlobal(point));
|
contextMenu.exec(this->viewport()->mapToGlobal(point));
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(selectionModel(), &QItemSelectionModel::selectionChanged, this, [&](const QItemSelection &selected, const QItemSelection &deselected) {
|
|
||||||
std::vector<InstanceRefWeak> selectedInstances;
|
|
||||||
selectedInstances.reserve(selected.count()); // This doesn't reserve everything, but should enhance things anyway
|
|
||||||
|
|
||||||
for (auto range : selected) {
|
|
||||||
for (auto index : range.indexes()) {
|
|
||||||
selectedInstances.push_back(reinterpret_cast<Instance*>(index.internalPointer())->weak_from_this());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
::setSelection(selectedInstances, true);
|
|
||||||
});
|
|
||||||
|
|
||||||
addSelectionListener([&](auto oldSelection, auto newSelection, bool fromExplorer) {
|
addSelectionListener([&](auto oldSelection, auto newSelection, bool fromExplorer) {
|
||||||
// It's from us, ignore it.
|
|
||||||
if (fromExplorer) return;
|
|
||||||
|
|
||||||
this->clearSelection();
|
this->clearSelection();
|
||||||
for (InstanceRefWeak inst : newSelection) {
|
for (InstanceRefWeak inst : newSelection) {
|
||||||
if (inst.expired()) continue;
|
if (inst.expired()) continue;
|
||||||
|
|
|
@ -56,10 +56,10 @@ bool PropertiesModel::setData(const QModelIndex &index, const QVariant &value, i
|
||||||
|
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case Qt::EditRole:
|
case Qt::EditRole:
|
||||||
if (!meta.type->fromString)
|
if (meta.type != &Data::String::TYPE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
selectedItem->SetPropertyValue(propertyName, meta.type->fromString(value.toString().toStdString()));
|
selectedItem->SetPropertyValue(propertyName, value.toString().toStdString());
|
||||||
return true;
|
return true;
|
||||||
case Qt::CheckStateRole:
|
case Qt::CheckStateRole:
|
||||||
if (meta.type != &Data::Bool::TYPE)
|
if (meta.type != &Data::Bool::TYPE)
|
||||||
|
|
|
@ -8,7 +8,6 @@ Camera camera(glm::vec3(0.0, 0.0, 3.0));
|
||||||
std::shared_ptr<DataModel> dataModel = DataModel::New();
|
std::shared_ptr<DataModel> dataModel = DataModel::New();
|
||||||
std::optional<HierarchyPreUpdateHandler> hierarchyPreUpdateHandler;
|
std::optional<HierarchyPreUpdateHandler> hierarchyPreUpdateHandler;
|
||||||
std::optional<HierarchyPostUpdateHandler> hierarchyPostUpdateHandler;
|
std::optional<HierarchyPostUpdateHandler> hierarchyPostUpdateHandler;
|
||||||
std::shared_ptr<Handles> editorToolHandles = Handles::New();
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<InstanceRefWeak> currentSelection;
|
std::vector<InstanceRefWeak> currentSelection;
|
|
@ -1,6 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "objects/base/instance.h"
|
#include "objects/base/instance.h"
|
||||||
#include "objects/handles.h"
|
|
||||||
#include "objects/workspace.h"
|
#include "objects/workspace.h"
|
||||||
#include "camera.h"
|
#include "camera.h"
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
@ -19,7 +18,6 @@ extern std::shared_ptr<DataModel> dataModel;
|
||||||
inline std::shared_ptr<Workspace> workspace() { return std::dynamic_pointer_cast<Workspace>(dataModel->services["Workspace"]); }
|
inline std::shared_ptr<Workspace> workspace() { return std::dynamic_pointer_cast<Workspace>(dataModel->services["Workspace"]); }
|
||||||
extern std::optional<HierarchyPreUpdateHandler> hierarchyPreUpdateHandler;
|
extern std::optional<HierarchyPreUpdateHandler> hierarchyPreUpdateHandler;
|
||||||
extern std::optional<HierarchyPostUpdateHandler> hierarchyPostUpdateHandler;
|
extern std::optional<HierarchyPostUpdateHandler> hierarchyPostUpdateHandler;
|
||||||
extern std::shared_ptr<Handles> editorToolHandles;
|
|
||||||
|
|
||||||
void setSelection(std::vector<InstanceRefWeak> newSelection, bool fromExplorer = false);
|
void setSelection(std::vector<InstanceRefWeak> newSelection, bool fromExplorer = false);
|
||||||
const std::vector<InstanceRefWeak> getSelection();
|
const std::vector<InstanceRefWeak> getSelection();
|
|
@ -4,7 +4,7 @@
|
||||||
#define IMPL_WRAPPER_CLASS(CLASS_NAME, WRAPPED_TYPE, TYPE_NAME) Data::CLASS_NAME::CLASS_NAME(WRAPPED_TYPE in) : value(in) {} \
|
#define IMPL_WRAPPER_CLASS(CLASS_NAME, WRAPPED_TYPE, TYPE_NAME) Data::CLASS_NAME::CLASS_NAME(WRAPPED_TYPE in) : value(in) {} \
|
||||||
Data::CLASS_NAME::~CLASS_NAME() = default; \
|
Data::CLASS_NAME::~CLASS_NAME() = default; \
|
||||||
Data::CLASS_NAME::operator const WRAPPED_TYPE() const { return value; } \
|
Data::CLASS_NAME::operator const WRAPPED_TYPE() const { return value; } \
|
||||||
const Data::TypeInfo Data::CLASS_NAME::TYPE = { .name = TYPE_NAME, .deserializer = &Data::CLASS_NAME::Deserialize, .fromString = &Data::CLASS_NAME::FromString }; \
|
const Data::TypeInfo Data::CLASS_NAME::TYPE = { .name = TYPE_NAME, .deserializer = &Data::CLASS_NAME::Deserialize }; \
|
||||||
const Data::TypeInfo& Data::CLASS_NAME::GetType() const { return Data::CLASS_NAME::TYPE; }; \
|
const Data::TypeInfo& Data::CLASS_NAME::GetType() const { return Data::CLASS_NAME::TYPE; }; \
|
||||||
void Data::CLASS_NAME::Serialize(pugi::xml_node* node) const { node->text().set(std::string(this->ToString())); }
|
void Data::CLASS_NAME::Serialize(pugi::xml_node* node) const { node->text().set(std::string(this->ToString())); }
|
||||||
|
|
||||||
|
@ -45,11 +45,6 @@ Data::Variant Data::Bool::Deserialize(pugi::xml_node* node) {
|
||||||
return Data::Bool(node->text().as_bool());
|
return Data::Bool(node->text().as_bool());
|
||||||
}
|
}
|
||||||
|
|
||||||
Data::Variant Data::Bool::FromString(std::string string) {
|
|
||||||
return Data::Bool(string[0] == 't' || string[0] == 'T' || string[0] == '1' || string[0] == 'y' || string[0] == 'Y');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const Data::String Data::Int::ToString() const {
|
const Data::String Data::Int::ToString() const {
|
||||||
return Data::String(std::to_string(value));
|
return Data::String(std::to_string(value));
|
||||||
}
|
}
|
||||||
|
@ -58,11 +53,6 @@ Data::Variant Data::Int::Deserialize(pugi::xml_node* node) {
|
||||||
return Data::Int(node->text().as_int());
|
return Data::Int(node->text().as_int());
|
||||||
}
|
}
|
||||||
|
|
||||||
Data::Variant Data::Int::FromString(std::string string) {
|
|
||||||
return Data::Int(std::stoi(string));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const Data::String Data::Float::ToString() const {
|
const Data::String Data::Float::ToString() const {
|
||||||
return Data::String(std::to_string(value));
|
return Data::String(std::to_string(value));
|
||||||
}
|
}
|
||||||
|
@ -71,19 +61,10 @@ Data::Variant Data::Float::Deserialize(pugi::xml_node* node) {
|
||||||
return Data::Float(node->text().as_float());
|
return Data::Float(node->text().as_float());
|
||||||
}
|
}
|
||||||
|
|
||||||
Data::Variant Data::Float::FromString(std::string string) {
|
|
||||||
return Data::Float(std::stof(string));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const Data::String Data::String::ToString() const {
|
const Data::String Data::String::ToString() const {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Data::Variant Data::String::Deserialize(pugi::xml_node* node) {
|
Data::Variant Data::String::Deserialize(pugi::xml_node* node) {
|
||||||
return Data::String(node->text().as_string());
|
return Data::String(node->text().as_string());
|
||||||
}
|
|
||||||
|
|
||||||
Data::Variant Data::String::FromString(std::string string) {
|
|
||||||
return Data::String(string);
|
|
||||||
}
|
}
|
|
@ -16,18 +16,15 @@ public: \
|
||||||
virtual const Data::String ToString() const override; \
|
virtual const Data::String ToString() const override; \
|
||||||
virtual void Serialize(pugi::xml_node* node) const override; \
|
virtual void Serialize(pugi::xml_node* node) const override; \
|
||||||
static Data::Variant Deserialize(pugi::xml_node* node); \
|
static Data::Variant Deserialize(pugi::xml_node* node); \
|
||||||
static Data::Variant FromString(std::string); \
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
class Variant;
|
class Variant;
|
||||||
typedef std::function<Data::Variant(pugi::xml_node*)> Deserializer;
|
typedef std::function<Data::Variant(pugi::xml_node*)> Deserializer;
|
||||||
typedef std::function<Data::Variant(std::string)> FromString;
|
|
||||||
|
|
||||||
struct TypeInfo {
|
struct TypeInfo {
|
||||||
std::string name;
|
std::string name;
|
||||||
Deserializer deserializer;
|
Deserializer deserializer;
|
||||||
FromString fromString;
|
|
||||||
TypeInfo(const TypeInfo&) = delete;
|
TypeInfo(const TypeInfo&) = delete;
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,16 +2,11 @@
|
||||||
#include "datatypes/vector.h"
|
#include "datatypes/vector.h"
|
||||||
#include "physics/util.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/matrix.hpp>
|
|
||||||
#include <reactphysics3d/mathematics/Transform.h>
|
#include <reactphysics3d/mathematics/Transform.h>
|
||||||
#define GLM_ENABLE_EXPERIMENTAL
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
#include <glm/gtx/euler_angles.hpp>
|
#include <glm/gtx/euler_angles.hpp>
|
||||||
// #include "meta.h" // IWYU pragma: keep
|
// #include "meta.h" // IWYU pragma: keep
|
||||||
|
|
||||||
const Data::CFrame Data::CFrame::IDENTITY(glm::vec3(0, 0, 0), glm::mat3(1.f));
|
|
||||||
const Data::CFrame Data::CFrame::YToZ(glm::vec3(0, 0, 0), glm::mat3(glm::vec3(1, 0, 0), glm::vec3(0, 0, 1), glm::vec3(0, 1, 0)));
|
|
||||||
|
|
||||||
Data::CFrame::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)
|
Data::CFrame::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)
|
||||||
: translation(x, y, z)
|
: translation(x, y, z)
|
||||||
, rotation({
|
, rotation({
|
||||||
|
@ -38,13 +33,17 @@ Data::CFrame::CFrame(const rp::Transform& transform) : Data::CFrame::CFrame(rpTo
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::mat3 lookAt(Data::Vector3 position, Data::Vector3 lookAt, Data::Vector3 up) {
|
glm::mat3 lookAt(Data::Vector3 position, Data::Vector3 lookAt, Data::Vector3 up) {
|
||||||
// https://github.com/sgorsten/linalg/issues/29#issuecomment-743989030
|
// https://github.com/sgorsten/glm/issues/29#issuecomment-743989030
|
||||||
Data::Vector3 f = (lookAt - position).Unit(); // Forward/Look
|
Data::Vector3 f = (lookAt - position).Unit(); // Forward/Look
|
||||||
Data::Vector3 u = up.Unit(); // Up
|
Data::Vector3 u = up.Unit(); // Up
|
||||||
Data::Vector3 s = f.Cross(u).Unit(); // Right
|
Data::Vector3 s = f.Cross(u).Unit(); // Right
|
||||||
u = s.Cross(f);
|
u = s.Cross(u);
|
||||||
|
|
||||||
return { s, u, f };
|
return {
|
||||||
|
{ s.X(), u.X(), -f.X() },
|
||||||
|
{ s.Y(), u.Y(), -f.Y() },
|
||||||
|
{ s.Z(), u.Z(), -f.Z() },
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Data::CFrame::CFrame(Data::Vector3 position, Data::Vector3 lookAt, Data::Vector3 up)
|
Data::CFrame::CFrame(Data::Vector3 position, Data::Vector3 lookAt, Data::Vector3 up)
|
||||||
|
@ -86,21 +85,8 @@ Data::CFrame Data::CFrame::FromEulerAnglesXYZ(Data::Vector3 vector) {
|
||||||
return Data::CFrame(Data::Vector3::ZERO, glm::column(mat, 2), (Data::Vector3)glm::column(mat, 1)); // Getting LookAt (3rd) and Up (2nd) vectors
|
return Data::CFrame(Data::Vector3::ZERO, glm::column(mat, 2), (Data::Vector3)glm::column(mat, 1)); // Getting LookAt (3rd) and Up (2nd) vectors
|
||||||
}
|
}
|
||||||
|
|
||||||
Data::CFrame Data::CFrame::Inverse() const {
|
|
||||||
return CFrame { -translation * glm::transpose(glm::inverse(rotation)), glm::inverse(rotation) };
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Operators
|
// Operators
|
||||||
|
|
||||||
Data::CFrame Data::CFrame::operator *(Data::CFrame otherFrame) const {
|
|
||||||
return CFrame { this->translation + this->rotation * otherFrame.translation, this->rotation * otherFrame.rotation };
|
|
||||||
}
|
|
||||||
|
|
||||||
Data::Vector3 Data::CFrame::operator *(Data::Vector3 vector) const {
|
|
||||||
return this->translation + this->rotation * vector;
|
|
||||||
}
|
|
||||||
|
|
||||||
Data::CFrame Data::CFrame::operator +(Data::Vector3 vector) const {
|
Data::CFrame Data::CFrame::operator +(Data::Vector3 vector) const {
|
||||||
return CFrame { this->translation + glm::vec3(vector), this->rotation };
|
return CFrame { this->translation + glm::vec3(vector), this->rotation };
|
||||||
}
|
}
|
|
@ -7,8 +7,6 @@
|
||||||
#include <glm/ext/vector_float3.hpp>
|
#include <glm/ext/vector_float3.hpp>
|
||||||
#include <glm/fwd.hpp>
|
#include <glm/fwd.hpp>
|
||||||
#include <glm/gtc/matrix_access.hpp>
|
#include <glm/gtc/matrix_access.hpp>
|
||||||
#include <glm/gtc/matrix_inverse.hpp>
|
|
||||||
#include <glm/matrix.hpp>
|
|
||||||
#include <reactphysics3d/mathematics/Transform.h>
|
#include <reactphysics3d/mathematics/Transform.h>
|
||||||
#include <reactphysics3d/reactphysics3d.h>
|
#include <reactphysics3d/reactphysics3d.h>
|
||||||
|
|
||||||
|
@ -30,9 +28,6 @@ namespace Data {
|
||||||
CFrame(Data::Vector3 position, Data::Vector3 lookAt, Data::Vector3 up = Data::Vector3(0, 1, 0));
|
CFrame(Data::Vector3 position, Data::Vector3 lookAt, Data::Vector3 up = Data::Vector3(0, 1, 0));
|
||||||
~CFrame();
|
~CFrame();
|
||||||
|
|
||||||
static const CFrame IDENTITY;
|
|
||||||
static const CFrame YToZ;
|
|
||||||
|
|
||||||
virtual const TypeInfo& GetType() const override;
|
virtual const TypeInfo& GetType() const override;
|
||||||
static const TypeInfo TYPE;
|
static const TypeInfo TYPE;
|
||||||
|
|
||||||
|
@ -46,21 +41,18 @@ namespace Data {
|
||||||
//inline static CFrame identity() { }
|
//inline static CFrame identity() { }
|
||||||
inline Vector3 Position() const { return translation; }
|
inline Vector3 Position() const { return translation; }
|
||||||
inline CFrame Rotation() const { return CFrame { glm::vec3(0, 0, 0), rotation }; }
|
inline CFrame Rotation() const { return CFrame { glm::vec3(0, 0, 0), rotation }; }
|
||||||
CFrame Inverse() const;
|
|
||||||
inline float X() const { return translation.x; }
|
inline float X() const { return translation.x; }
|
||||||
inline float Y() const { return translation.y; }
|
inline float Y() const { return translation.y; }
|
||||||
inline float Z() const { return translation.z; }
|
inline float Z() const { return translation.z; }
|
||||||
|
|
||||||
inline Vector3 RightVector() { return glm::column(rotation, 0); }
|
inline Vector3 RightVector() { return glm::column(rotation, 0); }
|
||||||
inline Vector3 UpVector() { return glm::column(rotation, 1); }
|
inline Vector3 UpVector() { return glm::column(rotation, 1); }
|
||||||
inline Vector3 LookVector() { return -glm::column(rotation, 2); }
|
inline Vector3 LookVector() { return glm::column(rotation, 2); }
|
||||||
|
|
||||||
Vector3 ToEulerAnglesXYZ();
|
Vector3 ToEulerAnglesXYZ();
|
||||||
static CFrame FromEulerAnglesXYZ(Data::Vector3);
|
static CFrame FromEulerAnglesXYZ(Data::Vector3);
|
||||||
|
|
||||||
// Operators
|
// Operators
|
||||||
Data::CFrame operator *(Data::CFrame) const;
|
|
||||||
Data::Vector3 operator *(Data::Vector3) const;
|
|
||||||
Data::CFrame operator +(Data::Vector3) const;
|
Data::CFrame operator +(Data::Vector3) const;
|
||||||
Data::CFrame operator -(Data::Vector3) const;
|
Data::CFrame operator -(Data::Vector3) const;
|
||||||
};
|
};
|
|
@ -25,14 +25,6 @@ Data::Vector3::operator glm::vec3() const { return vector; };
|
||||||
Data::Vector3::operator rp::Vector3() const { return rp::Vector3(X(), Y(), Z()); };
|
Data::Vector3::operator rp::Vector3() const { return rp::Vector3(X(), Y(), Z()); };
|
||||||
|
|
||||||
// Operators
|
// Operators
|
||||||
Data::Vector3 Data::Vector3::operator *(float scale) const {
|
|
||||||
return Data::Vector3(this->X() * scale, this->Y() * scale, this->Z() * scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
Data::Vector3 Data::Vector3::operator /(float scale) const {
|
|
||||||
return Data::Vector3(this->X() / scale, this->Y() / scale, this->Z() / scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
Data::Vector3 Data::Vector3::operator +(Data::Vector3 other) const {
|
Data::Vector3 Data::Vector3::operator +(Data::Vector3 other) const {
|
||||||
return Data::Vector3(this->X() + other.X(), this->Y() + other.Y(), this->Z() + other.Z());
|
return Data::Vector3(this->X() + other.X(), this->Y() + other.Y(), this->Z() + other.Z());
|
||||||
}
|
}
|
|
@ -40,8 +40,6 @@ namespace Data {
|
||||||
float Dot(Data::Vector3) const;
|
float Dot(Data::Vector3) const;
|
||||||
|
|
||||||
// Operators
|
// Operators
|
||||||
Data::Vector3 operator *(float) const;
|
|
||||||
Data::Vector3 operator /(float) const;
|
|
||||||
Data::Vector3 operator +(Data::Vector3) const;
|
Data::Vector3 operator +(Data::Vector3) const;
|
||||||
Data::Vector3 operator -(Data::Vector3) const;
|
Data::Vector3 operator -(Data::Vector3) const;
|
||||||
Data::Vector3 operator -() const;
|
Data::Vector3 operator -() const;
|
|
@ -10,8 +10,7 @@
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
// #include <../../include/expected.hpp>
|
#include <../include/expected.hpp>
|
||||||
#include <expected.hpp>
|
|
||||||
#include <pugixml.hpp>
|
#include <pugixml.hpp>
|
||||||
|
|
||||||
#include "member.h"
|
#include "member.h"
|
|
@ -69,37 +69,33 @@ Part::Part(PartConstructParams params): Instance(&TYPE), cframe(Data::CFrame(par
|
||||||
.type = &Data::Bool::TYPE,
|
.type = &Data::Bool::TYPE,
|
||||||
.codec = fieldCodecOf<Data::Bool, bool>(),
|
.codec = fieldCodecOf<Data::Bool, bool>(),
|
||||||
.updateCallback = memberFunctionOf(&Part::onUpdated, this)
|
.updateCallback = memberFunctionOf(&Part::onUpdated, this)
|
||||||
}}, { "Position", {
|
} }, { "Position", {
|
||||||
.backingField = &cframe,
|
.backingField = &cframe,
|
||||||
.type = &Data::Vector3::TYPE,
|
.type = &Data::Vector3::TYPE,
|
||||||
.codec = cframePositionCodec(),
|
.codec = cframePositionCodec(),
|
||||||
.updateCallback = memberFunctionOf(&Part::onUpdated, this),
|
.updateCallback = memberFunctionOf(&Part::onUpdated, this),
|
||||||
.flags = PropertyFlags::PROP_NOSAVE
|
.flags = PropertyFlags::PROP_NOSAVE
|
||||||
}}, { "Rotation", {
|
} }, { "Rotation", {
|
||||||
.backingField = &cframe,
|
.backingField = &cframe,
|
||||||
.type = &Data::Vector3::TYPE,
|
.type = &Data::Vector3::TYPE,
|
||||||
.codec = cframeRotationCodec(),
|
.codec = cframeRotationCodec(),
|
||||||
.updateCallback = memberFunctionOf(&Part::onUpdated, this),
|
.updateCallback = memberFunctionOf(&Part::onUpdated, this),
|
||||||
.flags = PropertyFlags::PROP_NOSAVE
|
.flags = PropertyFlags::PROP_NOSAVE
|
||||||
}}, { "CFrame", {
|
} }, { "CFrame", {
|
||||||
.backingField = &cframe,
|
.backingField = &cframe,
|
||||||
.type = &Data::CFrame::TYPE,
|
.type = &Data::CFrame::TYPE,
|
||||||
.codec = fieldCodecOf<Data::CFrame>(),
|
.codec = fieldCodecOf<Data::CFrame>(),
|
||||||
.updateCallback = memberFunctionOf(&Part::onUpdated, this),
|
.updateCallback = memberFunctionOf(&Part::onUpdated, this),
|
||||||
}}, { "Size", {
|
} }, { "Size", {
|
||||||
.backingField = &size,
|
.backingField = &size,
|
||||||
.type = &Data::Vector3::TYPE,
|
.type = &Data::Vector3::TYPE,
|
||||||
.codec = fieldCodecOf<Data::Vector3, glm::vec3>(),
|
.codec = fieldCodecOf<Data::Vector3, glm::vec3>(),
|
||||||
.updateCallback = memberFunctionOf(&Part::onUpdated, this)
|
.updateCallback = memberFunctionOf(&Part::onUpdated, this)
|
||||||
}}, { "Color", {
|
} }, { "Color", {
|
||||||
.backingField = &color,
|
.backingField = &color,
|
||||||
.type = &Data::Color3::TYPE,
|
.type = &Data::Color3::TYPE,
|
||||||
.codec = fieldCodecOf<Data::Color3>(),
|
.codec = fieldCodecOf<Data::Color3>(),
|
||||||
}}, { "Transparency", {
|
} }
|
||||||
.backingField = &transparency,
|
|
||||||
.type = &Data::Float::TYPE,
|
|
||||||
.codec = fieldCodecOf<Data::Float, float>(),
|
|
||||||
}}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -32,7 +32,6 @@ public:
|
||||||
Data::CFrame cframe;
|
Data::CFrame cframe;
|
||||||
glm::vec3 size;
|
glm::vec3 size;
|
||||||
Data::Color3 color;
|
Data::Color3 color;
|
||||||
float transparency = 0.f;
|
|
||||||
bool selected = false;
|
bool selected = false;
|
||||||
|
|
||||||
bool anchored = false;
|
bool anchored = false;
|
|
@ -6,7 +6,6 @@
|
||||||
#include <reactphysics3d/collision/shapes/BoxShape.h>
|
#include <reactphysics3d/collision/shapes/BoxShape.h>
|
||||||
#include <reactphysics3d/collision/shapes/CollisionShape.h>
|
#include <reactphysics3d/collision/shapes/CollisionShape.h>
|
||||||
#include <reactphysics3d/components/RigidBodyComponents.h>
|
#include <reactphysics3d/components/RigidBodyComponents.h>
|
||||||
#include <reactphysics3d/configuration.h>
|
|
||||||
#include <reactphysics3d/engine/EventListener.h>
|
#include <reactphysics3d/engine/EventListener.h>
|
||||||
#include <reactphysics3d/engine/PhysicsCommon.h>
|
#include <reactphysics3d/engine/PhysicsCommon.h>
|
||||||
#include <reactphysics3d/mathematics/Quaternion.h>
|
#include <reactphysics3d/mathematics/Quaternion.h>
|
||||||
|
@ -40,9 +39,6 @@ void simulationInit() {
|
||||||
world = physicsCommon->createPhysicsWorld();
|
world = physicsCommon->createPhysicsWorld();
|
||||||
|
|
||||||
world->setGravity(rp::Vector3(0, -196.2, 0));
|
world->setGravity(rp::Vector3(0, -196.2, 0));
|
||||||
// world->setContactsPositionCorrectionTechnique(rp3d::ContactsPositionCorrectionTechnique::BAUMGARTE_CONTACTS);
|
|
||||||
world->setNbIterationsPositionSolver(2000);
|
|
||||||
world->setNbIterationsVelocitySolver(2000);
|
|
||||||
|
|
||||||
world->setEventListener(&eventListener);
|
world->setEventListener(&eventListener);
|
||||||
}
|
}
|
||||||
|
@ -73,7 +69,7 @@ void syncPartPhysics(std::shared_ptr<Part> part) {
|
||||||
|
|
||||||
void physicsStep(float deltaTime) {
|
void physicsStep(float deltaTime) {
|
||||||
// Step the simulation a few steps
|
// Step the simulation a few steps
|
||||||
world->update(std::min(deltaTime / 2, (1/60.f)));
|
world->update(deltaTime / 2);
|
||||||
|
|
||||||
// Naive implementation. Parts are only considered so if they are just under Workspace
|
// Naive implementation. Parts are only considered so if they are just under Workspace
|
||||||
// TODO: Add list of tracked parts in workspace based on their ancestry using inWorkspace property of Instance
|
// TODO: Add list of tracked parts in workspace based on their ancestry using inWorkspace property of Instance
|
47
src/rendering/defaultmeshes.cpp
Normal file
47
src/rendering/defaultmeshes.cpp
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#include "defaultmeshes.h"
|
||||||
|
|
||||||
|
Mesh* CUBE_MESH;
|
||||||
|
|
||||||
|
void initMeshes() {
|
||||||
|
static float vertices[] = {
|
||||||
|
// positions // normals // texture coords
|
||||||
|
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
|
||||||
|
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
|
||||||
|
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
|
||||||
|
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
|
||||||
|
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
|
||||||
|
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
|
||||||
|
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
|
||||||
|
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
|
||||||
|
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
|
||||||
|
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
|
||||||
|
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
|
||||||
|
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
|
||||||
|
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
|
||||||
|
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
|
||||||
|
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
|
||||||
|
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
|
||||||
|
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
|
||||||
|
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
|
||||||
|
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
|
||||||
|
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
|
||||||
|
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
|
||||||
|
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
|
||||||
|
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
|
||||||
|
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
|
||||||
|
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
|
||||||
|
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f,
|
||||||
|
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
|
||||||
|
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
|
||||||
|
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f,
|
||||||
|
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
|
||||||
|
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
|
||||||
|
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
|
||||||
|
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
|
||||||
|
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
|
||||||
|
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
|
||||||
|
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
|
||||||
|
};
|
||||||
|
|
||||||
|
CUBE_MESH = new Mesh(36, vertices);
|
||||||
|
}
|
|
@ -2,7 +2,5 @@
|
||||||
#include "mesh.h"
|
#include "mesh.h"
|
||||||
|
|
||||||
extern Mesh* CUBE_MESH;
|
extern Mesh* CUBE_MESH;
|
||||||
extern Mesh* SPHERE_MESH;
|
|
||||||
extern Mesh* ARROW_MESH;
|
|
||||||
|
|
||||||
void initMeshes();
|
void initMeshes();
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#include "mesh.h"
|
#include "mesh.h"
|
||||||
|
|
||||||
Mesh::Mesh(int vertexCount, float *vertices) : vertexCount(vertexCount) {
|
Mesh::Mesh(int vertexCount, float *vertices) {
|
||||||
// Generate buffers
|
// Generate buffers
|
||||||
glGenBuffers(1, &VBO);
|
glGenBuffers(1, &VBO);
|
||||||
glGenVertexArrays(1, &VAO);
|
glGenVertexArrays(1, &VAO);
|
|
@ -4,8 +4,6 @@ class Mesh {
|
||||||
unsigned int VBO, VAO;
|
unsigned int VBO, VAO;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int vertexCount;
|
|
||||||
|
|
||||||
Mesh(int vertexCount, float* vertices);
|
Mesh(int vertexCount, float* vertices);
|
||||||
~Mesh();
|
~Mesh();
|
||||||
void bind();
|
void bind();
|
|
@ -5,13 +5,11 @@
|
||||||
#include <glm/ext.hpp>
|
#include <glm/ext.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/vector_float3.hpp>
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/trigonometric.hpp>
|
#include <glm/trigonometric.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "datatypes/cframe.h"
|
|
||||||
#include "physics/util.h"
|
#include "physics/util.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
#include "mesh.h"
|
#include "mesh.h"
|
||||||
|
@ -25,10 +23,8 @@
|
||||||
|
|
||||||
#include "renderer.h"
|
#include "renderer.h"
|
||||||
|
|
||||||
Shader* shader = NULL;
|
Shader *shader = NULL;
|
||||||
Shader* skyboxShader = NULL;
|
Shader *skyboxShader = NULL;
|
||||||
Shader* handleShader = NULL;
|
|
||||||
Shader* identityShader = NULL;
|
|
||||||
extern Camera camera;
|
extern Camera camera;
|
||||||
Skybox* skyboxTexture = NULL;
|
Skybox* skyboxTexture = NULL;
|
||||||
Texture3D* studsTexture = NULL;
|
Texture3D* studsTexture = NULL;
|
||||||
|
@ -58,20 +54,13 @@ void renderInit(GLFWwindow* window, int width, int height) {
|
||||||
|
|
||||||
studsTexture = new Texture3D("assets/textures/studs.png", 128, 128, 6, GL_RGBA);
|
studsTexture = new Texture3D("assets/textures/studs.png", 128, 128, 6, GL_RGBA);
|
||||||
|
|
||||||
// Compile shaders
|
// Compile shader
|
||||||
shader = new Shader("assets/shaders/phong.vs", "assets/shaders/phong.fs");
|
shader = new Shader("assets/shaders/phong.vs", "assets/shaders/phong.fs");
|
||||||
skyboxShader = new Shader("assets/shaders/skybox.vs", "assets/shaders/skybox.fs");
|
skyboxShader = new Shader("assets/shaders/skybox.vs", "assets/shaders/skybox.fs");
|
||||||
handleShader = new Shader("assets/shaders/handle.vs", "assets/shaders/handle.fs");
|
|
||||||
identityShader = new Shader("assets/shaders/identity.vs", "assets/shaders/identity.fs");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderParts() {
|
void renderParts() {
|
||||||
glDepthMask(GL_TRUE);
|
glDepthMask(GL_TRUE);
|
||||||
glEnable(GL_CULL_FACE);
|
|
||||||
glCullFace(GL_BACK);
|
|
||||||
glFrontFace(GL_CW);
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
|
|
||||||
// Use shader
|
// Use shader
|
||||||
shader->use();
|
shader->use();
|
||||||
|
@ -79,7 +68,7 @@ void renderParts() {
|
||||||
// shader->set("lightColor", glm::vec3(1.0f, 1.0f, 1.0f));
|
// shader->set("lightColor", glm::vec3(1.0f, 1.0f, 1.0f));
|
||||||
|
|
||||||
// view/projection transformations
|
// view/projection transformations
|
||||||
glm::mat4 projection = glm::perspective(glm::radians(45.f), (float)viewportWidth / (float)viewportHeight, 0.1f, 1000.0f);
|
glm::mat4 projection = glm::perspective(glm::radians(45.f), (float)viewportWidth / (float)viewportHeight, 0.1f, 100.0f);
|
||||||
glm::mat4 view = camera.getLookAt();
|
glm::mat4 view = camera.getLookAt();
|
||||||
shader->set("projection", projection);
|
shader->set("projection", projection);
|
||||||
shader->set("view", view);
|
shader->set("view", view);
|
||||||
|
@ -116,40 +105,27 @@ void renderParts() {
|
||||||
// Pass in the camera position
|
// Pass in the camera position
|
||||||
shader->set("viewPos", camera.cameraPos);
|
shader->set("viewPos", camera.cameraPos);
|
||||||
|
|
||||||
// Sort by nearest
|
// TODO: Same as todo in src/physics/simulation.cpp
|
||||||
std::map<float, std::shared_ptr<Part>> sorted;
|
|
||||||
for (InstanceRef inst : workspace()->GetChildren()) {
|
for (InstanceRef inst : workspace()->GetChildren()) {
|
||||||
if (inst->GetClass()->className != "Part") continue;
|
if (inst->GetClass()->className != "Part") continue;
|
||||||
std::shared_ptr<Part> part = std::dynamic_pointer_cast<Part>(inst);
|
std::shared_ptr<Part> part = std::dynamic_pointer_cast<Part>(inst);
|
||||||
if (part->transparency > 0.00001) {
|
|
||||||
float distance = glm::length(glm::vec3(Data::Vector3(camera.cameraPos) - part->position()));
|
|
||||||
sorted[distance] = part;
|
|
||||||
} else {
|
|
||||||
glm::mat4 model = part->cframe;
|
|
||||||
if (part->name == "camera") model = camera.getLookAt();
|
|
||||||
model = glm::scale(model, part->size);
|
|
||||||
shader->set("model", model);
|
|
||||||
shader->set("material", Material {
|
|
||||||
.diffuse = part->color,
|
|
||||||
.specular = glm::vec3(0.5f, 0.5f, 0.5f),
|
|
||||||
.shininess = 16.0f,
|
|
||||||
});
|
|
||||||
glm::mat3 normalMatrix = glm::mat3(glm::transpose(glm::inverse(model)));
|
|
||||||
shader->set("normalMatrix", normalMatrix);
|
|
||||||
shader->set("texScale", part->size);
|
|
||||||
shader->set("transparency", part->transparency);
|
|
||||||
|
|
||||||
CUBE_MESH->bind();
|
// if (inst->name == "Target") printf("(%f,%f,%f):(%f,%f,%f;%f,%f,%f;%f,%f,%f)\n",
|
||||||
glDrawArrays(GL_TRIANGLES, 0, CUBE_MESH->vertexCount);
|
// part->cframe.X(),
|
||||||
}
|
// part->cframe.Y(),
|
||||||
}
|
// part->cframe.Z(),
|
||||||
|
// part->cframe.RightVector().X(),
|
||||||
|
// part->cframe.UpVector().X(),
|
||||||
|
// part->cframe.LookVector().X(),
|
||||||
|
// part->cframe.RightVector().Y(),
|
||||||
|
// part->cframe.UpVector().Y(),
|
||||||
|
// part->cframe.LookVector().Y(),
|
||||||
|
// part->cframe.RightVector().Z(),
|
||||||
|
// part->cframe.UpVector().Z(),
|
||||||
|
// part->cframe.LookVector().Z()
|
||||||
|
// );
|
||||||
|
|
||||||
// TODO: Same as todo in src/physics/simulation.cpp
|
|
||||||
// According to LearnOpenGL, std::map automatically sorts its contents.
|
|
||||||
for (std::map<float, std::shared_ptr<Part>>::reverse_iterator it = sorted.rbegin(); it != sorted.rend(); it++) {
|
|
||||||
std::shared_ptr<Part> part = it->second;
|
|
||||||
glm::mat4 model = part->cframe;
|
glm::mat4 model = part->cframe;
|
||||||
if (part->name == "camera") model = camera.getLookAt();
|
|
||||||
model = glm::scale(model, part->size);
|
model = glm::scale(model, part->size);
|
||||||
shader->set("model", model);
|
shader->set("model", model);
|
||||||
shader->set("material", Material {
|
shader->set("material", Material {
|
||||||
|
@ -160,20 +136,18 @@ void renderParts() {
|
||||||
glm::mat3 normalMatrix = glm::mat3(glm::transpose(glm::inverse(model)));
|
glm::mat3 normalMatrix = glm::mat3(glm::transpose(glm::inverse(model)));
|
||||||
shader->set("normalMatrix", normalMatrix);
|
shader->set("normalMatrix", normalMatrix);
|
||||||
shader->set("texScale", part->size);
|
shader->set("texScale", part->size);
|
||||||
shader->set("transparency", part->transparency);
|
|
||||||
|
|
||||||
CUBE_MESH->bind();
|
CUBE_MESH->bind();
|
||||||
glDrawArrays(GL_TRIANGLES, 0, CUBE_MESH->vertexCount);
|
glDrawArrays(GL_TRIANGLES, 0, 36);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderSkyBox() {
|
void renderSkyBox() {
|
||||||
glDepthMask(GL_FALSE);
|
glDepthMask(GL_FALSE);
|
||||||
glCullFace(GL_FRONT);
|
|
||||||
|
|
||||||
skyboxShader->use();
|
skyboxShader->use();
|
||||||
|
|
||||||
glm::mat4 projection = glm::perspective(glm::radians(45.f), (float)viewportWidth / (float)viewportHeight, 0.1f, 1000.0f);
|
glm::mat4 projection = glm::perspective(glm::radians(45.f), (float)viewportWidth / (float)viewportHeight, 0.1f, 100.0f);
|
||||||
// Remove translation component of view, making us always at (0, 0, 0)
|
// Remove translation component of view, making us always at (0, 0, 0)
|
||||||
glm::mat4 view = glm::mat4(glm::mat3(camera.getLookAt()));
|
glm::mat4 view = glm::mat4(glm::mat3(camera.getLookAt()));
|
||||||
|
|
||||||
|
@ -186,80 +160,11 @@ void renderSkyBox() {
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 36);
|
glDrawArrays(GL_TRIANGLES, 0, 36);
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderHandles() {
|
|
||||||
if (!editorToolHandles->adornee.has_value() || !editorToolHandles->active) return;
|
|
||||||
|
|
||||||
glDepthMask(GL_TRUE);
|
|
||||||
glCullFace(GL_BACK);
|
|
||||||
|
|
||||||
// Use shader
|
|
||||||
handleShader->use();
|
|
||||||
|
|
||||||
// view/projection transformations
|
|
||||||
glm::mat4 projection = glm::perspective(glm::radians(45.f), (float)viewportWidth / (float)viewportHeight, 0.1f, 1000.0f);
|
|
||||||
glm::mat4 view = camera.getLookAt();
|
|
||||||
handleShader->set("projection", projection);
|
|
||||||
handleShader->set("view", view);
|
|
||||||
handleShader->set("sunLight", DirLight {
|
|
||||||
.direction = glm::vec3(-0.2f, -1.0f, -0.3f),
|
|
||||||
.ambient = glm::vec3(0.2f, 0.2f, 0.2f),
|
|
||||||
.diffuse = glm::vec3(0.5f, 0.5f, 0.5f),
|
|
||||||
.specular = glm::vec3(1.0f, 1.0f, 1.0f),
|
|
||||||
});
|
|
||||||
handleShader->set("numPointLights", 0);
|
|
||||||
|
|
||||||
// Pass in the camera position
|
|
||||||
handleShader->set("viewPos", camera.cameraPos);
|
|
||||||
|
|
||||||
for (auto face : HandleFace::Faces) {
|
|
||||||
glm::mat4 model = editorToolHandles->GetCFrameOfHandle(face);
|
|
||||||
model = glm::scale(model, (glm::vec3)editorToolHandles->HandleSize(face));
|
|
||||||
handleShader->set("model", model);
|
|
||||||
handleShader->set("material", Material {
|
|
||||||
.diffuse = glm::abs(face.normal),
|
|
||||||
.specular = glm::vec3(0.5f, 0.5f, 0.5f),
|
|
||||||
.shininess = 16.0f,
|
|
||||||
});
|
|
||||||
glm::mat3 normalMatrix = glm::mat3(glm::transpose(glm::inverse(model)));
|
|
||||||
handleShader->set("normalMatrix", normalMatrix);
|
|
||||||
|
|
||||||
if (editorToolHandles->handlesType == HandlesType::MoveHandles) {
|
|
||||||
ARROW_MESH->bind();
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, ARROW_MESH->vertexCount);
|
|
||||||
} else {
|
|
||||||
SPHERE_MESH->bind();
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, SPHERE_MESH->vertexCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2d square overlay
|
|
||||||
identityShader->use();
|
|
||||||
identityShader->set("aColor", glm::vec3(0.f, 1.f, 1.f));
|
|
||||||
|
|
||||||
for (auto face : HandleFace::Faces) {
|
|
||||||
Data::CFrame cframe = editorToolHandles->GetCFrameOfHandle(face);
|
|
||||||
glm::vec4 screenPos = projection * view * glm::vec4((glm::vec3)cframe.Position(), 1.0f);
|
|
||||||
glm::vec3 ndcCoords = screenPos / screenPos.w;
|
|
||||||
|
|
||||||
float rad = 5;
|
|
||||||
float xRad = rad * 1/viewportWidth;
|
|
||||||
float yRad = rad * 1/viewportHeight;
|
|
||||||
|
|
||||||
glBegin(GL_QUADS);
|
|
||||||
glVertex3f(ndcCoords.x - xRad, ndcCoords.y - yRad, 0);
|
|
||||||
glVertex3f(ndcCoords.x + xRad, ndcCoords.y - yRad, 0);
|
|
||||||
glVertex3f(ndcCoords.x + xRad, ndcCoords.y + yRad, 0);
|
|
||||||
glVertex3f(ndcCoords.x - xRad, ndcCoords.y + yRad, 0);
|
|
||||||
glEnd();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void render(GLFWwindow* window) {
|
void render(GLFWwindow* window) {
|
||||||
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
|
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
renderSkyBox();
|
renderSkyBox();
|
||||||
renderHandles();
|
|
||||||
renderParts();
|
renderParts();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,78 +0,0 @@
|
||||||
#!/usr/bin/python3
|
|
||||||
|
|
||||||
# Default mesh generator
|
|
||||||
# Input from wavefront obj file
|
|
||||||
|
|
||||||
# Usage: ./genmesh.py mesh.obj > mesh.cpp
|
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
HEADER = """
|
|
||||||
static float CUBE_VERTICES[] = {
|
|
||||||
// positions // normals // texture coords
|
|
||||||
"""
|
|
||||||
|
|
||||||
FOOTER = """
|
|
||||||
};"""
|
|
||||||
|
|
||||||
file = open(sys.argv[1], "r")
|
|
||||||
|
|
||||||
vert_coords = []
|
|
||||||
vert_norms = []
|
|
||||||
vert_uvs = []
|
|
||||||
|
|
||||||
out_vertices = []
|
|
||||||
|
|
||||||
min_coords: tuple[float, float, float] | None = None
|
|
||||||
max_coords: tuple[float, float, float] | None = None
|
|
||||||
|
|
||||||
def normalize(x, y, z):
|
|
||||||
assert min_coords
|
|
||||||
assert max_coords
|
|
||||||
return ((x-max_coords[0])/(max_coords[0]-min_coords[0])+0.5, (y-max_coords[1])/(max_coords[1]-min_coords[1])+0.5, (z-max_coords[2])/(max_coords[2]-min_coords[2])+0.5)
|
|
||||||
|
|
||||||
for line in file:
|
|
||||||
if line.startswith('v '):
|
|
||||||
coords = line.split(' ')[1:]
|
|
||||||
coords = (float(coords[0]), float(coords[1]), float(coords[2]))
|
|
||||||
vert_coords.append(coords)
|
|
||||||
|
|
||||||
if not min_coords: min_coords = coords
|
|
||||||
if not max_coords: max_coords = coords
|
|
||||||
|
|
||||||
if coords[0] > max_coords[0]: max_coords = (coords[0], max_coords[1], max_coords[2])
|
|
||||||
if coords[1] > max_coords[1]: max_coords = (max_coords[0], coords[1], max_coords[2])
|
|
||||||
if coords[2] > max_coords[2]: max_coords = (max_coords[0], max_coords[1], coords[2])
|
|
||||||
|
|
||||||
if coords[0] < min_coords[0]: min_coords = (coords[0], min_coords[1], min_coords[2])
|
|
||||||
if coords[1] < min_coords[1]: min_coords = (min_coords[0], coords[1], min_coords[2])
|
|
||||||
if coords[2] < min_coords[2]: min_coords = (min_coords[0], min_coords[1], coords[2])
|
|
||||||
|
|
||||||
if line.startswith('vn '):
|
|
||||||
coords = line.split(' ')[1:]
|
|
||||||
vert_norms.append((float(coords[0]), float(coords[1]), float(coords[2])))
|
|
||||||
|
|
||||||
if line.startswith('vt '):
|
|
||||||
coords = line.split(' ')[1:]
|
|
||||||
vert_uvs.append((float(coords[0]), float(coords[1])))
|
|
||||||
|
|
||||||
if line.startswith('f '):
|
|
||||||
verts = line.split(' ')[1:]
|
|
||||||
for vert in verts:
|
|
||||||
coords, uv, normal = vert.split('/')
|
|
||||||
coords, uv, normal = int(coords), int(uv), int(normal)
|
|
||||||
coords, uv, normal = vert_coords[coords-1], vert_uvs[uv-1], vert_norms[normal-1]
|
|
||||||
|
|
||||||
coords = normalize(*coords)
|
|
||||||
# for coord in [*normal]:
|
|
||||||
# if coord > greatest_coord: greatest_coord = coord
|
|
||||||
# if coord < least_coord: least_coord = coord
|
|
||||||
|
|
||||||
out_vertices.append((coords, normal, uv))
|
|
||||||
|
|
||||||
print(HEADER)
|
|
||||||
|
|
||||||
for coords, normal, uv in out_vertices:
|
|
||||||
print(f"\t{coords[0]}, {coords[1]}, {coords[2]},\t{normal[0]}, {normal[1]}, {normal[2]},\t{uv[0]}, {uv[1]},")
|
|
||||||
|
|
||||||
print(FOOTER)
|
|
Loading…
Add table
Reference in a new issue