Compare commits

..

No commits in common. "e2054a51a8a622a47b9ad2b49987ca0f0a93178f" and "6d95cc8e1a1c2a823214a9be36e063d013e323bb" have entirely different histories.

61 changed files with 333 additions and 6865 deletions

View file

@ -1,3 +1,2 @@
CompileFlags:
Add: [-std=c++20]
Remove: [-mno-direct-extern-access]

View file

@ -1,27 +1,20 @@
# Building on Linux
You will need to install Qt and LLVM/libclang beforehand. All other packages will automatically be obtained through CPM.
For pre-requisite packages, check [deps.txt](./deps.txt)
ccache is highly recommended.
If your distribution does not provide ReactPhysics3D, you will have to build (and install) it yourself prior to this step
Use the following to generate the build files:
cmake -Bbuild .
> [!NOTE]
> Add -DCMAKE_BUILD_TYPE=Release to produce a release build
Then build the project using:
cmake --build build
The compiled binaries should then be located in `./build/bin/` and should be ready for redistribution without any further work.
If any of the compilation steps fail, or the binaries fail to execute, please create an issue so that this can be corrected.
# Building on Windows
The process is very similar on Windows
The project will be built using VCPKG and MSVC
## Pre-requisites
@ -29,7 +22,6 @@ The process is very similar on Windows
* Qt 6.8.3 or higher, with MSVC toolchain
* CMake
* Git (for cloning the repo, optional)
* LLVM/libclang 18.1.8+ (from https://github.com/llvm/llvm-project/releases/download/llvmorg-18.1.8/LLVM-18.1.8-win64.exe)
* QScintilla already built (see [docs/qscintilla.md](./docs/qscintilla.md)) *\*likely temporary\**
To start, clone the repository:
@ -42,18 +34,18 @@ Once in the directory, add Qt to the `CMAKE_PREFIX_PATH` variable (for instance,
set CMAKE_PREFIX_PATH=C:\Qt\6.8.3\msvc2022_64
Now, generate the build files:
Now, generate the build files with cmake via the vcpkg preset:
cmake -Bbuild .
cmake -Bbuild . --preset vcpkg
Then, finally build:
Then, finally, build in release mode\*:
cmake --build build
cmake --build build --config Release
> [!NOTE]
> To build in release mode, add -DCMAKE_BUILD_TYPE=Release to the configure (first) command,
> and add --config Release to the build (second) command
The compiled binaries should then be placed in `./build/bin/` and should be ready for redistribution without any further work.
The compiled binaries should then be located in `./build/bin/[Debug|Release]` and should be ready for redistribution without any further work.
If any of the compilation steps fail, or the binaries fail to execute, please create an issue so that this can be corrected.
If any of the compilation steps fail, or the binaries fail to execute, please create an issue so that this can be corrected.
\* Release mode is necessary as debug mode copies DLLs that are not linked to the output binary
DEVELOPER NOTE: AKA Not for you. If you get CUSTOM COMMAND BUILD errors just keep rerunning build

View file

@ -10,7 +10,6 @@ else()
endif()
set( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" )
set(USE_CCACHE ON)
add_subdirectory(autogen)
@ -25,6 +24,4 @@ add_subdirectory(client)
add_subdirectory(editor)
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/tests )
enable_testing()
add_subdirectory(tests)
install(FILES $<TARGET_RUNTIME_DLLS:editor> TYPE BIN)

21
CMakePresets.json Normal file
View file

@ -0,0 +1,21 @@
{
"version": 2,
"configurePresets": [
{
"name": "vcpkg",
"generator": "Visual Studio 17 2022",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
}
},
{
"name": "vcpkg-linux",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
}
}
]
}

13
CMakeUserPresets.json Normal file
View file

@ -0,0 +1,13 @@
{
"version": 2,
"configurePresets": [
{
"name": "default",
"inherits": "vcpkg",
"environment": {
"VCPKG_ROOT": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\vcpkg\\vcpkg.exe"
}
}
]
}

View file

@ -26,7 +26,6 @@ int processHeader(fs::path srcRoot, fs::path srcPath, fs::path outPath) {
std::string srcRootStr = string_of(srcRoot);
std::string srcPathStr = string_of(srcPath);
std::string outPathStr = string_of(outPath);
std::string logFileStr = outPathStr + ".log";
const char* cargs[] = { "-xc++", "-std=c++17", "-I", srcRootStr.c_str(), "-D__AUTOGEN__", 0 };
// THANK YOU SO MUCH THIS STACKOVERFLOW ANSWER IS SO HELPFUL
@ -43,26 +42,17 @@ int processHeader(fs::path srcRoot, fs::path srcPath, fs::path outPath) {
return 1;
}
fs::create_directories(outPath.parent_path()); // Make sure generated dir exists before we try writing to it
// We write to a special log file instead of stdout/stderr to
// 1. avoid confusion
// 2. prevent MSBuild from reading the word "error" and detecting there's a problem with the program (there isn't)
FILE* logout = fopen(logFileStr.c_str(), "w");
// Print errors
int ndiags = clang_getNumDiagnostics(unit);
for (int i = 0; i < ndiags; i++) {
CXDiagnostic diag = clang_getDiagnostic(unit, i);
CXString str = clang_formatDiagnostic(diag, 0);
fprintf(logout, "diag: %s\n", clang_getCString(str));
fprintf(stderr, "diag: %s\n", clang_getCString(str));
clang_disposeString(str);
clang_disposeDiagnostic(diag);
}
fclose(logout);
CXCursor cursor = clang_getTranslationUnitCursor(unit);
object::AnalysisState objectAnlyState;
@ -76,6 +66,8 @@ int processHeader(fs::path srcRoot, fs::path srcPath, fs::path outPath) {
data::analyzeClasses(cursor, srcRootStr, &dataAnlyState);
enum_::analyzeClasses(cursor, srcRootStr, &enumAnlyState);
fs::create_directories(outPath.parent_path()); // Make sure generated dir exists before we try writing to it
printf("[AUTOGEN] Generating file %s...\n", relpathStr.c_str());
std::ofstream outStream(outPathStr);
@ -112,7 +104,5 @@ int main(int argc, char** argv) {
fs::path srcPath = argv[2];
fs::path outPath = argv[3];
// fprintf(stderr, "Some error here\n");
// return 0;
return processHeader(srcRoot, srcPath, outPath);
}

View file

@ -1,24 +1,8 @@
include(${CMAKE_CURRENT_SOURCE_DIR}/deps.cmake)
find_package(SDL2 REQUIRED)
include_directories(${SDL2_INCLUDE_DIRS})
find_package(glfw3 REQUIRED)
add_executable(client "src/main.cpp")
target_link_libraries(client PRIVATE openblocks glfw)
add_dependencies(client openblocks)
if(WIN32)
# Copy assets
add_custom_command(
TARGET client POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/assets
$<TARGET_FILE_DIR:client>/assets)
endif()
set_target_properties(client PROPERTIES
WIN32_EXECUTABLE ON
)
# https://stackoverflow.com/a/73899349/16255372
if (WIN32)
# /ENTRY:mainCRTStartup keeps the same "main" function instead of requiring "WinMain"
target_link_options(client PRIVATE "/ENTRY:mainCRTStartup")
endif()
target_link_libraries(client PRIVATE ${SDL2_LIBRARIES} openblocks glfw)
add_dependencies(client openblocks)

View file

@ -1,12 +0,0 @@
# Declare/fetch packages
include(FetchContent)
FetchContent_Declare(
glfw3
GIT_REPOSITORY https://github.com/glfw/glfw
GIT_TAG 3.4
)
FetchContent_MakeAvailable(glfw3)
# Find/include packages

View file

@ -1,8 +1,6 @@
#include <glad/gl.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "logger.h"
#include "objects/part/part.h"
#include "panic.h"
#include "rendering/renderer.h"
#include "common.h"
#include "version.h"
@ -39,13 +37,7 @@ int main() {
glfwSetFramebufferSizeCallback(window, resizeCallback);
glfwMakeContextCurrent(window);
int version = gladLoadGL(glfwGetProcAddress);
if (version == 0) {
Logger::fatalError("Failed to initialize OpenGL context");
panic();
} else {
Logger::debugf("Initialized GL context version %d.%d", GLAD_VERSION_MAJOR(version), GLAD_VERSION_MINOR(version));
}
glewInit();
gDataModel->Init();
renderInit(1200, 900);
@ -91,7 +83,7 @@ int main() {
}
void errorCatcher(int id, const char* str) {
Logger::fatalErrorf("GLFW Error: [%d] %s", id, str);
Logger::fatalErrorf("GLFW Error: [{}] {}", id, str);
}
float lastTime;

View file

@ -1,23 +0,0 @@
set(CPM_DOWNLOAD_VERSION 0.42.0)
# Patch support is broken in CPM upstream atm, so we have to use a fork
set(CPM_HASH_SUM "f7d92592a257d184fd8de6fb496a711ce393676ed68999b96043aab2e5e6f9e6")
# set(CPM_HASH_SUM "2020b4fc42dba44817983e06342e682ecfc3d2f484a581f11cc5731fbe4dce8a")
if(CPM_SOURCE_CACHE)
set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
elseif(DEFINED ENV{CPM_SOURCE_CACHE})
set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
else()
set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
endif()
# Expand relative path. This is important if the provided path contains a tilde (~)
get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE)
file(DOWNLOAD
https://raw.githubusercontent.com/BohdanBuinich/CPM.cmake/refs/heads/feat/fix_patch_command/cmake/CPM.cmake
# https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM}
)
include(${CPM_DOWNLOAD_LOCATION})

View file

@ -1,60 +0,0 @@
# Modified from QGIS' FindQScintilla.cmake by Thomas Moenicke, Larry Schaffer
add_library(QScintilla::QScintilla UNKNOWN IMPORTED)
### NECESSARY TO PREVENT staticMetaObject ERROR!!! See qscintilla.prf AKA qmake config
if(WIN32)
add_compile_definitions(QSCINTILLA_DLL)
endif()
FIND_PATH(QSCINTILLA_INCLUDE_DIR
NAMES Qsci/qsciglobal.h
PATHS
${Qt6Core_INCLUDE_DIRS}
$ENV{LIB_DIR}/include
/usr/local/include
/usr/include
${VCPKG_INSTALLED_DIR}/x64-windows/include
PATH_SUFFIXES ${QSCINTILLA_PATH_SUFFIXES}
)
set(QSCINTILLA_LIBRARY_NAMES
qscintilla2-qt6
qscintilla2_qt6
libqt6scintilla2
libqscintilla2-qt6
qt6scintilla2
libqscintilla2-qt6.dylib
qscintilla2
)
find_library(QSCINTILLA_LIBRARY
NAMES ${QSCINTILLA_LIBRARY_NAMES}
PATHS
"${QT_LIBRARY_DIR}"
$ENV{LIB_DIR}/lib
/usr/local/lib
/usr/local/lib/qt6
/usr/lib
/usr/lib64
/usr/lib32
${VCPKG_INSTALLED_DIR}/x64-windows/lib
)
get_filename_component(QSCINTILLA_LIB_DIR ${QSCINTILLA_LIBRARY} DIRECTORY)
list(TRANSFORM QSCINTILLA_LIBRARY_NAMES APPEND ".dll" OUTPUT_VARIABLE QSCINTILLA_DLL_NAMES)
find_file(QSCINTILLA_DLLS
NAMES ${QSCINTILLA_DLL_NAMES}
PATHS
"${QT_LIBRARY_DIR}"
$ENV{LIB_DIR}/lib
/usr/local/lib
/usr/local/lib/qt6
/usr/lib64
/usr/lib32
/usr/lib
${QSCINTILLA_LIB_DIR}
${VCPKG_INSTALLED_DIR}/x64-windows/lib
)

30
cmake/FindStb.cmake Normal file
View file

@ -0,0 +1,30 @@
# Distributed under the OSI-approved BSD 3-Clause License.
# Copyright Stefano Sinigardi
#.rst:
# FindStb
# ------------
#
# Find the Stb include headers.
#
# Result Variables
# ^^^^^^^^^^^^^^^^
#
# This module defines the following variables:
#
# ``Stb_FOUND``
# True if Stb library found
#
# ``Stb_INCLUDE_DIR``
# Location of Stb headers
#
include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake)
include(${CMAKE_ROOT}/Modules/SelectLibraryConfigurations.cmake)
if(NOT Stb_INCLUDE_DIR)
find_path(Stb_INCLUDE_DIR NAMES stb_image.h PATHS ${Stb_DIR} PATH_SUFFIXES include stb include/stb)
endif()
find_package_handle_standard_args(Stb DEFAULT_MSG Stb_INCLUDE_DIR)
mark_as_advanced(Stb_INCLUDE_DIR)

View file

@ -1,176 +1,29 @@
include(${CMAKE_CURRENT_SOURCE_DIR}/deps.cmake)
find_package(OpenGL REQUIRED COMPONENTS OpenGL)
## Sources
set(SOURCES
src/stb.cpp
src/glad.cpp
find_package(GLEW REQUIRED)
include_directories(${GLEW_INCLUDE_DIRS})
src/ptr_helpers.h
src/enum/part.h
src/enum/surface.cpp
src/enum/meta.h
src/enum/annotation.h
src/enum/surface.h
src/camera.cpp
src/datatypes/vector.cpp
src/datatypes/variant.h
src/datatypes/cframe.cpp
src/datatypes/signal.cpp
src/datatypes/base.h
src/datatypes/enum.h
src/datatypes/enum.cpp
src/datatypes/primitives.h
src/datatypes/cframe.h
src/datatypes/variant.cpp
src/datatypes/vector.h
src/datatypes/color3.h
src/datatypes/annotation.h
src/datatypes/color3.cpp
src/datatypes/primitives.cpp
src/datatypes/ref.cpp
src/datatypes/ref.h
src/datatypes/signal.h
src/common.cpp
src/utils.h
src/platform.h
src/math_helper.cpp
src/rendering/skybox.cpp
src/rendering/mesh2d.cpp
src/rendering/torus.cpp
src/rendering/mesh.h
src/rendering/font.cpp
src/rendering/debug/debugrenderer.cpp
src/rendering/texture.h
src/rendering/shader.h
src/rendering/defaultmeshes.cpp
src/rendering/skybox.h
src/rendering/mesh2d.h
src/rendering/light.h
src/rendering/renderer.cpp
src/rendering/texture3d.h
src/rendering/texture.cpp
src/rendering/renderer.h
src/rendering/shader.cpp
src/rendering/mesh.cpp
src/rendering/material.h
src/rendering/torus.h
src/rendering/font.h
src/rendering/defaultmeshes.h
src/rendering/texture3d.cpp
src/logger.cpp
src/handles.h
src/timeutil.h
src/error/error.h
src/error/result.h
src/error/instance.h
src/error/data.h
src/partassembly.h
src/objects/service/jointsservice.cpp
src/objects/service/script/serverscriptservice.h
src/objects/service/script/serverscriptservice.cpp
src/objects/service/script/scriptcontext.h
src/objects/service/script/scriptcontext.cpp
src/objects/service/workspace.cpp
src/objects/service/selection.cpp
src/objects/service/selection.h
src/objects/service/jointsservice.h
src/objects/service/workspace.h
src/objects/datamodel.cpp
src/objects/script.h
src/objects/joint/snap.h
src/objects/joint/jointinstance.h
src/objects/joint/rotatev.h
src/objects/joint/weld.cpp
src/objects/joint/jointinstance.cpp
src/objects/joint/rotate.cpp
src/objects/joint/rotate.h
src/objects/joint/weld.h
src/objects/joint/snap.cpp
src/objects/joint/rotatev.cpp
src/objects/base/service.h
src/objects/base/member.h
src/objects/base/instance.h
src/objects/base/service.cpp
src/objects/base/instance.cpp
src/objects/base/refstate.h
src/objects/message.h
src/objects/pvinstance.cpp
src/objects/hint.cpp
src/objects/pvinstance.h
src/objects/base.h
src/objects/folder.cpp
src/objects/model.cpp
src/objects/datamodel.h
src/objects/folder.h
src/objects/meta.cpp
src/objects/model.h
src/objects/part/part.cpp
src/objects/part/part.h
src/objects/part/wedgepart.h
src/objects/part/basepart.cpp
src/objects/part/wedgepart.cpp
src/objects/part/basepart.h
src/objects/meta.h
src/objects/hint.h
src/objects/annotation.h
src/objects/message.cpp
src/objects/script.cpp
src/partassembly.cpp
src/panic.cpp
src/logger.h
src/camera.h
src/handles.cpp
src/version.h
src/common.h
src/platform.cpp
src/panic.h
src/lua/instancelib.cpp
src/timeutil.cpp
src/physics/util.h
src/luaapis.h
src/math_helper.h
)
find_package(OpenGL)
find_package(glm CONFIG REQUIRED)
find_package(ReactPhysics3D REQUIRED)
find_package(pugixml 1.15 REQUIRED)
find_package(Freetype)
set(AUTOGEN_SOURCES
# Objects
src/objects/service/script/serverscriptservice.h
src/objects/service/script/scriptcontext.h
src/objects/service/selection.h
src/objects/service/jointsservice.h
src/objects/service/workspace.h
src/objects/script.h
src/objects/joint/snap.h
src/objects/joint/jointinstance.h
src/objects/joint/rotatev.h
src/objects/joint/rotate.h
src/objects/joint/weld.h
src/objects/message.h
src/objects/pvinstance.h
src/objects/base.h
src/objects/datamodel.h
src/objects/folder.h
src/objects/model.h
src/objects/part/part.h
src/objects/part/wedgepart.h
src/objects/part/basepart.h
src/objects/meta.h
src/objects/hint.h
# Enum
src/enum/part.h
src/enum/surface.h
# Data types
src/datatypes/enum.h
src/datatypes/cframe.h
src/datatypes/vector.h
src/datatypes/color3.h
)
find_package(Stb REQUIRED)
include_directories(${Stb_INCLUDE_DIR})
# PkgConfig packages
find_package(PkgConfig REQUIRED)
pkg_check_modules(LUAJIT REQUIRED luajit)
link_directories(${LUAJIT_LIBRARY_DIRS})
### Autogen
file(GLOB_RECURSE AUTOGEN_SOURCES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/src" "src/objects/*.h" "src/datatypes/*.h" "src/enum/*.h")
# https://cmake.org/cmake/help/book/mastering-cmake/chapter/Custom%20Commands.html
foreach (SRC ${AUTOGEN_SOURCES})
string(REGEX REPLACE "[.]h$" ".cpp" OUT_SRC_NAME ${SRC})
set(SRC_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${SRC}")
set(SRC_PATH "${CMAKE_CURRENT_SOURCE_DIR}/src/${SRC}")
set(OUT_PATH "${CMAKE_BINARY_DIR}/generated/${OUT_SRC_NAME}")
add_custom_command(
@ -192,13 +45,14 @@ add_custom_target(autogen_build ALL
DEPENDS ${AUTOGEN_OUTS}
)
file(GLOB_RECURSE SOURCES "src/*.cpp" "src/*.h")
list(APPEND SOURCES ${AUTOGEN_OUTS})
list(APPEND SOURCES ${CMAKE_CURRENT_BINARY_DIR}/src/version.cpp)
add_library(openblocks STATIC ${SOURCES})
set_target_properties(openblocks PROPERTIES OUTPUT_NAME "openblocks")
target_link_directories(openblocks PUBLIC ${LUAJIT_LIBRARY_DIRS})
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" ${ReactPhysics3D_SOURCE_DIR}/include ${LUAJIT_INCLUDE_DIRS} ${stb_SOURCE_DIR})
target_link_libraries(openblocks ${GLEW_LIBRARIES} ${LUAJIT_LIBRARIES} OpenGL::GL ReactPhysics3D::ReactPhysics3D pugixml::pugixml Freetype::Freetype)
target_include_directories(openblocks PUBLIC "src" "../include" ${LUAJIT_INCLUDE_DIRS})
add_dependencies(openblocks autogen_build autogen)
# Windows-specific dependencies

View file

@ -1,32 +0,0 @@
include(CPM)
# Some packages will build helper binaries. This keeps them out of our own build output
set (PREV_BIN_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
unset (CMAKE_RUNTIME_OUTPUT_DIRECTORY)
CPMAddPackage("gh:g-truc/glm#1.0.1")
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(
NAME freetype
GIT_REPOSITORY https://github.com/aseprite/freetype2.git
GIT_TAG VER-2-10-0
VERSION 2.10.0
PATCHES ${CMAKE_SOURCE_DIR}/patches/freetype_cmakever.patch
)
if (freetype_ADDED)
add_library(Freetype::Freetype ALIAS freetype)
endif()
CPMAddPackage("gh:nothings/stb#8cfb1605c02aee9fb6eb5d8ea559017745bd9a16") # 2.14
CPMAddPackage("gh:WohlSoft/LuaJIT#a5da8f4a31972b74254f00969111b8b7a07cf584") # v2.1
set(LUAJIT_INCLUDE_DIRS ${LuaJIT_SOURCE_DIR}/src)
CPMAddPackage("gh:mackron/miniaudio#0.11.22")
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PREV_BIN_PATH})

View file

@ -1,2 +0,0 @@
#define GLAD_GL_IMPLEMENTATION
#include <glad/gl.h>

View file

@ -58,7 +58,7 @@ std::optional<HandleFace> raycastHandle(rp3d::Ray ray) {
// 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());
body->addCollider(common.createBoxShape(cframe.Rotation() * Vector3(handleSize(face) / 2.f)), rp3d::Transform::identity());
rp3d::RaycastInfo info;
if (body->raycast(ray, info)) {

View file

@ -10,26 +10,18 @@
static std::ofstream logStream;
static std::vector<Logger::LogListener> logListeners;
std::string Logger::currentLogDir = "NULL";
static std::stringstream* rawOutputBuffer = nullptr;
void Logger::init() {
initProgramLogsDir();
const auto now = std::chrono::system_clock::now();
const auto nows = std::chrono::floor<std::chrono::seconds>(now);
std::string fileName = std::format("log_{0:%Y%m%d}_{0:%H%M%S}.txt", nows);
std::string fileName = std::format("log_{0:%Y%m%d}_{0:%H%M%S}.txt", now);
logStream = std::ofstream(currentLogDir = (getProgramLogsDir() + "/" + fileName));
Logger::debug("Logger initialized");
}
// Initializes the logger in a "void" mode for testing.
// It is not necessary to call Logger::finish
void Logger::initTest(std::stringstream* outputBuffer) {
rawOutputBuffer = outputBuffer;
}
void Logger::finish() {
Logger::debug("Closing logger...");
logStream.close();
@ -49,7 +41,6 @@ void Logger::log(std::string message, Logger::LogLevel logLevel, ScriptSource so
logStream << formattedLogLine << std::endl;
printf("%s\n", formattedLogLine.c_str());
if (rawOutputBuffer != nullptr) *rawOutputBuffer << logLevelStr << ": " << message << "\n";
for (Logger::LogListener listener : logListeners) {
listener(logLevel, message, source);
@ -62,8 +53,4 @@ void Logger::log(std::string message, Logger::LogLevel logLevel, ScriptSource so
void Logger::addLogListener(Logger::LogListener listener) {
logListeners.push_back(listener);
}
void Logger::resetLogListeners() {
logListeners.clear();
}

View file

@ -2,7 +2,6 @@
#include <functional>
#include <memory>
#include <ostream>
#include <string>
class Script;
@ -27,10 +26,8 @@ namespace Logger {
extern std::string currentLogDir;
void init();
void initTest(std::stringstream* out); // Testing only!
void finish();
void addLogListener(LogListener);
void resetLogListeners(); // Testing only!
void log(std::string message, LogLevel logLevel, ScriptSource source = {});
inline void info(std::string message) { log(message, LogLevel::INFO); }

View file

@ -6,8 +6,6 @@ extern "C" {
#include <lua.h>
}
LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname);
inline const char* x_luaL_udatatname (lua_State *L, int ud) {
void *p = lua_touserdata(L, ud);
if (p != NULL) {
@ -18,6 +16,4 @@ inline const char* x_luaL_udatatname (lua_State *L, int ud) {
return str;
}
return NULL;
}
#define LUA_OK 0
}

View file

@ -13,7 +13,6 @@ 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
@ -88,5 +87,5 @@ void WedgePart::createWedgeShape(rp::PhysicsCommon* common) {
// Create the convex mesh
std::vector<rp3d::Message> messages;
// wedgePhysMesh = common->createConvexMesh(polygonVertexArray, messages);
wedgePhysMesh = common->createConvexMesh(polygonVertexArray, messages);
}

View file

@ -3,7 +3,7 @@
#include "basepart.h"
#include "objects/annotation.h"
class DEF_INST_(hidden) WedgePart : public BasePart {
class DEF_INST WedgePart : public BasePart {
AUTOGEN_PREAMBLE
protected:

View file

@ -3,7 +3,7 @@
#include "objects/annotation.h"
#include "objects/base/service.h"
class DEF_INST_SERVICE_(hidden) JointsService : public Service {
class DEF_INST_SERVICE JointsService : public Service {
AUTOGEN_PREAMBLE
private:
std::optional<std::shared_ptr<Workspace>> jointWorkspace();

View file

@ -15,7 +15,7 @@ struct SleepingThread {
class Script;
class DEF_INST_SERVICE_(hidden) ScriptContext : public Service {
class DEF_INST_SERVICE ScriptContext : public Service {
AUTOGEN_PREAMBLE
std::vector<SleepingThread> sleepingThreads;

View file

@ -5,7 +5,7 @@
// Container class for server scripts
// 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
protected:
void InitService() override;

View file

@ -6,7 +6,7 @@
#include <memory>
#include <vector>
class DEF_INST_SERVICE_(hidden) Selection : public Service {
class DEF_INST_SERVICE Selection : public Service {
AUTOGEN_PREAMBLE
private:
std::vector<std::shared_ptr<Instance>> selection;

View file

@ -76,8 +76,8 @@ void Workspace::InitService() {
physicsWorld->setGravity(rp::Vector3(0, -196.2, 0));
// world->setContactsPositionCorrectionTechnique(rp3d::ContactsPositionCorrectionTechnique::BAUMGARTE_CONTACTS);
// physicsWorld->setNbIterationsPositionSolver(2000);
// physicsWorld->setNbIterationsVelocitySolver(2000);
physicsWorld->setNbIterationsPositionSolver(2000);
physicsWorld->setNbIterationsVelocitySolver(2000);
// physicsWorld->setSleepLinearVelocity(10);
// physicsWorld->setSleepAngularVelocity(5);

View file

@ -1,7 +1,8 @@
#include "rendering/shader.h"
#include "rendering/texture.h"
#include "timeutil.h"
#include <glad/gl.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <glm/ext/vector_float4.hpp>
#include <string>

View file

@ -3,7 +3,8 @@
#include "panic.h"
#include "rendering/shader.h"
#include <glad/gl.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <glm/ext/matrix_clip_space.hpp>
#include <memory>

View file

@ -1,4 +1,5 @@
#include <glad/gl.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include "mesh.h"

View file

@ -1,4 +1,5 @@
#include <glad/gl.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include "mesh2d.h"

View file

@ -1,4 +1,5 @@
#include <glad/gl.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <cmath>
#include <cstdio>
#include <glm/ext.hpp>

View file

@ -1,5 +1,6 @@
#include <fstream>
#include <glad/gl.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <glm/gtc/type_ptr.hpp>
#include "logger.h"

View file

@ -1,4 +1,5 @@
#include <glad/gl.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <stb_image.h>
#include "logger.h"

View file

@ -1,6 +1,7 @@
#include "texture.h"
#include <glad/gl.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <stb_image.h>
#include "panic.h"

View file

@ -1,6 +1,7 @@
#include "texture3d.h"
#include <glad/gl.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <stb_image.h>
#include "panic.h"

View file

@ -1,7 +1,7 @@
#include "torus.h"
#include <cmath>
#include <glad/gl.h>
#include <GL/glew.h>
#define PI 3.1415926535f

View file

@ -4,15 +4,9 @@
tu_time_t TIME_STARTED_MICROS = std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now()).time_since_epoch().count();
static tu_time_t timeOverride = -1UL;
tu_time_t tu_clock_micros() {
if (timeOverride != -1UL) return timeOverride;
tu_time_t now = std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now()).time_since_epoch().count();;
return now - TIME_STARTED_MICROS;
}
void tu_set_override(tu_time_t destTime) {
timeOverride = destTime;
}

View file

@ -5,8 +5,4 @@
typedef uint64_t tu_time_t;
// Provides a high-accuracy time since the program started in microseconds (via std::chrono)
tu_time_t tu_clock_micros();
#ifdef TU_TIME_EXPOSE_TEST
void tu_set_override(tu_time_t destTime);
#endif
tu_time_t tu_clock_micros();

View file

@ -1,7 +1,8 @@
opengl (Linux: glvnd, Windows: [built-in/none])
glfw
glad
glew
glm
sdl2
stb
qt6
reactphysics3d

View file

@ -4,7 +4,7 @@ To do this, first download the source archive from [`https://www.riverbankcomput
Next, launch the *x64 Native Tools Command Prompt for VS 2022*, and cd into the directory that you extracted the archive to
Now, run `qmake src` from your Qt's bin directory to configure it
Now, run `qmake` from your Qt's bin directory to configure it
Once that's done, build and install the project using `nmake install`

View file

@ -1,12 +1,21 @@
cmake_minimum_required(VERSION 3.30.0)
project(editor VERSION 0.1 LANGUAGES CXX)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(QT_VERSION_MAJOR 6)
find_package(Qt6 REQUIRED COMPONENTS Widgets OpenGLWidgets REQUIRED)
find_package(QScintilla6 REQUIRED)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include(${CMAKE_CURRENT_SOURCE_DIR}/deps.cmake)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Multimedia LinguistTools)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Multimedia LinguistTools)
find_package(QScintilla REQUIRED)
set(TS_FILES editor_en_US.ts)
set(PROJECT_SOURCES
main.cpp
@ -38,25 +47,59 @@ set(PROJECT_SOURCES
${TS_FILES}
)
qt_add_executable(editor MANUAL_FINALIZATION ${PROJECT_SOURCES})
target_include_directories(editor PRIVATE .)
target_link_libraries(editor PRIVATE openblocks Qt6::Widgets Qt6::OpenGLWidgets ${QSCINTILLA_LIBRARY} miniaudio QCursorConstraints)
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
qt_add_executable(editor
MANUAL_FINALIZATION
${PROJECT_SOURCES}
)
# Define target properties for Android with Qt 6 as:
# set_property(TARGET editor APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
# ${CMAKE_CURRENT_SOURCE_DIR}/android)
# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation
set_target_properties(editor PROPERTIES
WIN32_EXECUTABLE ON
)
qt_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
else()
if(ANDROID)
add_library(editor SHARED
${PROJECT_SOURCES}
)
# Define properties for Android with Qt 5 after find_package() calls as:
# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
else()
add_executable(editor
${PROJECT_SOURCES}
mainglwidget.h mainglwidget.cpp
)
endif()
qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
endif()
target_include_directories(editor PUBLIC "../core/src" "../include" ${QSCINTILLA_INCLUDE_DIR})
target_link_libraries(editor PRIVATE openblocks Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Multimedia ${QSCINTILLA_LIBRARY})
add_dependencies(editor openblocks)
# Qt6 does not include QOpenGLWidgets as part of Widgets base anymore, so
# we have to include it manually
if (${QT_VERSION} GREATER_EQUAL 6)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS OpenGL OpenGLWidgets)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS OpenGL OpenGLWidgets)
target_include_directories(editor PUBLIC Qt6::OpenGL Qt6::OpenGLWidgets)
target_link_libraries(editor PRIVATE Qt6::OpenGL Qt6::OpenGLWidgets)
endif()
# Copy assets
add_custom_command(
TARGET editor POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/assets
$<TARGET_FILE_DIR:editor>/assets)
# Copy Qt files
if (WIN32)
#include("${QT_DEPLOY_SUPPORT}")
# Copy assets
add_custom_command(
TARGET editor POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/assets
$<TARGET_FILE_DIR:editor>/assets)
# Copy over QScintilla DLLs
# TODO: Use a better approach?
add_custom_command(
@ -64,37 +107,45 @@ if (WIN32)
COMMAND ${CMAKE_COMMAND} -E copy ${QSCINTILLA_DLLS} $<TARGET_FILE_DIR:editor>
)
set(WINDEPLOYQT_OPTIONS
--dir $<TARGET_FILE_DIR:editor>
--translations en
--no-compiler-runtime
--no-opengl-sw # No sense adding opengl-sw given that hardware acceleration is necessary, anyway
--no-system-d3d-compiler
--plugindir $<TARGET_FILE_DIR:editor>/qtplugins
# Also don't want to clutter with plugins, add only needed ones
)
# We split these into two commands because
# we might build a debug binary against a release qscintilla library
# TODO: Add other translations
add_custom_command(
TARGET editor POST_BUILD
COMMAND ${WINDEPLOYQT_EXECUTABLE} $<TARGET_FILE:editor>
${WINDEPLOYQT_OPTIONS}
COMMAND ${WINDEPLOYQT_EXECUTABLE} $<TARGET_FILE:editor> ${QSCINTILLA_DLLS} --dir $<TARGET_FILE_DIR:editor> --translations en --no-compiler-runtime --no-opengl-sw --no-system-d3d-compiler --plugindir $<TARGET_FILE_DIR:editor>/qtplugins
)
# No sense adding opengl-sw given that hardware acceleration is necessary, anyway
# Also don't want to clutter with plugins, add only needed ones
# Copy QScintilla dependencies too
add_custom_command(
TARGET editor POST_BUILD
COMMAND ${WINDEPLOYQT_EXECUTABLE} ${QSCINTILLA_DLLS}
${WINDEPLOYQT_OPTIONS}
)
# Copy qt.conf to override default plugins location
add_custom_command(
TARGET editor POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/qt.conf $<TARGET_FILE_DIR:editor>/qt.conf
)
endif()
endif ()
qt_finalize_executable(editor)
# 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
# explicit, fixed bundle identifier manually though.
if(${QT_VERSION} VERSION_LESS 6.1.0)
set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.example.qtbasic)
endif()
set_target_properties(editor PROPERTIES
${BUNDLE_ID_OPTION}
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
MACOSX_BUNDLE TRUE
WIN32_EXECUTABLE TRUE
)
include(GNUInstallDirs)
install(TARGETS editor
BUNDLE DESTINATION .
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
install(FILES $<TARGET_RUNTIME_DLLS:editor> TYPE BIN)
if(QT_VERSION_MAJOR EQUAL 6)
qt_finalize_executable(editor)
endif()

View file

@ -1,4 +0,0 @@
include(CPM)
CPMAddPackage("gh:m-doescode/qcursorconstraints#cef1a31c0afad8ed3c95ee1a6bc531090805b510")

View file

@ -7,40 +7,25 @@
#include <QStyleFactory>
#include <QBasicTimer>
#include <QSurfaceFormat>
#include <cstdio>
#include <qfont.h>
#include <qsurfaceformat.h>
#include <miniaudio.h>
#include <qcursorconstraints.h>
ma_engine miniaudio;
int main(int argc, char *argv[])
{
Logger::init();
// Has to happen before Qt application initializes or we get an error in WASAPI initialization
ma_result res = ma_engine_init(NULL, &miniaudio);
if (res != MA_SUCCESS) {
Logger::fatalErrorf("Failed to initialize Miniaudio withe error [%d]", res);
panic();
}
QSurfaceFormat format;
format.setSamples(4);
format.setRenderableType(QSurfaceFormat::OpenGL);
format.setVersion(3, 3);
format.setProfile(QSurfaceFormat::CompatibilityProfile); // Valid only in OpenGL 3.2+, see: https://stackoverflow.com/a/70519392/16255372
QSurfaceFormat::setDefaultFormat(format);
QApplication a(argc, argv);
QCursorConstraints::init();
Logger::init();
MainWindow w;
w.show();
int result = a.exec();
ma_engine_uninit(&miniaudio);
Logger::finish();
return result;
}

View file

@ -1,11 +1,9 @@
#include <glad/gl.h>
#include <GL/glew.h>
#include <glm/common.hpp>
#include <glm/vector_relational.hpp>
#include <memory>
#include <miniaudio.h>
#include <qcursorconstraints.h>
#include <qnamespace.h>
#include <qguiapplication.h>
#include <qsoundeffect.h>
#include <string>
#include "./ui_mainwindow.h"
#include "mainglwidget.h"
@ -37,20 +35,15 @@ MainGLWidget::MainGLWidget(QWidget* parent): QOpenGLWidget(parent), contextMenu(
}
void MainGLWidget::initializeGL() {
int version = gladLoaderLoadGL();
if (version == 0) {
Logger::fatalError("Failed to initialize OpenGL context");
panic();
} else {
Logger::debugf("Initialized GL context version %d.%d", GLAD_VERSION_MAJOR(version), GLAD_VERSION_MINOR(version));
}
glewInit();
renderInit(width(), height());
}
extern ma_engine miniaudio;
inline void playSound(QString path) {
ma_engine_stop(&miniaudio);
ma_engine_play_sound(&miniaudio, path.toStdString().c_str(), NULL);
QSoundEffect *sound = new QSoundEffect;
sound->setSource(QUrl::fromLocalFile(path));
sound->play();
sound->connect(sound, &QSoundEffect::playingChanged, [=]() { /* Thank you QSound source code! */ sound->deleteLater(); return false; });
}
extern int vpx, vpy;
@ -75,11 +68,14 @@ void MainGLWidget::paintGL() {
}
bool isMouseRightDragging = false;
QPoint mouseLockedPos;
QPoint lastMousePos;
void MainGLWidget::handleCameraRotate(QMouseEvent* evt) {
if (!isMouseRightDragging) return;
camera.processRotation(evt->pos().x() - lastMousePos.x(), evt->pos().y() - lastMousePos.y());
lastMousePos = evt->pos();
camera.processRotation(evt->pos().x() - mouseLockedPos.x(), evt->pos().y() - mouseLockedPos.y());
// QCursor::setPos(lastMousePos);
}
@ -327,7 +323,6 @@ std::optional<HandleFace> MainGLWidget::raycastHandle(glm::vec3 pointDir) {
}
void MainGLWidget::handleCursorChange(QMouseEvent* evt) {
if (isMouseRightDragging) return; // Don't change the cursor while it is intentionally blank
QPoint position = evt->pos();
glm::vec3 pointDir = camera.getScreenDirection(glm::vec2(position.x(), position.y()), glm::vec2(width(), height()));
@ -378,10 +373,8 @@ void MainGLWidget::mousePressEvent(QMouseEvent* evt) {
switch(evt->button()) {
// Camera drag
case Qt::RightButton: {
mouseLockedPos = evt->pos();
lastMousePos = evt->pos();
isMouseRightDragging = true;
setCursor(Qt::BlankCursor);
QCursorConstraints::lockCursor(window()->windowHandle());
return;
// Clicking on objects
} case Qt::LeftButton: {
@ -466,13 +459,11 @@ void MainGLWidget::mousePressEvent(QMouseEvent* evt) {
}
void MainGLWidget::mouseReleaseEvent(QMouseEvent* evt) {
QCursorConstraints::unlockCursor(window()->windowHandle());
// if (isMouseDragging) draggingObject.lock()->rigidBody->getCollider(0)->setCollisionCategoryBits(0b11);
isMouseRightDragging = false;
isMouseDragging = false;
draggingObject = {};
draggingHandle = std::nullopt;
setCursor(Qt::ArrowCursor);
if (!initialTransforms.empty()) {
UndoState historyState;

View file

@ -12,8 +12,6 @@
#include "undohistory.h"
#include "version.h"
#include <memory>
#include <QToolButton>
#include <QSettings>
#include <qclipboard.h>
#include <qevent.h>
#include <qglobal.h>
@ -22,14 +20,13 @@
#include <qmessagebox.h>
#include <qmimedata.h>
#include <qnamespace.h>
#include <qsoundeffect.h>
#include <qstylefactory.h>
#include <qstylehints.h>
#include <qmdisubwindow.h>
#include <pugixml.hpp>
#include <qtextcursor.h>
#include <qtextedit.h>
#include <miniaudio.h>
#include <qtoolbutton.h>
#include <vector>
#ifdef _NDEBUG
@ -61,17 +58,17 @@ void logQtMessage(QtMsgType type, const QMessageLogContext &context, const QStri
// if (defaultMessageHandler) defaultMessageHandler(type, context, msg);
}
extern ma_engine miniaudio;
inline void playSound(QString path) {
ma_engine_play_sound(&miniaudio, path.toStdString().c_str(), NULL);
QSoundEffect *sound = new QSoundEffect;
sound->setSource(QUrl::fromLocalFile(path));
sound->play();
sound->connect(sound, &QSoundEffect::playingChanged, [=]() { /* Thank you QSound source code! */ sound->deleteLater(); return false; });
}
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
loadState();
gDataModel->Init();
ui->setupUi(this);
@ -107,28 +104,6 @@ MainWindow::MainWindow(QWidget *parent)
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);
placeDocument = new PlaceDocument(this);
placeDocument->setAttribute(Qt::WA_DeleteOnClose, true);
@ -152,7 +127,6 @@ MainWindow::MainWindow(QWidget *parent)
}
void MainWindow::closeEvent(QCloseEvent* evt) {
saveState();
#ifdef NDEBUG
// Ask if the user wants to save their changes
// https://stackoverflow.com/a/33890731
@ -175,64 +149,6 @@ void MainWindow::closeEvent(QCloseEvent* evt) {
#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() {
CommandEdit* commandEdit;
QToolBar* commandBar = ui->commandBar;
@ -366,7 +282,6 @@ void MainWindow::connectActionHandlers() {
}
editModeDataModel->SaveToFile(path);
if (path) pushRecentFile(QString::fromStdString(path.value()));
});
connect(ui->actionSaveAs, &QAction::triggered, this, [&]() {
@ -374,7 +289,6 @@ void MainWindow::connectActionHandlers() {
if (!path || path == "") return;
editModeDataModel->SaveToFile(path);
if (path) pushRecentFile(QString::fromStdString(path.value()));
});
connect(ui->actionOpen, &QAction::triggered, this, [&]() {
@ -395,7 +309,6 @@ void MainWindow::connectActionHandlers() {
placeDocument->setRunState(RUN_STOPPED);
undoManager.Reset();
updateToolbars();
if (path) pushRecentFile(QString::fromStdString(path.value()));
});
connect(ui->actionDelete, &QAction::triggered, this, [&]() {

View file

@ -64,18 +64,10 @@ public:
void openFile(std::string path);
Ui::MainWindow *ui;
QMenu* recentsMenu = nullptr;
QStringList recentFiles;
void refreshRecentsMenu();
void pushRecentFile(QString);
void loadState();
void saveState();
friend PlaceDocument;
private:
PlaceDocument* placeDocument = nullptr;
PlaceDocument* placeDocument;
void setUpCommandBar();
void connectActionHandlers();

View file

@ -8,10 +8,6 @@
#include <qmimedata.h>
#include <QWidget>
#ifdef _NDEBUG
#define NDEBUG
#endif
#define M_mainWindow dynamic_cast<MainWindow*>(dynamic_cast<QWidget*>(dynamic_cast<QObject*>(this)->parent())->window())
// https://doc.qt.io/qt-6/qtwidgets-itemviews-simpletreemodel-example.html#testing-the-model
@ -53,14 +49,8 @@ QModelIndex ExplorerModel::index(int row, int column, const QModelIndex &parent)
? static_cast<Instance*>(parent.internalPointer())
: rootItem.get();
#ifdef NDEBUG
if (parentItem->GetChildren().size() >= (size_t)row && !(parentItem->GetChildren()[row]->GetClass()->flags & INSTANCE_HIDDEN))
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 {};
}
@ -107,15 +97,7 @@ int ExplorerModel::rowCount(const QModelIndex &parent) const {
? static_cast<Instance*>(parent.internalPointer())
: 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();
#endif
}
int ExplorerModel::columnCount(const QModelIndex &parent) const {

View file

@ -107,7 +107,7 @@ void ExplorerView::buildContextMenu() {
contextMenu.addMenu(insertObjectMenu);
for (const auto& [_, type] : INSTANCE_MAP) {
if (type->flags & (INSTANCE_NOTCREATABLE | INSTANCE_HIDDEN) || !type->constructor) continue;
if (type->flags & INSTANCE_NOTCREATABLE || !type->constructor) continue;
QAction* instAction = new QAction(model.iconOf(type), QString::fromStdString(type->className));
insertObjectMenu->addAction(instAction);

5914
external/glad/glad/gl.h vendored

File diff suppressed because it is too large Load diff

View file

@ -1,14 +0,0 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 28dc3b3f6..37fd14713 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -85,7 +85,8 @@
# FreeType explicitly marks the API to be exported and relies on the compiler
# to hide all other symbols. CMake supports a C_VISBILITY_PRESET property
# starting with 2.8.12.
-cmake_minimum_required(VERSION 2.8.12)
+# cmake_minimum_required(VERSION 2.8.12)
+cmake_minimum_required(VERSION 3.5)
if (NOT CMAKE_VERSION VERSION_LESS 3.3)
# Allow symbol visibility settings also on static libraries. CMake < 3.3

View file

@ -1,14 +0,0 @@
function (create_test TEST_NAME)
set(TARGET_NAME test_${TEST_NAME})
add_executable(${TARGET_NAME} ${ARGN})
target_link_libraries(${TARGET_NAME} PRIVATE openblocks)
add_dependencies(${TARGET_NAME} openblocks)
add_test(NAME ${TARGET_NAME} COMMAND ${TARGET_NAME})
endfunction ()
create_test(lua src/luatest.cpp)
create_test(luasched src/luaschedtest.cpp)
create_test(luasignal src/luasignaltest.cpp)
# https://stackoverflow.com/a/36729074/16255372
add_custom_target(check ${CMAKE_CTEST_COMMAND} --output-on-failure WORKING_DIRECTORY ${CMAKE_BINARY_DIR})

View file

@ -1,77 +0,0 @@
#include "testutillua.h"
#include "timeutil.h"
void test_wait1(DATAMODEL_REF m) {
auto ctx = m->GetService<ScriptContext>();
std::stringstream out;
Logger::initTest(&out);
tu_set_override(0);
luaEval(m, "wait(1) print('Wait')");
ctx->RunSleepingThreads();
ASSERT_EQ("", out.str());
TT_ADVANCETIME(0.5);
ctx->RunSleepingThreads();
ASSERT_EQ("", out.str());
TT_ADVANCETIME(0.5);
ctx->RunSleepingThreads();
ASSERT_EQ("INFO: Wait\n", out.str());
Logger::initTest(nullptr);
}
void test_wait0(DATAMODEL_REF m) {
auto ctx = m->GetService<ScriptContext>();
std::stringstream out;
Logger::initTest(&out);
tu_set_override(0);
luaEval(m, "wait(0) print('Wait')");
ASSERT_EQ("", out.str());
ctx->RunSleepingThreads();
ASSERT_EQ("", out.str());
TT_ADVANCETIME(0.03);
ctx->RunSleepingThreads();
ASSERT_EQ("INFO: Wait\n", out.str());
Logger::initTest(nullptr);
}
void test_delay(DATAMODEL_REF m) {
auto ctx = m->GetService<ScriptContext>();
std::stringstream out;
Logger::initTest(&out);
tu_set_override(0);
luaEval(m, "delay(1, function() print('Delay') end)");
ctx->RunSleepingThreads();
ASSERT_EQ("", out.str());
TT_ADVANCETIME(0.5);
ctx->RunSleepingThreads();
ASSERT_EQ("", out.str());
TT_ADVANCETIME(0.5);
ctx->RunSleepingThreads();
ASSERT_EQ("INFO: Delay\n", out.str());
Logger::initTest(nullptr);
}
int main() {
auto m = DataModel::New();
m->Init(true);
test_wait1(m);
test_wait0(m);
test_delay(m);
return TEST_STATUS;
}

View file

@ -1,103 +0,0 @@
#include "testutil.h"
#include "testutillua.h"
#include "timeutil.h"
#include "objects/part/part.h"
#include "objects/service/workspace.h"
#include <memory>
#include <sstream>
void test_connect(DATAMODEL_REF m) {
auto ctx = m->GetService<ScriptContext>();
auto part = Part::New();
m->GetService<Workspace>()->AddChild(part);
std::stringstream out;
Logger::initTest(&out);
luaEval(m, "workspace.Part.Touched:Connect(function() print('Fired!') end)");
ASSERT_EQ("", out.str());
part->Touched->Fire();
ASSERT_EQ("INFO: Fired!\n", out.str());
part->Touched->Fire();
ASSERT_EQ("INFO: Fired!\nINFO: Fired!\n", out.str());
Logger::initTest(nullptr);
part->Destroy();
}
void test_waitwithin(DATAMODEL_REF m) {
auto ctx = m->GetService<ScriptContext>();
auto part = Part::New();
m->GetService<Workspace>()->AddChild(part);
std::stringstream out;
Logger::initTest(&out);
tu_set_override(0);
luaEval(m, "workspace.Part.Touched:Connect(function() print('Fired!') wait(1) print('Waited') end)");
ASSERT_EQ("", out.str());
// One shot
part->Touched->Fire();
ctx->RunSleepingThreads();
ASSERT_EQ("INFO: Fired!\n", out.str());
TT_ADVANCETIME(0.5);
ctx->RunSleepingThreads();
ASSERT_EQ("INFO: Fired!\n", out.str());
TT_ADVANCETIME(0.5);
ctx->RunSleepingThreads();
ASSERT_EQ("INFO: Fired!\nINFO: Waited\n", out.str());
// Clear
out = std::stringstream();
Logger::initTest(&out); // Shouldn't *theoretically* be necessary, but just in principle...
// Double fire
part->Touched->Fire();
TT_ADVANCETIME(0.2);
part->Touched->Fire();
ASSERT_EQ("INFO: Fired!\nINFO: Fired!\n", out.str());
TT_ADVANCETIME(1-0.2); // Small extra delay is necessary because floating point math
ctx->RunSleepingThreads();
ASSERT_EQ("INFO: Fired!\nINFO: Fired!\nINFO: Waited\n", out.str());
TT_ADVANCETIME(0.2);
ctx->RunSleepingThreads();
ASSERT_EQ("INFO: Fired!\nINFO: Fired!\nINFO: Waited\nINFO: Waited\n", out.str());
tu_set_override(-1UL);
Logger::initTest(nullptr);
part->Destroy();
}
void test_await(DATAMODEL_REF m) {
auto ctx = m->GetService<ScriptContext>();
auto part = Part::New();
m->GetService<Workspace>()->AddChild(part);
std::stringstream out;
Logger::initTest(&out);
tu_set_override(0);
luaEval(m, "workspace.Part.Touched:Wait() print('Fired!')");
ASSERT_EQ("", out.str());
part->Touched->Fire();
ASSERT_EQ("INFO: Fired!\n", out.str());
part->Touched->Fire(); // Firing again should not affect output
ASSERT_EQ("INFO: Fired!\n", out.str());
tu_set_override(-1UL);
Logger::initTest(nullptr);
part->Destroy();
}
int main() {
auto m = DataModel::New();
m->Init(true);
test_connect(m);
test_waitwithin(m);
test_await(m);
return TEST_STATUS;
}

View file

@ -1,20 +0,0 @@
#include "testutil.h"
#include "testutillua.h"
#include <memory>
void test_output(DATAMODEL_REF m) {
ASSERT_EQ("INFO: Hello, world!\n", luaEvalOut(m, "print('Hello, world!')"));
// ASSERT_EQ("WARN: Some warning here.\n", luaEvalOut(m, "warn('Some warning here.')"));
// ASSERT_EQ("ERROR: An error!.\n", luaEvalOut(m, "error('An error!')"));
}
int main() {
auto m = DataModel::New();
m->Init(true);
test_output(m);
return TEST_STATUS;
}

View file

@ -1,70 +0,0 @@
#pragma once
// https://bastian.rieck.me/blog/2017/simple_unit_tests/
#include <algorithm>
#include <cstddef>
#include <iomanip>
#include <regex>
#include <sstream>
#include <string>
#ifdef __FUNCTION__
#define __FUNC_NAME __FUNCTION__
#else
#define __FUNC_NAME __func__
#endif
#define ASSERT(x, msg) __assert((x), __FILE__, __LINE__, __FUNC_NAME, msg)
#define ASSERT_EQ(x, y) __assert_eq((x) == (y), __FILE__, __LINE__, __FUNC_NAME, #x, (y))
// #define ASSERT_EQSTR(x, y) ASSERT(strcmp(x, y) == 0, #x " != " #y)
#define ASSERT_EQSTR(x, y) ASSERT_EQ(x, y)
#define DATAMODEL_REF std::shared_ptr<DataModel>
#define TU_TIME_EXPOSE_TEST
#define TT_ADVANCETIME(secs) tu_set_override(tu_clock_micros() + (secs) * 1'000'000);
#include <cstdio>
#include <cstring>
int TEST_STATUS = 0;
inline void __assert(bool cond, std::string file, int line, std::string func, std::string message) {
if (cond) return;
fprintf(stderr, "ASSERT FAILED : %s:%d : %s : '%s'\n", file.c_str(), line, func.c_str(), message.c_str());
TEST_STATUS = 1;
}
template <typename T>
inline std::string quote(T value) {
return std::to_string(value);
}
template <>
std::string quote<std::string>(std::string value) {
std::stringstream ss;
ss << std::quoted(value);
std::string newstr = ss.str();
newstr = std::regex_replace(newstr, std::regex("\n"), "\\n");
return newstr;
}
template <>
inline std::string quote<const char*>(const char* value) {
return quote<std::string>(value);
}
template <>
inline std::string quote<char*>(char* value) {
return quote<std::string>(value);
}
template <typename T>
void __assert_eq(bool cond, std::string file, int line, std::string func, std::string model, T value) {
if (cond) return;
std::string message = model + " != " + quote(value);
fprintf(stderr, "ASSERT FAILED : %s:%d : %s : '%s'\n", file.c_str(), line, func.c_str(), message.c_str());
TEST_STATUS = 1;
}

View file

@ -1,30 +0,0 @@
#pragma once
#include "testutil.h"
#include <sstream>
#include "logger.h"
#include "objects/datamodel.h"
#include "objects/script.h"
#include "objects/service/script/scriptcontext.h"
std::string luaEvalOut(DATAMODEL_REF m, std::string source) {
std::stringstream out;
Logger::initTest(&out);
auto s = Script::New();
m->AddChild(s);
s->source = source;
s->Run();
Logger::initTest(nullptr);
return out.str();
}
void luaEval(DATAMODEL_REF m, std::string source) {
auto s = Script::New();
m->AddChild(s);
s->source = source;
s->Run();
}

17
vcpkg-configuration.json Executable file
View file

@ -0,0 +1,17 @@
{
"default-registry": {
"kind": "git",
"baseline": "0c4cf19224a049cf82f4521e29e39f7bd680440c",
"repository": "https://github.com/microsoft/vcpkg"
},
"registries": [
{
"kind": "artifact",
"location": "https://github.com/microsoft/vcpkg-ce-catalog/archive/refs/heads/main.zip",
"name": "microsoft"
}
],
"overlay-ports": [
"./vcpkg-overlays"
]
}

View file

@ -0,0 +1,23 @@
vcpkg_check_linkage(ONLY_STATIC_LIBRARY)
vcpkg_from_github(
OUT_SOURCE_PATH SOURCE_PATH
REPO DanielChappuis/reactphysics3d
REF "cd958bbc0c6e84a869388cba6613f10cc645b3cb"
SHA512 9856c0e998473e0bfb97af9ced07952bbd4dfef79f7dc388b1ecf9b6c6406f7669333e441fe6cefdf40b32edc5a1b8e4cb35a8c15fccb64c28785aff5fd77113
HEAD_REF master
PATCHES "std_chrono.patch"
)
vcpkg_cmake_configure(
SOURCE_PATH "${SOURCE_PATH}"
)
vcpkg_cmake_install()
vcpkg_cmake_config_fixup(PACKAGE_NAME "reactphysics3d" CONFIG_PATH "lib/cmake/ReactPhysics3D")
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include")
# file(INSTALL "${CMAKE_CURRENT_LIST_DIR}/usage" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}")
vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE")

View file

@ -0,0 +1,18 @@
{
"name": "reactphysics3d",
"version": "0.10.2",
"homepage": "https://github.com/DanielChappuis/reactphysics3d",
"description": "Open source C++ physics engine library in 3D",
"license": "zlib",
"dependencies": [
{
"name" : "vcpkg-cmake",
"host" : true
},
{
"name" : "vcpkg-cmake-config",
"host" : true
},
"fmt"
]
}

20
vcpkg.json Executable file
View file

@ -0,0 +1,20 @@
{
"dependencies": [
"glew",
"glfw3",
"glm",
{ "name": "pugixml", "version>=": "1.15" },
"sdl2",
"stb",
"reactphysics3d",
"pkgconf",
"luajit",
"freetype"
],
"overrides": [
{
"name": "sdl2",
"version": "2.32.4"
}
]
}