Compare commits
34 commits
6d95cc8e1a
...
e2054a51a8
Author | SHA1 | Date | |
---|---|---|---|
e2054a51a8 | |||
93984ce1c0 | |||
6803a659cb | |||
a619fa3afc | |||
43e41caebf | |||
1bd9b00c47 | |||
ae9a4adf67 | |||
7bd3e70c3a | |||
52cfa69a6e | |||
62743d8998 | |||
2fec4cc7f2 | |||
56ffc3f88c | |||
384c249874 | |||
692bb17d44 | |||
2ed8c83ec3 | |||
801b00ad97 | |||
4940b07403 | |||
2f09c6eb9c | |||
3521f50d1b | |||
11df6595c0 | |||
44c28b6825 | |||
92ab9f6fb9 | |||
b117f3cd4d | |||
d086cf629b | |||
143d3769c7 | |||
243af95a3b | |||
3df575314e | |||
8d5fb3b2c6 | |||
471b2472e3 | |||
be324e0aa8 | |||
330f128dd3 | |||
8b8776cbd7 | |||
74a4a01ebf | |||
12fc8906bc |
61 changed files with 6864 additions and 332 deletions
1
.clangd
1
.clangd
|
@ -1,2 +1,3 @@
|
|||
CompileFlags:
|
||||
Add: [-std=c++20]
|
||||
Remove: [-mno-direct-extern-access]
|
32
BUILD.md
32
BUILD.md
|
@ -1,20 +1,27 @@
|
|||
# Building on Linux
|
||||
|
||||
For pre-requisite packages, check [deps.txt](./deps.txt)
|
||||
You will need to install Qt and LLVM/libclang beforehand. All other packages will automatically be obtained through CPM.
|
||||
|
||||
If your distribution does not provide ReactPhysics3D, you will have to build (and install) it yourself prior to this step
|
||||
ccache is highly recommended.
|
||||
|
||||
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 project will be built using VCPKG and MSVC
|
||||
The process is very similar on Windows
|
||||
|
||||
## Pre-requisites
|
||||
|
||||
|
@ -22,6 +29,7 @@ The project will be built using VCPKG and MSVC
|
|||
* 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:
|
||||
|
@ -34,18 +42,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 with cmake via the vcpkg preset:
|
||||
Now, generate the build files:
|
||||
|
||||
cmake -Bbuild . --preset vcpkg
|
||||
cmake -Bbuild .
|
||||
|
||||
Then, finally, build in release mode\*:
|
||||
Then, finally build:
|
||||
|
||||
cmake --build build --config Release
|
||||
cmake --build build
|
||||
|
||||
The compiled binaries should then be placed in `./build/bin/` and should be ready for redistribution without any further work.
|
||||
> [!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
|
||||
|
||||
If any of the compilation steps fail, or the binaries fail to execute, please create an issue so that this can be corrected.
|
||||
The compiled binaries should then be located in `./build/bin/[Debug|Release]` and should be ready for redistribution without any further work.
|
||||
|
||||
\* 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
|
||||
If any of the compilation steps fail, or the binaries fail to execute, please create an issue so that this can be corrected.
|
|
@ -10,6 +10,7 @@ else()
|
|||
endif()
|
||||
|
||||
set( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" )
|
||||
set(USE_CCACHE ON)
|
||||
|
||||
add_subdirectory(autogen)
|
||||
|
||||
|
@ -24,4 +25,6 @@ add_subdirectory(client)
|
|||
add_subdirectory(editor)
|
||||
|
||||
|
||||
install(FILES $<TARGET_RUNTIME_DLLS:editor> TYPE BIN)
|
||||
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/tests )
|
||||
enable_testing()
|
||||
add_subdirectory(tests)
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"version": 2,
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "default",
|
||||
"inherits": "vcpkg",
|
||||
"environment": {
|
||||
"VCPKG_ROOT": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\vcpkg\\vcpkg.exe"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -26,6 +26,7 @@ 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
|
||||
|
@ -42,17 +43,26 @@ 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(stderr, "diag: %s\n", clang_getCString(str));
|
||||
fprintf(logout, "diag: %s\n", clang_getCString(str));
|
||||
|
||||
clang_disposeString(str);
|
||||
clang_disposeDiagnostic(diag);
|
||||
}
|
||||
|
||||
fclose(logout);
|
||||
|
||||
CXCursor cursor = clang_getTranslationUnitCursor(unit);
|
||||
|
||||
object::AnalysisState objectAnlyState;
|
||||
|
@ -66,8 +76,6 @@ 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);
|
||||
|
||||
|
@ -104,5 +112,7 @@ 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);
|
||||
}
|
|
@ -1,8 +1,24 @@
|
|||
find_package(SDL2 REQUIRED)
|
||||
include_directories(${SDL2_INCLUDE_DIRS})
|
||||
|
||||
find_package(glfw3 REQUIRED)
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/deps.cmake)
|
||||
|
||||
add_executable(client "src/main.cpp")
|
||||
target_link_libraries(client PRIVATE ${SDL2_LIBRARIES} openblocks glfw)
|
||||
add_dependencies(client openblocks)
|
||||
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()
|
12
client/deps.cmake
Normal file
12
client/deps.cmake
Normal file
|
@ -0,0 +1,12 @@
|
|||
# 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
|
|
@ -1,6 +1,8 @@
|
|||
#include <GL/glew.h>
|
||||
#include <glad/gl.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"
|
||||
|
@ -37,7 +39,13 @@ int main() {
|
|||
glfwSetFramebufferSizeCallback(window, resizeCallback);
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
glewInit();
|
||||
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));
|
||||
}
|
||||
|
||||
gDataModel->Init();
|
||||
renderInit(1200, 900);
|
||||
|
@ -83,7 +91,7 @@ int main() {
|
|||
}
|
||||
|
||||
void errorCatcher(int id, const char* str) {
|
||||
Logger::fatalErrorf("GLFW Error: [{}] {}", id, str);
|
||||
Logger::fatalErrorf("GLFW Error: [%d] %s", id, str);
|
||||
}
|
||||
|
||||
float lastTime;
|
||||
|
|
23
cmake/CPM.cmake
Normal file
23
cmake/CPM.cmake
Normal file
|
@ -0,0 +1,23 @@
|
|||
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})
|
60
cmake/FindQScintilla6.cmake
Normal file
60
cmake/FindQScintilla6.cmake
Normal file
|
@ -0,0 +1,60 @@
|
|||
# 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
|
||||
)
|
|
@ -1,30 +0,0 @@
|
|||
# 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)
|
|
@ -1,29 +1,176 @@
|
|||
find_package(OpenGL REQUIRED COMPONENTS OpenGL)
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/deps.cmake)
|
||||
|
||||
find_package(GLEW REQUIRED)
|
||||
include_directories(${GLEW_INCLUDE_DIRS})
|
||||
## Sources
|
||||
set(SOURCES
|
||||
src/stb.cpp
|
||||
src/glad.cpp
|
||||
|
||||
find_package(OpenGL)
|
||||
find_package(glm CONFIG REQUIRED)
|
||||
find_package(ReactPhysics3D REQUIRED)
|
||||
find_package(pugixml 1.15 REQUIRED)
|
||||
find_package(Freetype)
|
||||
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(Stb REQUIRED)
|
||||
include_directories(${Stb_INCLUDE_DIR})
|
||||
|
||||
# PkgConfig packages
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(LUAJIT REQUIRED luajit)
|
||||
link_directories(${LUAJIT_LIBRARY_DIRS})
|
||||
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
|
||||
)
|
||||
|
||||
### 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/${SRC}")
|
||||
set(SRC_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${SRC}")
|
||||
set(OUT_PATH "${CMAKE_BINARY_DIR}/generated/${OUT_SRC_NAME}")
|
||||
|
||||
add_custom_command(
|
||||
|
@ -45,14 +192,13 @@ 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 ${GLEW_LIBRARIES} ${LUAJIT_LIBRARIES} OpenGL::GL ReactPhysics3D::ReactPhysics3D pugixml::pugixml Freetype::Freetype)
|
||||
target_include_directories(openblocks PUBLIC "src" "../include" ${LUAJIT_INCLUDE_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})
|
||||
add_dependencies(openblocks autogen_build autogen)
|
||||
|
||||
# Windows-specific dependencies
|
||||
|
|
32
core/deps.cmake
Normal file
32
core/deps.cmake
Normal file
|
@ -0,0 +1,32 @@
|
|||
|
||||
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})
|
2
core/src/glad.cpp
Normal file
2
core/src/glad.cpp
Normal file
|
@ -0,0 +1,2 @@
|
|||
#define GLAD_GL_IMPLEMENTATION
|
||||
#include <glad/gl.h>
|
|
@ -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)), rp3d::Transform::identity());
|
||||
body->addCollider(common.createBoxShape((cframe.Rotation() * Vector3(handleSize(face) / 2.f)).Abs()), rp3d::Transform::identity());
|
||||
|
||||
rp3d::RaycastInfo info;
|
||||
if (body->raycast(ray, info)) {
|
||||
|
|
|
@ -10,18 +10,26 @@
|
|||
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", now);
|
||||
std::string fileName = std::format("log_{0:%Y%m%d}_{0:%H%M%S}.txt", nows);
|
||||
|
||||
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();
|
||||
|
@ -41,6 +49,7 @@ 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);
|
||||
|
@ -53,4 +62,8 @@ 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();
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
class Script;
|
||||
|
@ -26,8 +27,10 @@ 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); }
|
||||
|
|
|
@ -6,6 +6,8 @@ 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) {
|
||||
|
@ -16,4 +18,6 @@ inline const char* x_luaL_udatatname (lua_State *L, int ud) {
|
|||
return str;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#define LUA_OK 0
|
|
@ -13,6 +13,7 @@ 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
|
||||
|
@ -87,5 +88,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);
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
#include "basepart.h"
|
||||
#include "objects/annotation.h"
|
||||
|
||||
class DEF_INST WedgePart : public BasePart {
|
||||
class DEF_INST_(hidden) WedgePart : public BasePart {
|
||||
AUTOGEN_PREAMBLE
|
||||
|
||||
protected:
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "objects/annotation.h"
|
||||
#include "objects/base/service.h"
|
||||
|
||||
class DEF_INST_SERVICE JointsService : public Service {
|
||||
class DEF_INST_SERVICE_(hidden) JointsService : public Service {
|
||||
AUTOGEN_PREAMBLE
|
||||
private:
|
||||
std::optional<std::shared_ptr<Workspace>> jointWorkspace();
|
||||
|
|
|
@ -15,7 +15,7 @@ struct SleepingThread {
|
|||
|
||||
class Script;
|
||||
|
||||
class DEF_INST_SERVICE ScriptContext : public Service {
|
||||
class DEF_INST_SERVICE_(hidden) ScriptContext : public Service {
|
||||
AUTOGEN_PREAMBLE
|
||||
|
||||
std::vector<SleepingThread> sleepingThreads;
|
||||
|
|
|
@ -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") ServerScriptService : public Service {
|
||||
class DEF_INST_SERVICE_(explorer_icon="server-scripts", hidden) ServerScriptService : public Service {
|
||||
AUTOGEN_PREAMBLE
|
||||
protected:
|
||||
void InitService() override;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
class DEF_INST_SERVICE Selection : public Service {
|
||||
class DEF_INST_SERVICE_(hidden) Selection : public Service {
|
||||
AUTOGEN_PREAMBLE
|
||||
private:
|
||||
std::vector<std::shared_ptr<Instance>> selection;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
#include "rendering/shader.h"
|
||||
#include "rendering/texture.h"
|
||||
#include "timeutil.h"
|
||||
#include <GL/glew.h>
|
||||
#include <GL/gl.h>
|
||||
#include <glad/gl.h>
|
||||
#include <glm/ext/vector_float4.hpp>
|
||||
#include <string>
|
||||
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
#include "panic.h"
|
||||
#include "rendering/shader.h"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <GL/gl.h>
|
||||
#include <glad/gl.h>
|
||||
#include <glm/ext/matrix_clip_space.hpp>
|
||||
#include <memory>
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include <GL/glew.h>
|
||||
#include <GL/gl.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include "mesh.h"
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include <GL/glew.h>
|
||||
#include <GL/gl.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include "mesh2d.h"
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include <GL/glew.h>
|
||||
#include <GL/gl.h>
|
||||
#include <glad/gl.h>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <glm/ext.hpp>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include <fstream>
|
||||
#include <GL/glew.h>
|
||||
#include <GL/gl.h>
|
||||
#include <glad/gl.h>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include "logger.h"
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include <GL/glew.h>
|
||||
#include <GL/gl.h>
|
||||
#include <glad/gl.h>
|
||||
#include <stb_image.h>
|
||||
|
||||
#include "logger.h"
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#include "texture.h"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <GL/gl.h>
|
||||
#include <glad/gl.h>
|
||||
#include <stb_image.h>
|
||||
|
||||
#include "panic.h"
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#include "texture3d.h"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <GL/gl.h>
|
||||
#include <glad/gl.h>
|
||||
#include <stb_image.h>
|
||||
|
||||
#include "panic.h"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "torus.h"
|
||||
#include <cmath>
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#define PI 3.1415926535f
|
||||
|
||||
|
|
|
@ -4,9 +4,15 @@
|
|||
|
||||
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;
|
||||
}
|
|
@ -5,4 +5,8 @@
|
|||
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();
|
||||
tu_time_t tu_clock_micros();
|
||||
|
||||
#ifdef TU_TIME_EXPOSE_TEST
|
||||
void tu_set_override(tu_time_t destTime);
|
||||
#endif
|
3
deps.txt
3
deps.txt
|
@ -1,8 +1,7 @@
|
|||
opengl (Linux: glvnd, Windows: [built-in/none])
|
||||
glfw
|
||||
glew
|
||||
glad
|
||||
glm
|
||||
sdl2
|
||||
stb
|
||||
qt6
|
||||
reactphysics3d
|
||||
|
|
|
@ -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` from your Qt's bin directory to configure it
|
||||
Now, run `qmake src` from your Qt's bin directory to configure it
|
||||
|
||||
Once that's done, build and install the project using `nmake install`
|
||||
|
||||
|
|
|
@ -1,21 +1,12 @@
|
|||
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(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(QT_VERSION_MAJOR 6)
|
||||
find_package(Qt6 REQUIRED COMPONENTS Widgets OpenGLWidgets REQUIRED)
|
||||
find_package(QScintilla6 REQUIRED)
|
||||
|
||||
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)
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/deps.cmake)
|
||||
|
||||
set(PROJECT_SOURCES
|
||||
main.cpp
|
||||
|
@ -47,59 +38,25 @@ set(PROJECT_SOURCES
|
|||
${TS_FILES}
|
||||
)
|
||||
|
||||
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
|
||||
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)
|
||||
|
||||
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)
|
||||
set_target_properties(editor PROPERTIES
|
||||
WIN32_EXECUTABLE ON
|
||||
)
|
||||
|
||||
# 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(
|
||||
|
@ -107,45 +64,37 @@ 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> ${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
|
||||
COMMAND ${WINDEPLOYQT_EXECUTABLE} $<TARGET_FILE:editor>
|
||||
${WINDEPLOYQT_OPTIONS}
|
||||
)
|
||||
# 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 ()
|
||||
|
||||
# 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()
|
||||
qt_finalize_executable(editor)
|
4
editor/deps.cmake
Normal file
4
editor/deps.cmake
Normal file
|
@ -0,0 +1,4 @@
|
|||
|
||||
include(CPM)
|
||||
|
||||
CPMAddPackage("gh:m-doescode/qcursorconstraints#cef1a31c0afad8ed3c95ee1a6bc531090805b510")
|
|
@ -7,25 +7,40 @@
|
|||
#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);
|
||||
|
||||
Logger::init();
|
||||
QCursorConstraints::init();
|
||||
|
||||
MainWindow w;
|
||||
w.show();
|
||||
int result = a.exec();
|
||||
|
||||
ma_engine_uninit(&miniaudio);
|
||||
Logger::finish();
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
#include <glm/common.hpp>
|
||||
#include <glm/vector_relational.hpp>
|
||||
#include <memory>
|
||||
#include <miniaudio.h>
|
||||
#include <qcursorconstraints.h>
|
||||
#include <qnamespace.h>
|
||||
#include <qsoundeffect.h>
|
||||
#include <qguiapplication.h>
|
||||
#include <string>
|
||||
#include "./ui_mainwindow.h"
|
||||
#include "mainglwidget.h"
|
||||
|
@ -35,15 +37,20 @@ MainGLWidget::MainGLWidget(QWidget* parent): QOpenGLWidget(parent), contextMenu(
|
|||
}
|
||||
|
||||
void MainGLWidget::initializeGL() {
|
||||
glewInit();
|
||||
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));
|
||||
}
|
||||
renderInit(width(), height());
|
||||
}
|
||||
|
||||
extern ma_engine miniaudio;
|
||||
inline void playSound(QString path) {
|
||||
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; });
|
||||
ma_engine_stop(&miniaudio);
|
||||
ma_engine_play_sound(&miniaudio, path.toStdString().c_str(), NULL);
|
||||
}
|
||||
|
||||
extern int vpx, vpy;
|
||||
|
@ -68,14 +75,11 @@ void MainGLWidget::paintGL() {
|
|||
}
|
||||
|
||||
bool isMouseRightDragging = false;
|
||||
QPoint lastMousePos;
|
||||
QPoint mouseLockedPos;
|
||||
void MainGLWidget::handleCameraRotate(QMouseEvent* evt) {
|
||||
if (!isMouseRightDragging) return;
|
||||
|
||||
camera.processRotation(evt->pos().x() - lastMousePos.x(), evt->pos().y() - lastMousePos.y());
|
||||
lastMousePos = evt->pos();
|
||||
|
||||
// QCursor::setPos(lastMousePos);
|
||||
camera.processRotation(evt->pos().x() - mouseLockedPos.x(), evt->pos().y() - mouseLockedPos.y());
|
||||
}
|
||||
|
||||
|
||||
|
@ -323,6 +327,7 @@ 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()));
|
||||
|
@ -373,8 +378,10 @@ void MainGLWidget::mousePressEvent(QMouseEvent* evt) {
|
|||
switch(evt->button()) {
|
||||
// Camera drag
|
||||
case Qt::RightButton: {
|
||||
lastMousePos = evt->pos();
|
||||
mouseLockedPos = evt->pos();
|
||||
isMouseRightDragging = true;
|
||||
setCursor(Qt::BlankCursor);
|
||||
QCursorConstraints::lockCursor(window()->windowHandle());
|
||||
return;
|
||||
// Clicking on objects
|
||||
} case Qt::LeftButton: {
|
||||
|
@ -459,11 +466,13 @@ 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;
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include "undohistory.h"
|
||||
#include "version.h"
|
||||
#include <memory>
|
||||
#include <QToolButton>
|
||||
#include <QSettings>
|
||||
#include <qclipboard.h>
|
||||
#include <qevent.h>
|
||||
#include <qglobal.h>
|
||||
|
@ -20,13 +22,14 @@
|
|||
#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
|
||||
|
@ -58,17 +61,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) {
|
||||
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; });
|
||||
ma_engine_play_sound(&miniaudio, path.toStdString().c_str(), NULL);
|
||||
}
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
, ui(new Ui::MainWindow)
|
||||
{
|
||||
loadState();
|
||||
|
||||
gDataModel->Init();
|
||||
|
||||
ui->setupUi(this);
|
||||
|
@ -104,6 +107,28 @@ 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);
|
||||
|
@ -127,6 +152,7 @@ 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
|
||||
|
@ -149,6 +175,64 @@ 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;
|
||||
|
@ -282,6 +366,7 @@ void MainWindow::connectActionHandlers() {
|
|||
}
|
||||
|
||||
editModeDataModel->SaveToFile(path);
|
||||
if (path) pushRecentFile(QString::fromStdString(path.value()));
|
||||
});
|
||||
|
||||
connect(ui->actionSaveAs, &QAction::triggered, this, [&]() {
|
||||
|
@ -289,6 +374,7 @@ void MainWindow::connectActionHandlers() {
|
|||
if (!path || path == "") return;
|
||||
|
||||
editModeDataModel->SaveToFile(path);
|
||||
if (path) pushRecentFile(QString::fromStdString(path.value()));
|
||||
});
|
||||
|
||||
connect(ui->actionOpen, &QAction::triggered, this, [&]() {
|
||||
|
@ -309,6 +395,7 @@ void MainWindow::connectActionHandlers() {
|
|||
placeDocument->setRunState(RUN_STOPPED);
|
||||
undoManager.Reset();
|
||||
updateToolbars();
|
||||
if (path) pushRecentFile(QString::fromStdString(path.value()));
|
||||
});
|
||||
|
||||
connect(ui->actionDelete, &QAction::triggered, this, [&]() {
|
||||
|
|
|
@ -64,10 +64,18 @@ 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;
|
||||
PlaceDocument* placeDocument = nullptr;
|
||||
|
||||
void setUpCommandBar();
|
||||
void connectActionHandlers();
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
#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
|
||||
|
@ -49,8 +53,14 @@ 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 {};
|
||||
}
|
||||
|
||||
|
@ -97,7 +107,15 @@ 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 {
|
||||
|
|
|
@ -107,7 +107,7 @@ void ExplorerView::buildContextMenu() {
|
|||
contextMenu.addMenu(insertObjectMenu);
|
||||
|
||||
for (const auto& [_, type] : INSTANCE_MAP) {
|
||||
if (type->flags & INSTANCE_NOTCREATABLE || !type->constructor) continue;
|
||||
if (type->flags & (INSTANCE_NOTCREATABLE | INSTANCE_HIDDEN) || !type->constructor) continue;
|
||||
|
||||
QAction* instAction = new QAction(model.iconOf(type), QString::fromStdString(type->className));
|
||||
insertObjectMenu->addAction(instAction);
|
||||
|
|
5914
external/glad/glad/gl.h
vendored
Normal file
5914
external/glad/glad/gl.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
14
patches/freetype_cmakever.patch
Normal file
14
patches/freetype_cmakever.patch
Normal file
|
@ -0,0 +1,14 @@
|
|||
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
|
0
vcpkg-overlays/reactphysics3d/std_chrono.patch → patches/std_chrono.patch
Executable file → Normal file
0
vcpkg-overlays/reactphysics3d/std_chrono.patch → patches/std_chrono.patch
Executable file → Normal file
14
tests/CMakeLists.txt
Normal file
14
tests/CMakeLists.txt
Normal file
|
@ -0,0 +1,14 @@
|
|||
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})
|
77
tests/src/luaschedtest.cpp
Normal file
77
tests/src/luaschedtest.cpp
Normal file
|
@ -0,0 +1,77 @@
|
|||
#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;
|
||||
}
|
103
tests/src/luasignaltest.cpp
Normal file
103
tests/src/luasignaltest.cpp
Normal file
|
@ -0,0 +1,103 @@
|
|||
|
||||
#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;
|
||||
}
|
20
tests/src/luatest.cpp
Normal file
20
tests/src/luatest.cpp
Normal file
|
@ -0,0 +1,20 @@
|
|||
#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;
|
||||
}
|
70
tests/src/testutil.h
Normal file
70
tests/src/testutil.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
#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;
|
||||
}
|
30
tests/src/testutillua.h
Normal file
30
tests/src/testutillua.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#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();
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
{
|
||||
"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"
|
||||
]
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
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")
|
|
@ -1,18 +0,0 @@
|
|||
{
|
||||
"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
20
vcpkg.json
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"dependencies": [
|
||||
"glew",
|
||||
"glfw3",
|
||||
"glm",
|
||||
{ "name": "pugixml", "version>=": "1.15" },
|
||||
"sdl2",
|
||||
"stb",
|
||||
"reactphysics3d",
|
||||
"pkgconf",
|
||||
"luajit",
|
||||
"freetype"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"name": "sdl2",
|
||||
"version": "2.32.4"
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Add table
Reference in a new issue