Compare commits
1 commit
master
...
patch/0.3.
Author | SHA1 | Date | |
---|---|---|---|
2a60994013 |
1
.clangd
|
@ -1,3 +1,2 @@
|
||||||
CompileFlags:
|
CompileFlags:
|
||||||
Add: [-std=c++20]
|
Add: [-std=c++20]
|
||||||
Remove: [-mno-direct-extern-access]
|
|
7
.vscode/launch.json
vendored
|
@ -4,13 +4,6 @@
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
|
||||||
"type": "gdb",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "Debug (gdb)",
|
|
||||||
"program": "${workspaceFolder}/build/bin/editor",
|
|
||||||
"cwd": "${workspaceFolder}",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "lldb",
|
"type": "lldb",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
|
|
32
BUILD.md
|
@ -1,27 +1,20 @@
|
||||||
# Building on Linux
|
# 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:
|
Use the following to generate the build files:
|
||||||
|
|
||||||
cmake -Bbuild .
|
cmake -Bbuild .
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> Add -DCMAKE_BUILD_TYPE=Release to produce a release build
|
|
||||||
|
|
||||||
Then build the project using:
|
Then build the project using:
|
||||||
|
|
||||||
cmake --build build
|
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
|
# Building on Windows
|
||||||
|
|
||||||
The process is very similar on Windows
|
The project will be built using VCPKG and MSVC
|
||||||
|
|
||||||
## Pre-requisites
|
## Pre-requisites
|
||||||
|
|
||||||
|
@ -29,7 +22,6 @@ The process is very similar on Windows
|
||||||
* Qt 6.8.3 or higher, with MSVC toolchain
|
* Qt 6.8.3 or higher, with MSVC toolchain
|
||||||
* CMake
|
* CMake
|
||||||
* Git (for cloning the repo, optional)
|
* 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\**
|
* QScintilla already built (see [docs/qscintilla.md](./docs/qscintilla.md)) *\*likely temporary\**
|
||||||
|
|
||||||
To start, clone the repository:
|
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
|
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]
|
The compiled binaries should then be placed in `./build/bin/` and should be ready for redistribution without any further work.
|
||||||
> 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 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
|
|
@ -10,7 +10,6 @@ else()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" )
|
set( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" )
|
||||||
set(USE_CCACHE ON)
|
|
||||||
|
|
||||||
add_subdirectory(autogen)
|
add_subdirectory(autogen)
|
||||||
|
|
||||||
|
@ -25,6 +24,4 @@ add_subdirectory(client)
|
||||||
add_subdirectory(editor)
|
add_subdirectory(editor)
|
||||||
|
|
||||||
|
|
||||||
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/tests )
|
install(FILES $<TARGET_RUNTIME_DLLS:editor> TYPE BIN)
|
||||||
enable_testing()
|
|
||||||
add_subdirectory(tests)
|
|
21
CMakePresets.json
Normal 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
|
@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
sphere.obj was made by subdividing a cube, unwrapping it using cube projection, and then using the "To-sphere" tool in Blender to fully smoothen it out.
|
|
||||||
Make sure you select "shade smooth" before exporting!
|
|
||||||
|
|
||||||
Other settings:
|
|
||||||
Up axis: Y
|
|
||||||
Forward axis: -Z
|
|
||||||
|
|
||||||
The winding order in .obj files is always counter-clockwise, so my script (genmesh.py) uses reversed() to reverse this and homogenous the winding order
|
|
||||||
across meshes
|
|
|
@ -1,565 +0,0 @@
|
||||||
# Blender 4.4.0
|
|
||||||
# www.blender.org
|
|
||||||
mtllib arc.mtl
|
|
||||||
o Torus.001
|
|
||||||
v 1.090000 0.000000 0.000000
|
|
||||||
v 1.060000 0.051962 0.000000
|
|
||||||
v 1.000000 0.051962 0.000000
|
|
||||||
v 0.970000 0.000000 0.000000
|
|
||||||
v 1.000000 -0.051962 0.000000
|
|
||||||
v 1.060000 -0.051962 0.000000
|
|
||||||
v 1.030941 0.000000 -0.353922
|
|
||||||
v 1.002566 0.051962 -0.344181
|
|
||||||
v 0.945817 0.051962 -0.324699
|
|
||||||
v 0.917443 0.000000 -0.314958
|
|
||||||
v 0.945817 -0.051962 -0.324699
|
|
||||||
v 1.002566 -0.051962 -0.344181
|
|
||||||
v 0.860163 0.000000 -0.669492
|
|
||||||
v 0.836489 0.051962 -0.651065
|
|
||||||
v 0.789140 0.051962 -0.614213
|
|
||||||
v 0.765466 0.000000 -0.595786
|
|
||||||
v 0.789140 -0.051962 -0.614213
|
|
||||||
v 0.836489 -0.051962 -0.651065
|
|
||||||
v 0.596173 0.000000 -0.912512
|
|
||||||
v 0.579765 0.051962 -0.887396
|
|
||||||
v 0.546948 0.051962 -0.837166
|
|
||||||
v 0.530540 0.000000 -0.812051
|
|
||||||
v 0.546948 -0.051962 -0.837166
|
|
||||||
v 0.579765 -0.051962 -0.887396
|
|
||||||
v 0.267579 0.000000 -1.056646
|
|
||||||
v 0.260214 0.051962 -1.027564
|
|
||||||
v 0.245485 0.051962 -0.969400
|
|
||||||
v 0.238121 0.000000 -0.940318
|
|
||||||
v 0.245485 -0.051962 -0.969400
|
|
||||||
v 0.260214 -0.051962 -1.027564
|
|
||||||
v -0.090011 0.000000 -1.086277
|
|
||||||
v -0.087534 0.051962 -1.056379
|
|
||||||
v -0.082579 0.051962 -0.996584
|
|
||||||
v -0.080102 0.000000 -0.966687
|
|
||||||
v -0.082579 -0.051962 -0.996584
|
|
||||||
v -0.087534 -0.051962 -1.056379
|
|
||||||
v -0.437848 0.000000 -0.998193
|
|
||||||
v -0.425797 0.051962 -0.970720
|
|
||||||
v -0.401695 0.051962 -0.915773
|
|
||||||
v -0.389644 0.000000 -0.888300
|
|
||||||
v -0.401695 -0.051962 -0.915773
|
|
||||||
v -0.425797 -0.051962 -0.970720
|
|
||||||
v -0.738237 0.000000 -0.801939
|
|
||||||
v -0.717918 0.051962 -0.779867
|
|
||||||
v -0.677281 0.051962 -0.735724
|
|
||||||
v -0.656963 0.000000 -0.713652
|
|
||||||
v -0.677281 -0.051962 -0.735724
|
|
||||||
v -0.717918 -0.051962 -0.779867
|
|
||||||
v -0.958627 0.000000 -0.518782
|
|
||||||
v -0.932242 0.051962 -0.504504
|
|
||||||
v -0.879474 0.051962 -0.475947
|
|
||||||
v -0.853090 0.000000 -0.461669
|
|
||||||
v -0.879474 -0.051962 -0.475947
|
|
||||||
v -0.932242 -0.051962 -0.504504
|
|
||||||
v -1.075134 0.000000 -0.179408
|
|
||||||
v -1.045543 0.051962 -0.174470
|
|
||||||
v -0.986361 0.051962 -0.164595
|
|
||||||
v -0.956770 0.000000 -0.159657
|
|
||||||
v -0.986361 -0.051962 -0.164595
|
|
||||||
v -1.045543 -0.051962 -0.174470
|
|
||||||
v -1.075134 0.000000 0.179408
|
|
||||||
v -1.045543 0.051962 0.174470
|
|
||||||
v -0.986361 0.051962 0.164594
|
|
||||||
v -0.956771 0.000000 0.159656
|
|
||||||
v -0.986361 -0.051962 0.164594
|
|
||||||
v -1.045543 -0.051962 0.174470
|
|
||||||
v -0.958627 0.000000 0.518782
|
|
||||||
v -0.932242 0.051962 0.504504
|
|
||||||
v -0.879474 0.051962 0.475947
|
|
||||||
v -0.853090 0.000000 0.461669
|
|
||||||
v -0.879474 -0.051962 0.475947
|
|
||||||
v -0.932242 -0.051962 0.504504
|
|
||||||
v -0.738237 0.000000 0.801939
|
|
||||||
v -0.717918 0.051962 0.779867
|
|
||||||
v -0.677281 0.051962 0.735724
|
|
||||||
v -0.656963 0.000000 0.713652
|
|
||||||
v -0.677281 -0.051962 0.735724
|
|
||||||
v -0.717918 -0.051962 0.779867
|
|
||||||
v -0.437848 0.000000 0.998193
|
|
||||||
v -0.425797 0.051962 0.970720
|
|
||||||
v -0.401695 0.051962 0.915773
|
|
||||||
v -0.389644 0.000000 0.888300
|
|
||||||
v -0.401695 -0.051962 0.915773
|
|
||||||
v -0.425797 -0.051962 0.970720
|
|
||||||
v -0.090012 0.000000 1.086277
|
|
||||||
v -0.087535 0.051962 1.056379
|
|
||||||
v -0.082580 0.051962 0.996584
|
|
||||||
v -0.080102 0.000000 0.966687
|
|
||||||
v -0.082580 -0.051962 0.996584
|
|
||||||
v -0.087535 -0.051962 1.056379
|
|
||||||
v 0.267579 0.000000 1.056646
|
|
||||||
v 0.260214 0.051962 1.027564
|
|
||||||
v 0.245485 0.051962 0.969400
|
|
||||||
v 0.238121 0.000000 0.940318
|
|
||||||
v 0.245485 -0.051962 0.969400
|
|
||||||
v 0.260214 -0.051962 1.027564
|
|
||||||
v 0.596173 0.000000 0.912512
|
|
||||||
v 0.579765 0.051962 0.887396
|
|
||||||
v 0.546948 0.051962 0.837166
|
|
||||||
v 0.530540 0.000000 0.812051
|
|
||||||
v 0.546948 -0.051962 0.837166
|
|
||||||
v 0.579765 -0.051962 0.887396
|
|
||||||
v 0.860163 0.000000 0.669492
|
|
||||||
v 0.836489 0.051962 0.651065
|
|
||||||
v 0.789141 0.051962 0.614212
|
|
||||||
v 0.765466 0.000000 0.595786
|
|
||||||
v 0.789141 -0.051962 0.614212
|
|
||||||
v 0.836489 -0.051962 0.651065
|
|
||||||
v 1.030941 0.000000 0.353923
|
|
||||||
v 1.002566 0.051962 0.344182
|
|
||||||
v 0.945817 0.051962 0.324700
|
|
||||||
v 0.917443 0.000000 0.314959
|
|
||||||
v 0.945817 -0.051962 0.324700
|
|
||||||
v 1.002566 -0.051962 0.344182
|
|
||||||
vn 0.8571 0.4949 -0.1430
|
|
||||||
vn -0.0000 1.0000 -0.0000
|
|
||||||
vn -0.8571 0.4949 0.1430
|
|
||||||
vn -0.8571 -0.4949 0.1430
|
|
||||||
vn -0.0000 -1.0000 -0.0000
|
|
||||||
vn 0.8571 -0.4949 -0.1430
|
|
||||||
vn 0.7642 0.4949 -0.4136
|
|
||||||
vn -0.7642 0.4949 0.4136
|
|
||||||
vn -0.7642 -0.4949 0.4136
|
|
||||||
vn 0.7642 -0.4949 -0.4136
|
|
||||||
vn 0.5885 0.4949 -0.6393
|
|
||||||
vn -0.5885 0.4949 0.6393
|
|
||||||
vn -0.5885 -0.4949 0.6393
|
|
||||||
vn 0.5885 -0.4949 -0.6393
|
|
||||||
vn 0.3491 0.4949 -0.7958
|
|
||||||
vn -0.3491 0.4949 0.7958
|
|
||||||
vn -0.3491 -0.4949 0.7958
|
|
||||||
vn 0.3491 -0.4949 -0.7958
|
|
||||||
vn 0.0718 0.4949 -0.8660
|
|
||||||
vn -0.0718 0.4949 0.8660
|
|
||||||
vn -0.0718 -0.4949 0.8660
|
|
||||||
vn 0.0718 -0.4949 -0.8660
|
|
||||||
vn -0.2133 0.4949 -0.8424
|
|
||||||
vn 0.2133 0.4949 0.8424
|
|
||||||
vn 0.2133 -0.4949 0.8424
|
|
||||||
vn -0.2133 -0.4949 -0.8424
|
|
||||||
vn -0.4753 0.4949 -0.7275
|
|
||||||
vn 0.4753 0.4949 0.7275
|
|
||||||
vn 0.4753 -0.4949 0.7275
|
|
||||||
vn -0.4753 -0.4949 -0.7275
|
|
||||||
vn -0.6857 0.4949 -0.5337
|
|
||||||
vn 0.6857 0.4949 0.5337
|
|
||||||
vn 0.6857 -0.4949 0.5337
|
|
||||||
vn -0.6857 -0.4949 -0.5337
|
|
||||||
vn -0.8219 0.4949 -0.2822
|
|
||||||
vn 0.8219 0.4949 0.2822
|
|
||||||
vn 0.8219 -0.4949 0.2822
|
|
||||||
vn -0.8219 -0.4949 -0.2822
|
|
||||||
vn -0.8690 0.4949 -0.0000
|
|
||||||
vn 0.8690 0.4949 -0.0000
|
|
||||||
vn 0.8690 -0.4949 -0.0000
|
|
||||||
vn -0.8690 -0.4949 -0.0000
|
|
||||||
vn -0.8219 0.4949 0.2822
|
|
||||||
vn 0.8219 0.4949 -0.2822
|
|
||||||
vn 0.8219 -0.4949 -0.2822
|
|
||||||
vn -0.8219 -0.4949 0.2822
|
|
||||||
vn -0.6857 0.4949 0.5337
|
|
||||||
vn 0.6857 0.4949 -0.5337
|
|
||||||
vn 0.6857 -0.4949 -0.5337
|
|
||||||
vn -0.6857 -0.4949 0.5337
|
|
||||||
vn -0.4753 0.4949 0.7275
|
|
||||||
vn 0.4753 0.4949 -0.7275
|
|
||||||
vn 0.4753 -0.4949 -0.7275
|
|
||||||
vn -0.4753 -0.4949 0.7275
|
|
||||||
vn -0.2133 0.4949 0.8424
|
|
||||||
vn 0.2133 0.4949 -0.8424
|
|
||||||
vn 0.2133 -0.4949 -0.8424
|
|
||||||
vn -0.2133 -0.4949 0.8424
|
|
||||||
vn 0.0718 0.4949 0.8660
|
|
||||||
vn -0.0718 0.4949 -0.8660
|
|
||||||
vn -0.0718 -0.4949 -0.8660
|
|
||||||
vn 0.0718 -0.4949 0.8660
|
|
||||||
vn 0.3491 0.4949 0.7958
|
|
||||||
vn -0.3491 0.4949 -0.7958
|
|
||||||
vn -0.3491 -0.4949 -0.7958
|
|
||||||
vn 0.3491 -0.4949 0.7958
|
|
||||||
vn 0.5885 0.4949 0.6393
|
|
||||||
vn -0.5885 0.4949 -0.6393
|
|
||||||
vn -0.5885 -0.4949 -0.6393
|
|
||||||
vn 0.5885 -0.4949 0.6393
|
|
||||||
vn 0.7642 0.4949 0.4136
|
|
||||||
vn -0.7642 0.4949 -0.4136
|
|
||||||
vn -0.7642 -0.4949 -0.4136
|
|
||||||
vn 0.7642 -0.4949 0.4136
|
|
||||||
vn 0.8571 0.4949 0.1430
|
|
||||||
vn -0.8571 0.4949 -0.1430
|
|
||||||
vn -0.8571 -0.4949 -0.1430
|
|
||||||
vn 0.8571 -0.4949 0.1430
|
|
||||||
vt 0.526316 0.500000
|
|
||||||
vt 0.578947 0.666667
|
|
||||||
vt 0.526316 0.666667
|
|
||||||
vt 0.526316 0.833333
|
|
||||||
vt 0.578947 0.833333
|
|
||||||
vt 0.526316 1.000000
|
|
||||||
vt 0.578947 -0.000000
|
|
||||||
vt 0.526316 0.166667
|
|
||||||
vt 0.526316 -0.000000
|
|
||||||
vt 0.578947 0.333333
|
|
||||||
vt 0.526316 0.333333
|
|
||||||
vt 0.578947 0.500000
|
|
||||||
vt 0.631579 0.500000
|
|
||||||
vt 0.631579 0.666667
|
|
||||||
vt 0.631579 0.833333
|
|
||||||
vt 0.578947 1.000000
|
|
||||||
vt 0.631579 -0.000000
|
|
||||||
vt 0.578947 0.166667
|
|
||||||
vt 0.631579 0.166667
|
|
||||||
vt 0.684211 0.500000
|
|
||||||
vt 0.684211 0.666667
|
|
||||||
vt 0.684211 0.833333
|
|
||||||
vt 0.631579 1.000000
|
|
||||||
vt 0.684211 0.166667
|
|
||||||
vt 0.631579 0.333333
|
|
||||||
vt 0.684211 0.333333
|
|
||||||
vt 0.736842 0.666667
|
|
||||||
vt 0.736842 0.833333
|
|
||||||
vt 0.684211 1.000000
|
|
||||||
vt 0.736842 -0.000000
|
|
||||||
vt 0.684211 -0.000000
|
|
||||||
vt 0.736842 0.333333
|
|
||||||
vt 0.789474 0.500000
|
|
||||||
vt 0.736842 0.500000
|
|
||||||
vt 0.789474 0.666667
|
|
||||||
vt 0.789474 0.833333
|
|
||||||
vt 0.736842 1.000000
|
|
||||||
vt 0.789474 -0.000000
|
|
||||||
vt 0.736842 0.166667
|
|
||||||
vt 0.789474 0.166667
|
|
||||||
vt 0.789474 0.333333
|
|
||||||
vt 0.842105 0.666667
|
|
||||||
vt 0.842105 0.833333
|
|
||||||
vt 0.789474 1.000000
|
|
||||||
vt 0.842105 -0.000000
|
|
||||||
vt 0.842105 0.166667
|
|
||||||
vt 0.842105 0.333333
|
|
||||||
vt 0.842105 0.500000
|
|
||||||
vt 0.894737 0.666667
|
|
||||||
vt 0.894737 0.833333
|
|
||||||
vt 0.842105 1.000000
|
|
||||||
vt 0.894737 -0.000000
|
|
||||||
vt 0.894737 0.333333
|
|
||||||
vt 0.894737 0.500000
|
|
||||||
vt 0.947368 0.666667
|
|
||||||
vt 0.947368 0.833333
|
|
||||||
vt 0.894737 1.000000
|
|
||||||
vt 0.947368 -0.000000
|
|
||||||
vt 0.894737 0.166667
|
|
||||||
vt 0.947368 0.333333
|
|
||||||
vt 0.947368 0.500000
|
|
||||||
vt 1.000000 0.666667
|
|
||||||
vt 1.000000 0.833333
|
|
||||||
vt 0.947368 1.000000
|
|
||||||
vt 1.000000 -0.000000
|
|
||||||
vt 0.947368 0.166667
|
|
||||||
vt 1.000000 0.166667
|
|
||||||
vt 1.000000 0.333333
|
|
||||||
vt 0.052632 0.500000
|
|
||||||
vt -0.000000 0.666667
|
|
||||||
vt -0.000000 0.500000
|
|
||||||
vt 0.052632 0.666667
|
|
||||||
vt -0.000000 0.833333
|
|
||||||
vt 0.052632 1.000000
|
|
||||||
vt -0.000000 1.000000
|
|
||||||
vt 0.052632 -0.000000
|
|
||||||
vt -0.000000 0.166667
|
|
||||||
vt -0.000000 -0.000000
|
|
||||||
vt 0.052632 0.166667
|
|
||||||
vt -0.000000 0.333333
|
|
||||||
vt 0.052632 0.333333
|
|
||||||
vt 0.105263 0.500000
|
|
||||||
vt 0.105263 0.833333
|
|
||||||
vt 0.052632 0.833333
|
|
||||||
vt 0.105263 1.000000
|
|
||||||
vt 0.105263 -0.000000
|
|
||||||
vt 0.105263 0.166667
|
|
||||||
vt 0.157895 0.500000
|
|
||||||
vt 0.105263 0.666667
|
|
||||||
vt 0.157895 0.666667
|
|
||||||
vt 0.157895 0.833333
|
|
||||||
vt 0.157895 0.166667
|
|
||||||
vt 0.105263 0.333333
|
|
||||||
vt 0.210526 0.500000
|
|
||||||
vt 0.210526 0.833333
|
|
||||||
vt 0.157895 1.000000
|
|
||||||
vt 0.210526 -0.000000
|
|
||||||
vt 0.157895 -0.000000
|
|
||||||
vt 0.210526 0.166667
|
|
||||||
vt 0.157895 0.333333
|
|
||||||
vt 0.210526 0.333333
|
|
||||||
vt 0.263158 0.500000
|
|
||||||
vt 0.210526 0.666667
|
|
||||||
vt 0.263158 0.666667
|
|
||||||
vt 0.263158 0.833333
|
|
||||||
vt 0.210526 1.000000
|
|
||||||
vt 0.263158 0.166667
|
|
||||||
vt 0.263158 0.333333
|
|
||||||
vt 0.315789 0.500000
|
|
||||||
vt 0.315789 0.833333
|
|
||||||
vt 0.263158 1.000000
|
|
||||||
vt 0.315789 -0.000000
|
|
||||||
vt 0.263158 -0.000000
|
|
||||||
vt 0.315789 0.166667
|
|
||||||
vt 0.315789 0.333333
|
|
||||||
vt 0.368421 0.500000
|
|
||||||
vt 0.315789 0.666667
|
|
||||||
vt 0.368421 0.833333
|
|
||||||
vt 0.315789 1.000000
|
|
||||||
vt 0.368421 -0.000000
|
|
||||||
vt 0.368421 0.166667
|
|
||||||
vt 0.421053 0.666667
|
|
||||||
vt 0.368421 0.666667
|
|
||||||
vt 0.421053 0.833333
|
|
||||||
vt 0.368421 1.000000
|
|
||||||
vt 0.421053 -0.000000
|
|
||||||
vt 0.421053 0.333333
|
|
||||||
vt 0.368421 0.333333
|
|
||||||
vt 0.421053 0.500000
|
|
||||||
vt 0.473684 0.666667
|
|
||||||
vt 0.473684 0.833333
|
|
||||||
vt 0.421053 1.000000
|
|
||||||
vt 0.473684 -0.000000
|
|
||||||
vt 0.421053 0.166667
|
|
||||||
vt 0.473684 0.166667
|
|
||||||
vt 0.473684 0.333333
|
|
||||||
vt 0.473684 0.500000
|
|
||||||
vt 0.473684 1.000000
|
|
||||||
vt 1.000000 0.500000
|
|
||||||
vt 1.000000 1.000000
|
|
||||||
s 0
|
|
||||||
f 1/1/1 8/2/1 2/3/1
|
|
||||||
f 8/2/2 3/4/2 2/3/2
|
|
||||||
f 9/5/3 4/6/3 3/4/3
|
|
||||||
f 10/7/4 5/8/4 4/9/4
|
|
||||||
f 5/8/5 12/10/5 6/11/5
|
|
||||||
f 6/11/6 7/12/6 1/1/6
|
|
||||||
f 13/13/7 8/2/7 7/12/7
|
|
||||||
f 14/14/2 9/5/2 8/2/2
|
|
||||||
f 15/15/8 10/16/8 9/5/8
|
|
||||||
f 16/17/9 11/18/9 10/7/9
|
|
||||||
f 17/19/5 12/10/5 11/18/5
|
|
||||||
f 12/10/10 13/13/10 7/12/10
|
|
||||||
f 19/20/11 14/14/11 13/13/11
|
|
||||||
f 20/21/2 15/15/2 14/14/2
|
|
||||||
f 21/22/12 16/23/12 15/15/12
|
|
||||||
f 16/17/13 23/24/13 17/19/13
|
|
||||||
f 23/24/5 18/25/5 17/19/5
|
|
||||||
f 24/26/14 13/13/14 18/25/14
|
|
||||||
f 19/20/15 26/27/15 20/21/15
|
|
||||||
f 20/21/2 27/28/2 21/22/2
|
|
||||||
f 27/28/16 22/29/16 21/22/16
|
|
||||||
f 28/30/17 23/24/17 22/31/17
|
|
||||||
f 23/24/5 30/32/5 24/26/5
|
|
||||||
f 30/32/18 19/20/18 24/26/18
|
|
||||||
f 31/33/19 26/27/19 25/34/19
|
|
||||||
f 32/35/2 27/28/2 26/27/2
|
|
||||||
f 33/36/20 28/37/20 27/28/20
|
|
||||||
f 34/38/21 29/39/21 28/30/21
|
|
||||||
f 35/40/5 30/32/5 29/39/5
|
|
||||||
f 36/41/22 25/34/22 30/32/22
|
|
||||||
f 31/33/23 38/42/23 32/35/23
|
|
||||||
f 32/35/2 39/43/2 33/36/2
|
|
||||||
f 39/43/24 34/44/24 33/36/24
|
|
||||||
f 40/45/25 35/40/25 34/38/25
|
|
||||||
f 41/46/5 36/41/5 35/40/5
|
|
||||||
f 42/47/26 31/33/26 36/41/26
|
|
||||||
f 37/48/27 44/49/27 38/42/27
|
|
||||||
f 44/49/2 39/43/2 38/42/2
|
|
||||||
f 45/50/28 40/51/28 39/43/28
|
|
||||||
f 46/52/29 41/46/29 40/45/29
|
|
||||||
f 41/46/5 48/53/5 42/47/5
|
|
||||||
f 48/53/30 37/48/30 42/47/30
|
|
||||||
f 43/54/31 50/55/31 44/49/31
|
|
||||||
f 44/49/2 51/56/2 45/50/2
|
|
||||||
f 51/56/32 46/57/32 45/50/32
|
|
||||||
f 52/58/33 47/59/33 46/52/33
|
|
||||||
f 47/59/5 54/60/5 48/53/5
|
|
||||||
f 54/60/34 43/54/34 48/53/34
|
|
||||||
f 49/61/35 56/62/35 50/55/35
|
|
||||||
f 56/62/2 51/56/2 50/55/2
|
|
||||||
f 57/63/36 52/64/36 51/56/36
|
|
||||||
f 58/65/37 53/66/37 52/58/37
|
|
||||||
f 59/67/5 54/60/5 53/66/5
|
|
||||||
f 60/68/38 49/61/38 54/60/38
|
|
||||||
f 61/69/39 56/70/39 55/71/39
|
|
||||||
f 62/72/2 57/73/2 56/70/2
|
|
||||||
f 57/73/40 64/74/40 58/75/40
|
|
||||||
f 64/76/41 59/77/41 58/78/41
|
|
||||||
f 65/79/5 60/80/5 59/77/5
|
|
||||||
f 66/81/42 55/71/42 60/80/42
|
|
||||||
f 67/82/43 62/72/43 61/69/43
|
|
||||||
f 62/72/2 69/83/2 63/84/2
|
|
||||||
f 63/84/44 70/85/44 64/74/44
|
|
||||||
f 70/86/45 65/79/45 64/76/45
|
|
||||||
f 71/87/5 66/81/5 65/79/5
|
|
||||||
f 66/81/46 67/82/46 61/69/46
|
|
||||||
f 73/88/47 68/89/47 67/82/47
|
|
||||||
f 74/90/2 69/83/2 68/89/2
|
|
||||||
f 75/91/48 70/85/48 69/83/48
|
|
||||||
f 70/86/49 77/92/49 71/87/49
|
|
||||||
f 77/92/5 72/93/5 71/87/5
|
|
||||||
f 72/93/50 73/88/50 67/82/50
|
|
||||||
f 79/94/51 74/90/51 73/88/51
|
|
||||||
f 74/90/2 81/95/2 75/91/2
|
|
||||||
f 81/95/52 76/96/52 75/91/52
|
|
||||||
f 82/97/53 77/92/53 76/98/53
|
|
||||||
f 83/99/5 78/100/5 77/92/5
|
|
||||||
f 84/101/54 73/88/54 78/100/54
|
|
||||||
f 85/102/55 80/103/55 79/94/55
|
|
||||||
f 86/104/2 81/95/2 80/103/2
|
|
||||||
f 87/105/56 82/106/56 81/95/56
|
|
||||||
f 82/97/57 89/107/57 83/99/57
|
|
||||||
f 89/107/5 84/101/5 83/99/5
|
|
||||||
f 90/108/58 79/94/58 84/101/58
|
|
||||||
f 91/109/59 86/104/59 85/102/59
|
|
||||||
f 86/104/2 93/110/2 87/105/2
|
|
||||||
f 93/110/60 88/111/60 87/105/60
|
|
||||||
f 94/112/61 89/107/61 88/113/61
|
|
||||||
f 95/114/5 90/108/5 89/107/5
|
|
||||||
f 96/115/62 85/102/62 90/108/62
|
|
||||||
f 97/116/63 92/117/63 91/109/63
|
|
||||||
f 92/117/2 99/118/2 93/110/2
|
|
||||||
f 99/118/64 94/119/64 93/110/64
|
|
||||||
f 100/120/65 95/114/65 94/112/65
|
|
||||||
f 101/121/5 96/115/5 95/114/5
|
|
||||||
f 96/115/66 97/116/66 91/109/66
|
|
||||||
f 97/116/67 104/122/67 98/123/67
|
|
||||||
f 104/122/2 99/118/2 98/123/2
|
|
||||||
f 105/124/68 100/125/68 99/118/68
|
|
||||||
f 106/126/69 101/121/69 100/120/69
|
|
||||||
f 101/121/5 108/127/5 102/128/5
|
|
||||||
f 108/127/70 97/116/70 102/128/70
|
|
||||||
f 103/129/71 110/130/71 104/122/71
|
|
||||||
f 110/130/2 105/124/2 104/122/2
|
|
||||||
f 111/131/72 106/132/72 105/124/72
|
|
||||||
f 112/133/73 107/134/73 106/126/73
|
|
||||||
f 113/135/5 108/127/5 107/134/5
|
|
||||||
f 114/136/74 103/129/74 108/127/74
|
|
||||||
f 1/1/75 110/130/75 109/137/75
|
|
||||||
f 2/3/2 111/131/2 110/130/2
|
|
||||||
f 3/4/76 112/138/76 111/131/76
|
|
||||||
f 4/9/77 113/135/77 112/133/77
|
|
||||||
f 5/8/5 114/136/5 113/135/5
|
|
||||||
f 6/11/78 109/137/78 114/136/78
|
|
||||||
f 1/1/1 7/12/1 8/2/1
|
|
||||||
f 8/2/2 9/5/2 3/4/2
|
|
||||||
f 9/5/3 10/16/3 4/6/3
|
|
||||||
f 10/7/4 11/18/4 5/8/4
|
|
||||||
f 5/8/5 11/18/5 12/10/5
|
|
||||||
f 6/11/6 12/10/6 7/12/6
|
|
||||||
f 13/13/7 14/14/7 8/2/7
|
|
||||||
f 14/14/2 15/15/2 9/5/2
|
|
||||||
f 15/15/8 16/23/8 10/16/8
|
|
||||||
f 16/17/9 17/19/9 11/18/9
|
|
||||||
f 17/19/5 18/25/5 12/10/5
|
|
||||||
f 12/10/10 18/25/10 13/13/10
|
|
||||||
f 19/20/11 20/21/11 14/14/11
|
|
||||||
f 20/21/2 21/22/2 15/15/2
|
|
||||||
f 21/22/12 22/29/12 16/23/12
|
|
||||||
f 16/17/13 22/31/13 23/24/13
|
|
||||||
f 23/24/5 24/26/5 18/25/5
|
|
||||||
f 24/26/14 19/20/14 13/13/14
|
|
||||||
f 19/20/15 25/34/15 26/27/15
|
|
||||||
f 20/21/2 26/27/2 27/28/2
|
|
||||||
f 27/28/16 28/37/16 22/29/16
|
|
||||||
f 28/30/17 29/39/17 23/24/17
|
|
||||||
f 23/24/5 29/39/5 30/32/5
|
|
||||||
f 30/32/18 25/34/18 19/20/18
|
|
||||||
f 31/33/19 32/35/19 26/27/19
|
|
||||||
f 32/35/2 33/36/2 27/28/2
|
|
||||||
f 33/36/20 34/44/20 28/37/20
|
|
||||||
f 34/38/21 35/40/21 29/39/21
|
|
||||||
f 35/40/5 36/41/5 30/32/5
|
|
||||||
f 36/41/22 31/33/22 25/34/22
|
|
||||||
f 31/33/23 37/48/23 38/42/23
|
|
||||||
f 32/35/2 38/42/2 39/43/2
|
|
||||||
f 39/43/24 40/51/24 34/44/24
|
|
||||||
f 40/45/25 41/46/25 35/40/25
|
|
||||||
f 41/46/5 42/47/5 36/41/5
|
|
||||||
f 42/47/26 37/48/26 31/33/26
|
|
||||||
f 37/48/27 43/54/27 44/49/27
|
|
||||||
f 44/49/2 45/50/2 39/43/2
|
|
||||||
f 45/50/28 46/57/28 40/51/28
|
|
||||||
f 46/52/29 47/59/29 41/46/29
|
|
||||||
f 41/46/5 47/59/5 48/53/5
|
|
||||||
f 48/53/30 43/54/30 37/48/30
|
|
||||||
f 43/54/31 49/61/31 50/55/31
|
|
||||||
f 44/49/2 50/55/2 51/56/2
|
|
||||||
f 51/56/32 52/64/32 46/57/32
|
|
||||||
f 52/58/33 53/66/33 47/59/33
|
|
||||||
f 47/59/5 53/66/5 54/60/5
|
|
||||||
f 54/60/34 49/61/34 43/54/34
|
|
||||||
f 49/61/35 55/139/35 56/62/35
|
|
||||||
f 56/62/2 57/63/2 51/56/2
|
|
||||||
f 57/63/36 58/140/36 52/64/36
|
|
||||||
f 58/65/37 59/67/37 53/66/37
|
|
||||||
f 59/67/5 60/68/5 54/60/5
|
|
||||||
f 60/68/38 55/139/38 49/61/38
|
|
||||||
f 61/69/39 62/72/39 56/70/39
|
|
||||||
f 62/72/2 63/84/2 57/73/2
|
|
||||||
f 57/73/40 63/84/40 64/74/40
|
|
||||||
f 64/76/41 65/79/41 59/77/41
|
|
||||||
f 65/79/5 66/81/5 60/80/5
|
|
||||||
f 66/81/42 61/69/42 55/71/42
|
|
||||||
f 67/82/43 68/89/43 62/72/43
|
|
||||||
f 62/72/2 68/89/2 69/83/2
|
|
||||||
f 63/84/44 69/83/44 70/85/44
|
|
||||||
f 70/86/45 71/87/45 65/79/45
|
|
||||||
f 71/87/5 72/93/5 66/81/5
|
|
||||||
f 66/81/46 72/93/46 67/82/46
|
|
||||||
f 73/88/47 74/90/47 68/89/47
|
|
||||||
f 74/90/2 75/91/2 69/83/2
|
|
||||||
f 75/91/48 76/96/48 70/85/48
|
|
||||||
f 70/86/49 76/98/49 77/92/49
|
|
||||||
f 77/92/5 78/100/5 72/93/5
|
|
||||||
f 72/93/50 78/100/50 73/88/50
|
|
||||||
f 79/94/51 80/103/51 74/90/51
|
|
||||||
f 74/90/2 80/103/2 81/95/2
|
|
||||||
f 81/95/52 82/106/52 76/96/52
|
|
||||||
f 82/97/53 83/99/53 77/92/53
|
|
||||||
f 83/99/5 84/101/5 78/100/5
|
|
||||||
f 84/101/54 79/94/54 73/88/54
|
|
||||||
f 85/102/55 86/104/55 80/103/55
|
|
||||||
f 86/104/2 87/105/2 81/95/2
|
|
||||||
f 87/105/56 88/111/56 82/106/56
|
|
||||||
f 82/97/57 88/113/57 89/107/57
|
|
||||||
f 89/107/5 90/108/5 84/101/5
|
|
||||||
f 90/108/58 85/102/58 79/94/58
|
|
||||||
f 91/109/59 92/117/59 86/104/59
|
|
||||||
f 86/104/2 92/117/2 93/110/2
|
|
||||||
f 93/110/60 94/119/60 88/111/60
|
|
||||||
f 94/112/61 95/114/61 89/107/61
|
|
||||||
f 95/114/5 96/115/5 90/108/5
|
|
||||||
f 96/115/62 91/109/62 85/102/62
|
|
||||||
f 97/116/63 98/123/63 92/117/63
|
|
||||||
f 92/117/2 98/123/2 99/118/2
|
|
||||||
f 99/118/64 100/125/64 94/119/64
|
|
||||||
f 100/120/65 101/121/65 95/114/65
|
|
||||||
f 101/121/5 102/128/5 96/115/5
|
|
||||||
f 96/115/66 102/128/66 97/116/66
|
|
||||||
f 97/116/67 103/129/67 104/122/67
|
|
||||||
f 104/122/2 105/124/2 99/118/2
|
|
||||||
f 105/124/68 106/132/68 100/125/68
|
|
||||||
f 106/126/69 107/134/69 101/121/69
|
|
||||||
f 101/121/5 107/134/5 108/127/5
|
|
||||||
f 108/127/70 103/129/70 97/116/70
|
|
||||||
f 103/129/71 109/137/71 110/130/71
|
|
||||||
f 110/130/2 111/131/2 105/124/2
|
|
||||||
f 111/131/72 112/138/72 106/132/72
|
|
||||||
f 112/133/73 113/135/73 107/134/73
|
|
||||||
f 113/135/5 114/136/5 108/127/5
|
|
||||||
f 114/136/74 109/137/74 103/129/74
|
|
||||||
f 1/1/75 2/3/75 110/130/75
|
|
||||||
f 2/3/2 3/4/2 111/131/2
|
|
||||||
f 3/4/76 4/6/76 112/138/76
|
|
||||||
f 4/9/77 5/8/77 113/135/77
|
|
||||||
f 5/8/5 6/11/5 114/136/5
|
|
||||||
f 6/11/78 1/1/78 109/137/78
|
|
|
@ -1,119 +0,0 @@
|
||||||
# Blender 4.3.2
|
|
||||||
# www.blender.org
|
|
||||||
mtllib arrow.mtl
|
|
||||||
o Cylinder.001
|
|
||||||
v 0.189969 0.008460 -1.749730
|
|
||||||
v 0.189969 0.008460 1.759116
|
|
||||||
v 0.134756 -0.124837 -1.749730
|
|
||||||
v 0.134756 -0.124837 1.759116
|
|
||||||
v 0.001459 -0.180050 -1.749730
|
|
||||||
v 0.001459 -0.180050 1.759116
|
|
||||||
v -0.131837 -0.124837 -1.749730
|
|
||||||
v -0.131837 -0.124837 1.759116
|
|
||||||
v -0.187050 0.008460 -1.749730
|
|
||||||
v -0.187050 0.008460 1.759116
|
|
||||||
v -0.131837 0.141756 -1.749730
|
|
||||||
v -0.131837 0.141756 1.759116
|
|
||||||
v 0.001459 0.196969 -1.749730
|
|
||||||
v 0.001459 0.196969 1.759116
|
|
||||||
v 0.134756 0.141756 -1.749730
|
|
||||||
v 0.134756 0.141756 1.759116
|
|
||||||
v 0.398640 0.008460 1.759116
|
|
||||||
v 0.282308 -0.272389 1.759116
|
|
||||||
v 0.001459 -0.388721 1.759116
|
|
||||||
v -0.279390 -0.272389 1.759116
|
|
||||||
v -0.395722 0.008460 1.759116
|
|
||||||
v -0.279390 0.289309 1.759116
|
|
||||||
v 0.001459 0.405641 1.759116
|
|
||||||
v 0.282308 0.289309 1.759116
|
|
||||||
v 0.001459 0.010576 2.759115
|
|
||||||
vn 0.9239 -0.3827 -0.0000
|
|
||||||
vn 0.3827 -0.9239 -0.0000
|
|
||||||
vn -0.3827 -0.9239 -0.0000
|
|
||||||
vn -0.9239 -0.3827 -0.0000
|
|
||||||
vn -0.9239 0.3827 -0.0000
|
|
||||||
vn -0.3827 0.9239 -0.0000
|
|
||||||
vn -0.0000 -0.0000 -1.0000
|
|
||||||
vn 0.3827 0.9239 -0.0000
|
|
||||||
vn 0.9239 0.3827 -0.0000
|
|
||||||
vn 0.8676 0.3594 0.3438
|
|
||||||
vn -0.3595 0.8679 0.3429
|
|
||||||
vn -0.8671 -0.3592 0.3452
|
|
||||||
vn 0.3590 -0.8668 0.3461
|
|
||||||
vn 0.3595 0.8679 0.3429
|
|
||||||
vn -0.8676 0.3594 0.3438
|
|
||||||
vn -0.3590 -0.8668 0.3461
|
|
||||||
vn 0.8671 -0.3592 0.3452
|
|
||||||
vt 1.000000 1.000000
|
|
||||||
vt 0.875000 0.500000
|
|
||||||
vt 1.000000 0.500000
|
|
||||||
vt 0.875000 1.000000
|
|
||||||
vt 0.750000 0.500000
|
|
||||||
vt 0.750000 1.000000
|
|
||||||
vt 0.625000 0.500000
|
|
||||||
vt 0.625000 1.000000
|
|
||||||
vt 0.500000 0.500000
|
|
||||||
vt 0.500000 1.000000
|
|
||||||
vt 0.375000 0.500000
|
|
||||||
vt 0.375000 1.000000
|
|
||||||
vt 0.250000 0.500000
|
|
||||||
vt 0.250000 1.000000
|
|
||||||
vt 0.125000 0.500000
|
|
||||||
vt 0.125000 1.000000
|
|
||||||
vt 0.000000 0.500000
|
|
||||||
vt 0.919706 0.080294
|
|
||||||
vt 0.580294 0.080294
|
|
||||||
vt 0.580294 0.419706
|
|
||||||
vt 0.000000 1.000000
|
|
||||||
vt 0.750000 0.490000
|
|
||||||
vt 0.919706 0.419706
|
|
||||||
vt 0.990000 0.250000
|
|
||||||
vt 0.750000 0.010000
|
|
||||||
vt 0.510000 0.250000
|
|
||||||
s 0
|
|
||||||
f 2/1/1 3/2/1 1/3/1
|
|
||||||
f 4/4/2 5/5/2 3/2/2
|
|
||||||
f 6/6/3 7/7/3 5/5/3
|
|
||||||
f 8/8/4 9/9/4 7/7/4
|
|
||||||
f 10/10/5 11/11/5 9/9/5
|
|
||||||
f 12/12/6 13/13/6 11/11/6
|
|
||||||
f 8/8/7 21/10/7 10/10/7
|
|
||||||
f 14/14/8 15/15/8 13/13/8
|
|
||||||
f 16/16/9 1/17/9 15/15/9
|
|
||||||
f 7/18/7 11/19/7 15/20/7
|
|
||||||
f 17/21/10 24/16/10 25/21/10
|
|
||||||
f 14/14/7 24/16/7 16/16/7
|
|
||||||
f 4/4/7 19/6/7 6/6/7
|
|
||||||
f 10/10/7 22/12/7 12/12/7
|
|
||||||
f 16/16/7 17/21/7 2/21/7
|
|
||||||
f 2/1/7 18/4/7 4/4/7
|
|
||||||
f 6/6/7 20/8/7 8/8/7
|
|
||||||
f 12/12/7 23/14/7 14/14/7
|
|
||||||
f 23/14/11 22/12/11 25/14/11
|
|
||||||
f 21/10/12 20/8/12 25/10/12
|
|
||||||
f 19/6/13 18/4/13 25/6/13
|
|
||||||
f 24/16/14 23/14/14 25/16/14
|
|
||||||
f 22/12/15 21/10/15 25/12/15
|
|
||||||
f 20/8/16 19/6/16 25/8/16
|
|
||||||
f 18/4/17 17/1/17 25/4/17
|
|
||||||
f 2/1/1 4/4/1 3/2/1
|
|
||||||
f 4/4/2 6/6/2 5/5/2
|
|
||||||
f 6/6/3 8/8/3 7/7/3
|
|
||||||
f 8/8/4 10/10/4 9/9/4
|
|
||||||
f 10/10/5 12/12/5 11/11/5
|
|
||||||
f 12/12/6 14/14/6 13/13/6
|
|
||||||
f 8/8/7 20/8/7 21/10/7
|
|
||||||
f 14/14/8 16/16/8 15/15/8
|
|
||||||
f 16/16/9 2/21/9 1/17/9
|
|
||||||
f 15/20/7 1/22/7 3/23/7
|
|
||||||
f 3/23/7 5/24/7 7/18/7
|
|
||||||
f 7/18/7 9/25/7 11/19/7
|
|
||||||
f 11/19/7 13/26/7 15/20/7
|
|
||||||
f 15/20/7 3/23/7 7/18/7
|
|
||||||
f 14/14/7 23/14/7 24/16/7
|
|
||||||
f 4/4/7 18/4/7 19/6/7
|
|
||||||
f 10/10/7 21/10/7 22/12/7
|
|
||||||
f 16/16/7 24/16/7 17/21/7
|
|
||||||
f 2/1/7 17/1/7 18/4/7
|
|
||||||
f 6/6/7 19/6/7 20/8/7
|
|
||||||
f 12/12/7 22/12/7 23/14/7
|
|
|
@ -1,36 +0,0 @@
|
||||||
# Blender 4.3.2
|
|
||||||
# www.blender.org
|
|
||||||
mtllib cube.mtl
|
|
||||||
o Cube
|
|
||||||
v 1.000000 1.000000 -1.000000
|
|
||||||
v 1.000000 -1.000000 -1.000000
|
|
||||||
v 1.000000 1.000000 1.000000
|
|
||||||
v 1.000000 -1.000000 1.000000
|
|
||||||
v -1.000000 1.000000 -1.000000
|
|
||||||
v -1.000000 -1.000000 -1.000000
|
|
||||||
v -1.000000 1.000000 1.000000
|
|
||||||
v -1.000000 -1.000000 1.000000
|
|
||||||
vn -0.0000 1.0000 -0.0000
|
|
||||||
vn -0.0000 -0.0000 1.0000
|
|
||||||
vn -1.0000 -0.0000 -0.0000
|
|
||||||
vn -0.0000 -1.0000 -0.0000
|
|
||||||
vn 1.0000 -0.0000 -0.0000
|
|
||||||
vn -0.0000 -0.0000 -1.0000
|
|
||||||
vt 0.000000 1.000000
|
|
||||||
vt 1.000000 0.000000
|
|
||||||
vt 1.000000 1.000000
|
|
||||||
vt 0.000000 0.000000
|
|
||||||
s 0
|
|
||||||
usemtl Material
|
|
||||||
f 5/1/1 3/2/1 1/3/1
|
|
||||||
f 3/3/2 8/4/2 4/2/2
|
|
||||||
f 7/1/3 6/2/3 8/4/3
|
|
||||||
f 2/3/4 8/4/4 6/1/4
|
|
||||||
f 1/3/5 4/4/5 2/2/5
|
|
||||||
f 5/1/6 2/2/6 6/4/6
|
|
||||||
f 5/1/1 7/4/1 3/2/1
|
|
||||||
f 3/3/2 7/1/2 8/4/2
|
|
||||||
f 7/1/3 5/3/3 6/2/3
|
|
||||||
f 2/3/4 4/2/4 8/4/4
|
|
||||||
f 1/3/5 3/1/5 4/4/5
|
|
||||||
f 5/1/6 1/3/6 2/2/6
|
|
|
@ -1,137 +0,0 @@
|
||||||
# Blender 4.4.1
|
|
||||||
# www.blender.org
|
|
||||||
mtllib cylinder.mtl
|
|
||||||
o Cylinder
|
|
||||||
v 0.000000 -1.000000 1.000000
|
|
||||||
v 0.000000 -1.000000 -1.000000
|
|
||||||
v 0.500000 -0.866025 1.000000
|
|
||||||
v 0.500000 -0.866025 -1.000000
|
|
||||||
v 0.866025 -0.500000 1.000000
|
|
||||||
v 0.866025 -0.500000 -1.000000
|
|
||||||
v 1.000000 0.000000 1.000000
|
|
||||||
v 1.000000 -0.000000 -1.000000
|
|
||||||
v 0.866025 0.500000 1.000000
|
|
||||||
v 0.866025 0.500000 -1.000000
|
|
||||||
v 0.500000 0.866025 1.000000
|
|
||||||
v 0.500000 0.866025 -1.000000
|
|
||||||
v 0.000000 1.000000 1.000000
|
|
||||||
v 0.000000 1.000000 -1.000000
|
|
||||||
v -0.500000 0.866025 1.000000
|
|
||||||
v -0.500000 0.866025 -1.000000
|
|
||||||
v -0.866025 0.500000 1.000000
|
|
||||||
v -0.866025 0.500000 -1.000000
|
|
||||||
v -1.000000 0.000000 1.000000
|
|
||||||
v -1.000000 -0.000000 -1.000000
|
|
||||||
v -0.866025 -0.500000 1.000000
|
|
||||||
v -0.866025 -0.500000 -1.000000
|
|
||||||
v -0.500000 -0.866025 1.000000
|
|
||||||
v -0.500000 -0.866025 -1.000000
|
|
||||||
vn 0.2588 -0.9659 -0.0000
|
|
||||||
vn 0.7071 -0.7071 -0.0000
|
|
||||||
vn 0.9659 -0.2588 -0.0000
|
|
||||||
vn 0.9659 0.2588 -0.0000
|
|
||||||
vn 0.7071 0.7071 -0.0000
|
|
||||||
vn 0.2588 0.9659 -0.0000
|
|
||||||
vn -0.2588 0.9659 -0.0000
|
|
||||||
vn -0.7071 0.7071 -0.0000
|
|
||||||
vn -0.9659 0.2588 -0.0000
|
|
||||||
vn -0.9659 -0.2588 -0.0000
|
|
||||||
vn -0.0000 -0.0000 -1.0000
|
|
||||||
vn -0.7071 -0.7071 -0.0000
|
|
||||||
vn -0.2588 -0.9659 -0.0000
|
|
||||||
vn -0.0000 -0.0000 1.0000
|
|
||||||
vt 1.000000 1.000000
|
|
||||||
vt 0.916667 0.500000
|
|
||||||
vt 1.000000 0.500000
|
|
||||||
vt 0.916667 1.000000
|
|
||||||
vt 0.833333 0.500000
|
|
||||||
vt 0.833333 1.000000
|
|
||||||
vt 0.750000 0.500000
|
|
||||||
vt 0.750000 1.000000
|
|
||||||
vt 0.666667 0.500000
|
|
||||||
vt 0.666667 1.000000
|
|
||||||
vt 0.583333 0.500000
|
|
||||||
vt 0.583333 1.000000
|
|
||||||
vt 0.500000 0.500000
|
|
||||||
vt 0.500000 1.000000
|
|
||||||
vt 0.416667 0.500000
|
|
||||||
vt 0.416667 1.000000
|
|
||||||
vt 0.333333 0.500000
|
|
||||||
vt 0.333333 1.000000
|
|
||||||
vt 0.250000 0.500000
|
|
||||||
vt 0.250000 1.000000
|
|
||||||
vt 0.166667 0.500000
|
|
||||||
vt 0.042154 0.370000
|
|
||||||
vt 0.250000 0.010000
|
|
||||||
vt 0.457846 0.370000
|
|
||||||
vt 0.166667 1.000000
|
|
||||||
vt 0.083333 0.500000
|
|
||||||
vt 0.083333 1.000000
|
|
||||||
vt 0.000000 0.500000
|
|
||||||
vt 0.990000 0.250000
|
|
||||||
vt 0.630000 0.042154
|
|
||||||
vt 0.630000 0.457846
|
|
||||||
vt 0.370000 0.457846
|
|
||||||
vt 0.250000 0.490000
|
|
||||||
vt 0.130000 0.457846
|
|
||||||
vt 0.010000 0.250000
|
|
||||||
vt 0.042154 0.130000
|
|
||||||
vt 0.130000 0.042154
|
|
||||||
vt 0.370000 0.042154
|
|
||||||
vt 0.457846 0.130000
|
|
||||||
vt 0.490000 0.250000
|
|
||||||
vt 0.000000 1.000000
|
|
||||||
vt 0.750000 0.490000
|
|
||||||
vt 0.870000 0.457846
|
|
||||||
vt 0.957846 0.370000
|
|
||||||
vt 0.957846 0.130000
|
|
||||||
vt 0.870000 0.042154
|
|
||||||
vt 0.750000 0.010000
|
|
||||||
vt 0.542154 0.130000
|
|
||||||
vt 0.510000 0.250000
|
|
||||||
vt 0.542154 0.370000
|
|
||||||
s 0
|
|
||||||
f 2/1/1 3/2/1 1/3/1
|
|
||||||
f 4/4/2 5/5/2 3/2/2
|
|
||||||
f 6/6/3 7/7/3 5/5/3
|
|
||||||
f 8/8/4 9/9/4 7/7/4
|
|
||||||
f 10/10/5 11/11/5 9/9/5
|
|
||||||
f 12/12/6 13/13/6 11/11/6
|
|
||||||
f 14/14/7 15/15/7 13/13/7
|
|
||||||
f 16/16/8 17/17/8 15/15/8
|
|
||||||
f 18/18/9 19/19/9 17/17/9
|
|
||||||
f 20/20/10 21/21/10 19/19/10
|
|
||||||
f 22/22/11 14/23/11 6/24/11
|
|
||||||
f 22/25/12 23/26/12 21/21/12
|
|
||||||
f 24/27/13 1/28/13 23/26/13
|
|
||||||
f 7/29/14 15/30/14 23/31/14
|
|
||||||
f 2/1/1 4/4/1 3/2/1
|
|
||||||
f 4/4/2 6/6/2 5/5/2
|
|
||||||
f 6/6/3 8/8/3 7/7/3
|
|
||||||
f 8/8/4 10/10/4 9/9/4
|
|
||||||
f 10/10/5 12/12/5 11/11/5
|
|
||||||
f 12/12/6 14/14/6 13/13/6
|
|
||||||
f 14/14/7 16/16/7 15/15/7
|
|
||||||
f 16/16/8 18/18/8 17/17/8
|
|
||||||
f 18/18/9 20/20/9 19/19/9
|
|
||||||
f 20/20/10 22/25/10 21/21/10
|
|
||||||
f 6/24/11 4/32/11 2/33/11
|
|
||||||
f 2/33/11 24/34/11 22/22/11
|
|
||||||
f 22/22/11 20/35/11 18/36/11
|
|
||||||
f 18/36/11 16/37/11 22/22/11
|
|
||||||
f 16/37/11 14/23/11 22/22/11
|
|
||||||
f 14/23/11 12/38/11 10/39/11
|
|
||||||
f 10/39/11 8/40/11 14/23/11
|
|
||||||
f 8/40/11 6/24/11 14/23/11
|
|
||||||
f 6/24/11 2/33/11 22/22/11
|
|
||||||
f 22/25/12 24/27/12 23/26/12
|
|
||||||
f 24/27/13 2/41/13 1/28/13
|
|
||||||
f 23/31/14 1/42/14 3/43/14
|
|
||||||
f 3/43/14 5/44/14 23/31/14
|
|
||||||
f 5/44/14 7/29/14 23/31/14
|
|
||||||
f 7/29/14 9/45/14 11/46/14
|
|
||||||
f 11/46/14 13/47/14 7/29/14
|
|
||||||
f 13/47/14 15/30/14 7/29/14
|
|
||||||
f 15/30/14 17/48/14 19/49/14
|
|
||||||
f 19/49/14 21/50/14 23/31/14
|
|
||||||
f 15/30/14 19/49/14 23/31/14
|
|
|
@ -1,295 +0,0 @@
|
||||||
# Blender 4.4.0
|
|
||||||
# www.blender.org
|
|
||||||
mtllib outline.mtl
|
|
||||||
o Cube
|
|
||||||
v -1.000000 -1.000000 1.000000
|
|
||||||
v -1.000000 1.000000 1.000000
|
|
||||||
v -1.000000 -1.000000 -1.000000
|
|
||||||
v -1.000000 1.000000 -1.000000
|
|
||||||
v 1.000000 -1.000000 1.000000
|
|
||||||
v 1.000000 1.000000 1.000000
|
|
||||||
v 1.000000 -1.000000 -1.000000
|
|
||||||
v 1.000000 1.000000 -1.000000
|
|
||||||
v -0.500000 -1.000000 -1.000000
|
|
||||||
v -0.500000 1.000000 -1.000000
|
|
||||||
v -0.500000 -1.000000 1.000000
|
|
||||||
v -0.500000 1.000000 1.000000
|
|
||||||
v 0.500000 1.000000 -1.000000
|
|
||||||
v 0.500000 -1.000000 1.000000
|
|
||||||
v 0.500000 -1.000000 -1.000000
|
|
||||||
v 0.500000 1.000000 1.000000
|
|
||||||
v -1.000000 -1.000000 -0.500000
|
|
||||||
v -1.000000 1.000000 -0.500000
|
|
||||||
v 1.000000 -1.000000 -0.500000
|
|
||||||
v 1.000000 1.000000 -0.500000
|
|
||||||
v -0.500000 1.000000 -0.500000
|
|
||||||
v -0.500000 -1.000000 -0.500000
|
|
||||||
v 0.500000 1.000000 -0.500000
|
|
||||||
v 0.500000 -1.000000 -0.500000
|
|
||||||
v -1.000000 -1.000000 0.500000
|
|
||||||
v 1.000000 1.000000 0.500000
|
|
||||||
v -0.500000 1.000000 0.500000
|
|
||||||
v -0.500000 -1.000000 0.500000
|
|
||||||
v 0.500000 1.000000 0.500000
|
|
||||||
v 0.500000 -1.000000 0.500000
|
|
||||||
v -1.000000 1.000000 0.500000
|
|
||||||
v 1.000000 -1.000000 0.500000
|
|
||||||
v -1.000000 0.500000 1.000000
|
|
||||||
v -1.000000 0.500000 -1.000000
|
|
||||||
v 1.000000 0.500000 -1.000000
|
|
||||||
v 1.000000 0.500000 1.000000
|
|
||||||
v -0.500000 0.500000 1.000000
|
|
||||||
v -0.500000 0.500000 -1.000000
|
|
||||||
v 0.500000 0.500000 1.000000
|
|
||||||
v 0.500000 0.500000 -1.000000
|
|
||||||
v 1.000000 0.500000 -0.500000
|
|
||||||
v -1.000000 0.500000 -0.500000
|
|
||||||
v -1.000000 0.500000 0.500000
|
|
||||||
v 1.000000 0.500000 0.500000
|
|
||||||
v -1.000000 -0.500000 -1.000000
|
|
||||||
v 1.000000 -0.500000 -1.000000
|
|
||||||
v 1.000000 -0.500000 1.000000
|
|
||||||
v -0.500000 -0.500000 1.000000
|
|
||||||
v -0.500000 -0.500000 -1.000000
|
|
||||||
v 0.500000 -0.500000 1.000000
|
|
||||||
v 0.500000 -0.500000 -1.000000
|
|
||||||
v 1.000000 -0.500000 -0.500000
|
|
||||||
v -1.000000 -0.500000 -0.500000
|
|
||||||
v -1.000000 -0.500000 0.500000
|
|
||||||
v 1.000000 -0.500000 0.500000
|
|
||||||
v -1.000000 -0.500000 1.000000
|
|
||||||
v 0.500000 0.500000 0.500000
|
|
||||||
v -0.500000 -0.500000 0.500000
|
|
||||||
v 0.500000 0.500000 -0.500000
|
|
||||||
v 0.500000 -0.500000 -0.500000
|
|
||||||
v -0.500000 -0.500000 -0.500000
|
|
||||||
v 0.500000 -0.500000 0.500000
|
|
||||||
v -0.500000 0.500000 0.500000
|
|
||||||
v -0.500000 0.500000 -0.500000
|
|
||||||
vn -1.0000 -0.0000 -0.0000
|
|
||||||
vn -0.0000 -0.0000 -1.0000
|
|
||||||
vn 1.0000 -0.0000 -0.0000
|
|
||||||
vn -0.0000 -0.0000 1.0000
|
|
||||||
vn -0.0000 -1.0000 -0.0000
|
|
||||||
vn -0.0000 1.0000 -0.0000
|
|
||||||
vt 0.625000 0.187500
|
|
||||||
vt 0.562500 0.250000
|
|
||||||
vt 0.562500 0.187500
|
|
||||||
vt 0.625000 0.437500
|
|
||||||
vt 0.562500 0.500000
|
|
||||||
vt 0.562500 0.437500
|
|
||||||
vt 0.625000 0.687500
|
|
||||||
vt 0.562500 0.750000
|
|
||||||
vt 0.562500 0.687500
|
|
||||||
vt 0.625000 0.937500
|
|
||||||
vt 0.562500 1.000000
|
|
||||||
vt 0.562500 0.937500
|
|
||||||
vt 0.375000 0.687500
|
|
||||||
vt 0.312500 0.750000
|
|
||||||
vt 0.312500 0.687500
|
|
||||||
vt 0.875000 0.687500
|
|
||||||
vt 0.812500 0.750000
|
|
||||||
vt 0.812500 0.687500
|
|
||||||
vt 0.687500 0.750000
|
|
||||||
vt 0.687500 0.687500
|
|
||||||
vt 0.187500 0.687500
|
|
||||||
vt 0.125000 0.750000
|
|
||||||
vt 0.125000 0.687500
|
|
||||||
vt 0.625000 0.812500
|
|
||||||
vt 0.562500 0.812500
|
|
||||||
vt 0.625000 0.250000
|
|
||||||
vt 0.562500 0.312500
|
|
||||||
vt 0.625000 0.750000
|
|
||||||
vt 0.187500 0.750000
|
|
||||||
vt 0.625000 0.312500
|
|
||||||
vt 0.312500 0.500000
|
|
||||||
vt 0.187500 0.562500
|
|
||||||
vt 0.187500 0.500000
|
|
||||||
vt 0.687500 0.500000
|
|
||||||
vt 0.625000 0.562500
|
|
||||||
vt 0.625000 0.500000
|
|
||||||
vt 0.125000 0.562500
|
|
||||||
vt 0.125000 0.500000
|
|
||||||
vt 0.812500 0.500000
|
|
||||||
vt 0.687500 0.562500
|
|
||||||
vt 0.875000 0.500000
|
|
||||||
vt 0.812500 0.562500
|
|
||||||
vt 0.375000 0.500000
|
|
||||||
vt 0.312500 0.562500
|
|
||||||
vt 0.562500 0.562500
|
|
||||||
vt 0.625000 0.062500
|
|
||||||
vt 0.562500 0.062500
|
|
||||||
vt 0.625000 0.000000
|
|
||||||
vt 0.562500 0.000000
|
|
||||||
vt 0.875000 0.562500
|
|
||||||
vt 0.375000 0.562500
|
|
||||||
vt 0.437500 0.562500
|
|
||||||
vt 0.437500 0.062500
|
|
||||||
vt 0.437500 0.000000
|
|
||||||
vt 0.437500 0.500000
|
|
||||||
vt 0.437500 0.437500
|
|
||||||
vt 0.437500 0.812500
|
|
||||||
vt 0.437500 0.750000
|
|
||||||
vt 0.437500 0.312500
|
|
||||||
vt 0.437500 0.250000
|
|
||||||
vt 0.437500 1.000000
|
|
||||||
vt 0.437500 0.937500
|
|
||||||
vt 0.437500 0.687500
|
|
||||||
vt 0.437500 0.187500
|
|
||||||
vt 0.375000 0.250000
|
|
||||||
vt 0.375000 0.187500
|
|
||||||
vt 0.375000 0.437500
|
|
||||||
vt 0.375000 0.750000
|
|
||||||
vt 0.375000 1.000000
|
|
||||||
vt 0.375000 0.937500
|
|
||||||
vt 0.375000 0.812500
|
|
||||||
vt 0.375000 0.312500
|
|
||||||
vt 0.375000 0.062500
|
|
||||||
vt 0.375000 0.000000
|
|
||||||
vt 0.625000 1.000000
|
|
||||||
vt 0.875000 0.750000
|
|
||||||
s 0
|
|
||||||
f 18/1/1 34/2/1 42/3/1
|
|
||||||
f 13/4/2 35/5/2 40/6/2
|
|
||||||
f 26/7/3 36/8/3 44/9/3
|
|
||||||
f 12/10/4 33/11/4 37/12/4
|
|
||||||
f 32/13/5 14/14/5 30/15/5
|
|
||||||
f 31/16/6 12/17/6 27/18/6
|
|
||||||
f 27/18/6 16/19/6 29/20/6
|
|
||||||
f 28/21/5 1/22/5 25/23/5
|
|
||||||
f 16/24/4 37/12/4 39/25/4
|
|
||||||
f 4/26/2 38/27/2 34/2/2
|
|
||||||
f 6/28/4 39/25/4 36/8/4
|
|
||||||
f 29/20/6 6/28/6 26/7/6
|
|
||||||
f 30/15/5 11/29/5 28/21/5
|
|
||||||
f 10/30/2 40/6/2 38/27/2
|
|
||||||
f 15/31/5 22/32/5 9/33/5
|
|
||||||
f 13/34/6 20/35/6 8/36/6
|
|
||||||
f 9/33/5 17/37/5 3/38/5
|
|
||||||
f 10/39/6 23/40/6 13/34/6
|
|
||||||
f 4/41/6 21/42/6 10/39/6
|
|
||||||
f 7/43/5 24/44/5 15/31/5
|
|
||||||
f 8/36/3 41/45/3 35/5/3
|
|
||||||
f 31/46/1 42/3/1 43/47/1
|
|
||||||
f 2/48/1 43/47/1 33/49/1
|
|
||||||
f 28/21/2 62/15/2 30/15/2
|
|
||||||
f 23/40/6 26/7/6 20/35/6
|
|
||||||
f 22/32/5 25/23/5 17/37/5
|
|
||||||
f 27/18/3 64/42/3 21/42/3
|
|
||||||
f 18/50/6 27/18/6 21/42/6
|
|
||||||
f 19/51/5 30/15/5 24/44/5
|
|
||||||
f 20/35/3 44/9/3 41/45/3
|
|
||||||
f 41/45/4 60/52/4 52/52/4
|
|
||||||
f 33/49/1 54/53/1 56/54/1
|
|
||||||
f 43/47/2 58/53/2 54/53/2
|
|
||||||
f 35/5/3 52/52/3 46/55/3
|
|
||||||
f 51/56/1 59/6/1 40/6/1
|
|
||||||
f 36/8/4 50/57/4 47/58/4
|
|
||||||
f 34/2/2 49/59/2 45/60/2
|
|
||||||
f 39/25/1 62/57/1 50/57/1
|
|
||||||
f 37/12/4 56/61/4 48/62/4
|
|
||||||
f 44/9/3 47/58/3 55/63/3
|
|
||||||
f 40/6/2 46/55/2 51/56/2
|
|
||||||
f 42/3/1 45/60/1 53/64/1
|
|
||||||
f 53/64/1 3/65/1 17/66/1
|
|
||||||
f 51/56/2 7/43/2 15/67/2
|
|
||||||
f 55/63/3 5/68/3 32/13/3
|
|
||||||
f 48/62/4 1/69/4 11/70/4
|
|
||||||
f 50/57/4 11/70/4 14/71/4
|
|
||||||
f 45/60/2 9/72/2 3/65/2
|
|
||||||
f 47/58/4 14/71/4 5/68/4
|
|
||||||
f 49/59/2 15/67/2 9/72/2
|
|
||||||
f 46/55/3 19/51/3 7/43/3
|
|
||||||
f 54/53/1 17/66/1 25/73/1
|
|
||||||
f 56/54/1 25/73/1 1/74/1
|
|
||||||
f 52/52/3 32/13/3 19/51/3
|
|
||||||
f 50/57/6 58/62/6 48/62/6
|
|
||||||
f 48/62/3 63/12/3 37/12/3
|
|
||||||
f 37/12/5 57/25/5 39/25/5
|
|
||||||
f 52/52/6 62/63/6 55/63/6
|
|
||||||
f 44/9/5 59/45/5 41/45/5
|
|
||||||
f 55/63/2 57/9/2 44/9/2
|
|
||||||
f 38/27/3 61/59/3 49/59/3
|
|
||||||
f 40/6/5 64/27/5 38/27/5
|
|
||||||
f 49/59/6 60/56/6 51/56/6
|
|
||||||
f 29/20/2 63/18/2 27/18/2
|
|
||||||
f 21/42/4 59/40/4 23/40/4
|
|
||||||
f 23/40/1 57/20/1 29/20/1
|
|
||||||
f 30/15/1 60/44/1 24/44/1
|
|
||||||
f 24/44/4 61/32/4 22/32/4
|
|
||||||
f 22/32/3 58/21/3 28/21/3
|
|
||||||
f 42/3/5 63/47/5 43/47/5
|
|
||||||
f 54/53/6 61/64/6 53/64/6
|
|
||||||
f 53/64/4 64/3/4 42/3/4
|
|
||||||
f 18/1/1 4/26/1 34/2/1
|
|
||||||
f 13/4/2 8/36/2 35/5/2
|
|
||||||
f 26/7/3 6/28/3 36/8/3
|
|
||||||
f 12/10/4 2/75/4 33/11/4
|
|
||||||
f 32/13/5 5/68/5 14/14/5
|
|
||||||
f 31/16/6 2/76/6 12/17/6
|
|
||||||
f 27/18/6 12/17/6 16/19/6
|
|
||||||
f 28/21/5 11/29/5 1/22/5
|
|
||||||
f 16/24/4 12/10/4 37/12/4
|
|
||||||
f 4/26/2 10/30/2 38/27/2
|
|
||||||
f 6/28/4 16/24/4 39/25/4
|
|
||||||
f 29/20/6 16/19/6 6/28/6
|
|
||||||
f 30/15/5 14/14/5 11/29/5
|
|
||||||
f 10/30/2 13/4/2 40/6/2
|
|
||||||
f 15/31/5 24/44/5 22/32/5
|
|
||||||
f 13/34/6 23/40/6 20/35/6
|
|
||||||
f 9/33/5 22/32/5 17/37/5
|
|
||||||
f 10/39/6 21/42/6 23/40/6
|
|
||||||
f 4/41/6 18/50/6 21/42/6
|
|
||||||
f 7/43/5 19/51/5 24/44/5
|
|
||||||
f 8/36/3 20/35/3 41/45/3
|
|
||||||
f 31/46/1 18/1/1 42/3/1
|
|
||||||
f 2/48/1 31/46/1 43/47/1
|
|
||||||
f 28/21/2 58/21/2 62/15/2
|
|
||||||
f 23/40/6 29/20/6 26/7/6
|
|
||||||
f 22/32/5 28/21/5 25/23/5
|
|
||||||
f 27/18/3 63/18/3 64/42/3
|
|
||||||
f 18/50/6 31/16/6 27/18/6
|
|
||||||
f 19/51/5 32/13/5 30/15/5
|
|
||||||
f 20/35/3 26/7/3 44/9/3
|
|
||||||
f 41/45/4 59/45/4 60/52/4
|
|
||||||
f 33/49/1 43/47/1 54/53/1
|
|
||||||
f 43/47/2 63/47/2 58/53/2
|
|
||||||
f 35/5/3 41/45/3 52/52/3
|
|
||||||
f 51/56/1 60/56/1 59/6/1
|
|
||||||
f 36/8/4 39/25/4 50/57/4
|
|
||||||
f 34/2/2 38/27/2 49/59/2
|
|
||||||
f 39/25/1 57/25/1 62/57/1
|
|
||||||
f 37/12/4 33/11/4 56/61/4
|
|
||||||
f 44/9/3 36/8/3 47/58/3
|
|
||||||
f 40/6/2 35/5/2 46/55/2
|
|
||||||
f 42/3/1 34/2/1 45/60/1
|
|
||||||
f 53/64/1 45/60/1 3/65/1
|
|
||||||
f 51/56/2 46/55/2 7/43/2
|
|
||||||
f 55/63/3 47/58/3 5/68/3
|
|
||||||
f 48/62/4 56/61/4 1/69/4
|
|
||||||
f 50/57/4 48/62/4 11/70/4
|
|
||||||
f 45/60/2 49/59/2 9/72/2
|
|
||||||
f 47/58/4 50/57/4 14/71/4
|
|
||||||
f 49/59/2 51/56/2 15/67/2
|
|
||||||
f 46/55/3 52/52/3 19/51/3
|
|
||||||
f 54/53/1 53/64/1 17/66/1
|
|
||||||
f 56/54/1 54/53/1 25/73/1
|
|
||||||
f 52/52/3 55/63/3 32/13/3
|
|
||||||
f 50/57/6 62/57/6 58/62/6
|
|
||||||
f 48/62/3 58/62/3 63/12/3
|
|
||||||
f 37/12/5 63/12/5 57/25/5
|
|
||||||
f 52/52/6 60/52/6 62/63/6
|
|
||||||
f 44/9/5 57/9/5 59/45/5
|
|
||||||
f 55/63/2 62/63/2 57/9/2
|
|
||||||
f 38/27/3 64/27/3 61/59/3
|
|
||||||
f 40/6/5 59/6/5 64/27/5
|
|
||||||
f 49/59/6 61/59/6 60/56/6
|
|
||||||
f 29/20/2 57/20/2 63/18/2
|
|
||||||
f 21/42/4 64/42/4 59/40/4
|
|
||||||
f 23/40/1 59/40/1 57/20/1
|
|
||||||
f 30/15/1 62/15/1 60/44/1
|
|
||||||
f 24/44/4 60/44/4 61/32/4
|
|
||||||
f 22/32/3 61/32/3 58/21/3
|
|
||||||
f 42/3/5 64/3/5 63/47/5
|
|
||||||
f 54/53/6 58/53/6 61/64/6
|
|
||||||
f 53/64/4 61/64/4 64/3/4
|
|
|
@ -1,36 +0,0 @@
|
||||||
# Blender 4.4.3
|
|
||||||
# www.blender.org
|
|
||||||
mtllib wedge.mtl
|
|
||||||
o Cube
|
|
||||||
v 1.000000 -1.000000 -1.000000
|
|
||||||
v 1.000000 1.000000 1.000000
|
|
||||||
v 1.000000 -1.000000 1.000000
|
|
||||||
v -1.000000 -1.000000 -1.000000
|
|
||||||
v -1.000000 1.000000 1.000000
|
|
||||||
v -1.000000 -1.000000 1.000000
|
|
||||||
vn -0.0000 -0.0000 1.0000
|
|
||||||
vn -1.0000 -0.0000 -0.0000
|
|
||||||
vn -0.0000 -1.0000 -0.0000
|
|
||||||
vn 1.0000 -0.0000 -0.0000
|
|
||||||
vn -0.0000 0.7071 -0.7071
|
|
||||||
vt 0.625000 0.750000
|
|
||||||
vt 0.375000 1.000000
|
|
||||||
vt 0.375000 0.750000
|
|
||||||
vt 0.375000 0.000000
|
|
||||||
vt 0.625000 0.000000
|
|
||||||
vt 0.375000 0.250000
|
|
||||||
vt 0.375000 0.500000
|
|
||||||
vt 0.125000 0.750000
|
|
||||||
vt 0.125000 0.500000
|
|
||||||
vt 0.875000 0.750000
|
|
||||||
vt 0.625000 1.000000
|
|
||||||
s 0
|
|
||||||
usemtl Material
|
|
||||||
f 2/1/1 6/2/1 3/3/1
|
|
||||||
f 6/4/2 5/5/2 4/6/2
|
|
||||||
f 1/7/3 6/8/3 4/9/3
|
|
||||||
f 1/7/4 2/1/4 3/3/4
|
|
||||||
f 5/10/5 1/7/5 4/6/5
|
|
||||||
f 2/1/1 5/11/1 6/2/1
|
|
||||||
f 1/7/3 3/3/3 6/8/3
|
|
||||||
f 5/10/5 2/1/5 1/7/5
|
|
Before Width: | Height: | Size: 413 B |
|
@ -3,10 +3,10 @@
|
||||||
// I/O
|
// I/O
|
||||||
|
|
||||||
out vec4 fColor;
|
out vec4 fColor;
|
||||||
uniform vec4 aColor;
|
uniform vec3 aColor;
|
||||||
|
|
||||||
// Main
|
// Main
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
fColor = aColor;
|
fColor = vec4(aColor, 1.0);
|
||||||
}
|
}
|
|
@ -54,14 +54,11 @@ uniform int numPointLights;
|
||||||
uniform DirLight sunLight;
|
uniform DirLight sunLight;
|
||||||
uniform Material material;
|
uniform Material material;
|
||||||
uniform sampler2DArray studs;
|
uniform sampler2DArray studs;
|
||||||
uniform samplerCube skybox;
|
|
||||||
uniform float transparency;
|
uniform float transparency;
|
||||||
uniform float reflectance;
|
|
||||||
uniform vec3 texScale;
|
uniform vec3 texScale;
|
||||||
|
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
vec3 calculateReflection();
|
|
||||||
vec3 calculateDirectionalLight(DirLight light);
|
vec3 calculateDirectionalLight(DirLight light);
|
||||||
vec3 calculatePointLight(PointLight light);
|
vec3 calculatePointLight(PointLight light);
|
||||||
mat3 lookAlong(vec3 pos, vec3 forward, vec3 up);
|
mat3 lookAlong(vec3 pos, vec3 forward, vec3 up);
|
||||||
|
@ -71,7 +68,6 @@ mat3 lookAlong(vec3 pos, vec3 forward, vec3 up);
|
||||||
void main() {
|
void main() {
|
||||||
vec3 result = vec3(0.0);
|
vec3 result = vec3(0.0);
|
||||||
|
|
||||||
result += calculateReflection();
|
|
||||||
result += calculateDirectionalLight(sunLight);
|
result += calculateDirectionalLight(sunLight);
|
||||||
|
|
||||||
for (int i = 0; i < numPointLights; i++) {
|
for (int i = 0; i < numPointLights; i++) {
|
||||||
|
@ -99,25 +95,6 @@ mat3 lookAlong(vec3 pos, vec3 forward, vec3 up) {
|
||||||
return mat3(s, u, f);
|
return mat3(s, u, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
vec3 sampleSkybox()
|
|
||||||
{
|
|
||||||
vec3 norm = normalize(vNormal);
|
|
||||||
vec3 viewDir = normalize(viewPos - vPos);
|
|
||||||
vec3 reflectDir = reflect(-viewDir, norm);
|
|
||||||
|
|
||||||
return textureLod(skybox,reflectDir, 5.0 * (1.0-material.shininess)).rgb;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 calculateReflection() {
|
|
||||||
vec3 norm = normalize(vNormal);
|
|
||||||
vec3 viewDir = normalize(viewPos - vPos);
|
|
||||||
vec3 reflectDir = reflect(viewDir, norm);
|
|
||||||
float fresnel = (pow(1.0-max(dot(viewDir, norm), 0.0), 5.0));
|
|
||||||
vec3 result = sampleSkybox() * mix(/* TEMPORARY: will be replaced by setting */ 0 * /* /TEMPORARY */ fresnel * material.specular, vec3(1.0), reflectance);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 calculateDirectionalLight(DirLight light) {
|
vec3 calculateDirectionalLight(DirLight light) {
|
||||||
// Calculate diffuse
|
// Calculate diffuse
|
||||||
vec3 norm = normalize(vNormal);
|
vec3 norm = normalize(vNormal);
|
||||||
|
@ -128,13 +105,10 @@ vec3 calculateDirectionalLight(DirLight light) {
|
||||||
vec3 viewDir = normalize(viewPos - vPos);
|
vec3 viewDir = normalize(viewPos - vPos);
|
||||||
vec3 reflectDir = reflect(-lightDir, norm);
|
vec3 reflectDir = reflect(-lightDir, norm);
|
||||||
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
|
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
|
||||||
// float fresnel = (pow(1.0-max(dot(viewDir, norm), 0.0), 5.0));
|
|
||||||
|
|
||||||
|
vec3 ambient = light.ambient * material.diffuse;
|
||||||
vec3 ambient = light.ambient * (material.diffuse * (1.0-reflectance));
|
vec3 diffuse = light.diffuse * diff * material.diffuse;
|
||||||
vec3 diffuse = light.diffuse * diff * (material.diffuse * (1.0-reflectance));
|
|
||||||
vec3 specular = light.specular * spec * material.specular;
|
vec3 specular = light.specular * spec * material.specular;
|
||||||
// specular += sampleSkybox() * fresnel * material.specular;
|
|
||||||
|
|
||||||
return (ambient + diffuse + specular);
|
return (ambient + diffuse + specular);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ const int FaceBack = 2;
|
||||||
const int FaceLeft = 3;
|
const int FaceLeft = 3;
|
||||||
const int FaceBottom = 4;
|
const int FaceBottom = 4;
|
||||||
const int FaceFront = 5;
|
const int FaceFront = 5;
|
||||||
const int FaceNone = 6;
|
|
||||||
|
|
||||||
const int SurfaceSmooth = 0;
|
const int SurfaceSmooth = 0;
|
||||||
const int SurfaceGlue = 1;
|
const int SurfaceGlue = 1;
|
||||||
|
@ -32,8 +31,6 @@ uniform mat4 projection;
|
||||||
uniform int surfaces[6];
|
uniform int surfaces[6];
|
||||||
uniform vec3 texScale;
|
uniform vec3 texScale;
|
||||||
|
|
||||||
const float faceThreshold = sqrt(2)/2;
|
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
gl_Position = projection * view * model * vec4(aPos, 1.0);
|
gl_Position = projection * view * model * vec4(aPos, 1.0);
|
||||||
|
@ -41,20 +38,12 @@ void main()
|
||||||
lPos = aPos;
|
lPos = aPos;
|
||||||
vNormal = normalMatrix * aNormal;
|
vNormal = normalMatrix * aNormal;
|
||||||
lNormal = aNormal;
|
lNormal = aNormal;
|
||||||
int vFace = FaceNone;
|
int vFace = aNormal == vec3(0,1,0) ? FaceTop :
|
||||||
|
aNormal == vec3(0, -1, 0) ? FaceBottom :
|
||||||
if (dot(vec3(0, 1, 0), aNormal) > faceThreshold)
|
aNormal == vec3(1, 0, 0) ? FaceRight :
|
||||||
vFace = FaceTop;
|
aNormal == vec3(-1, 0, 0) ? FaceLeft :
|
||||||
else if (dot(vec3(0, -1, 0), aNormal) > faceThreshold)
|
aNormal == vec3(0, 0, -1) ? FaceFront :
|
||||||
vFace = FaceBottom;
|
aNormal == vec3(0, 0, 1) ? FaceBack : -1;
|
||||||
else if (dot(vec3(1, 0, 0), aNormal) > faceThreshold)
|
|
||||||
vFace = FaceRight;
|
|
||||||
else if (dot(vec3(-1, 0, 0), aNormal) > faceThreshold)
|
|
||||||
vFace = FaceLeft;
|
|
||||||
else if (dot(vec3(0, 0, -1), aNormal) > faceThreshold)
|
|
||||||
vFace = FaceFront;
|
|
||||||
else if (dot(vec3(0, 0, 1), aNormal) > faceThreshold)
|
|
||||||
vFace = FaceBack;
|
|
||||||
|
|
||||||
vSurfaceZ = surfaces[vFace];
|
vSurfaceZ = surfaces[vFace];
|
||||||
if (surfaces[vFace] > SurfaceUniversal) vSurfaceZ = 0;
|
if (surfaces[vFace] > SurfaceUniversal) vSurfaceZ = 0;
|
||||||
|
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
|
@ -26,7 +26,6 @@ int processHeader(fs::path srcRoot, fs::path srcPath, fs::path outPath) {
|
||||||
std::string srcRootStr = string_of(srcRoot);
|
std::string srcRootStr = string_of(srcRoot);
|
||||||
std::string srcPathStr = string_of(srcPath);
|
std::string srcPathStr = string_of(srcPath);
|
||||||
std::string outPathStr = string_of(outPath);
|
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 };
|
const char* cargs[] = { "-xc++", "-std=c++17", "-I", srcRootStr.c_str(), "-D__AUTOGEN__", 0 };
|
||||||
// THANK YOU SO MUCH THIS STACKOVERFLOW ANSWER IS SO HELPFUL
|
// 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;
|
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
|
// Print errors
|
||||||
int ndiags = clang_getNumDiagnostics(unit);
|
int ndiags = clang_getNumDiagnostics(unit);
|
||||||
for (int i = 0; i < ndiags; i++) {
|
for (int i = 0; i < ndiags; i++) {
|
||||||
CXDiagnostic diag = clang_getDiagnostic(unit, i);
|
CXDiagnostic diag = clang_getDiagnostic(unit, i);
|
||||||
CXString str = clang_formatDiagnostic(diag, 0);
|
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_disposeString(str);
|
||||||
clang_disposeDiagnostic(diag);
|
clang_disposeDiagnostic(diag);
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(logout);
|
|
||||||
|
|
||||||
CXCursor cursor = clang_getTranslationUnitCursor(unit);
|
CXCursor cursor = clang_getTranslationUnitCursor(unit);
|
||||||
|
|
||||||
object::AnalysisState objectAnlyState;
|
object::AnalysisState objectAnlyState;
|
||||||
|
@ -76,6 +66,8 @@ int processHeader(fs::path srcRoot, fs::path srcPath, fs::path outPath) {
|
||||||
data::analyzeClasses(cursor, srcRootStr, &dataAnlyState);
|
data::analyzeClasses(cursor, srcRootStr, &dataAnlyState);
|
||||||
enum_::analyzeClasses(cursor, srcRootStr, &enumAnlyState);
|
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());
|
printf("[AUTOGEN] Generating file %s...\n", relpathStr.c_str());
|
||||||
std::ofstream outStream(outPathStr);
|
std::ofstream outStream(outPathStr);
|
||||||
|
|
||||||
|
@ -112,7 +104,5 @@ int main(int argc, char** argv) {
|
||||||
fs::path srcPath = argv[2];
|
fs::path srcPath = argv[2];
|
||||||
fs::path outPath = argv[3];
|
fs::path outPath = argv[3];
|
||||||
|
|
||||||
// fprintf(stderr, "Some error here\n");
|
|
||||||
// return 0;
|
|
||||||
return processHeader(srcRoot, srcPath, outPath);
|
return processHeader(srcRoot, srcPath, outPath);
|
||||||
}
|
}
|
|
@ -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")
|
add_executable(client "src/main.cpp")
|
||||||
target_link_libraries(client PRIVATE openblocks glfw)
|
target_link_libraries(client PRIVATE ${SDL2_LIBRARIES} openblocks glfw)
|
||||||
add_dependencies(client openblocks)
|
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()
|
|
|
@ -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
|
|
|
@ -1,12 +1,8 @@
|
||||||
#include <glad/gl.h>
|
#include <GL/glew.h>
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
#include "logger.h"
|
#include "objects/part.h"
|
||||||
#include "objects/part/part.h"
|
|
||||||
#include "panic.h"
|
|
||||||
#include "physics/world.h"
|
|
||||||
#include "rendering/renderer.h"
|
#include "rendering/renderer.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "version.h"
|
|
||||||
|
|
||||||
void errorCatcher(int id, const char* str);
|
void errorCatcher(int id, const char* str);
|
||||||
|
|
||||||
|
@ -19,36 +15,24 @@ void mouseCallback(GLFWwindow* window, double xpos, double ypos);
|
||||||
void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
|
void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
|
||||||
void resizeCallback(GLFWwindow* window, int width, int height);
|
void resizeCallback(GLFWwindow* window, int width, int height);
|
||||||
|
|
||||||
std::shared_ptr<BasePart> lastPart;
|
std::shared_ptr<Part> lastPart;
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
Logger::init();
|
Logger::init();
|
||||||
|
|
||||||
glfwSetErrorCallback(errorCatcher);
|
glfwSetErrorCallback(errorCatcher);
|
||||||
|
|
||||||
std::string title = std::string() + "Openblocks Client " + BUILD_VERSION;
|
|
||||||
|
|
||||||
glfwInit();
|
glfwInit();
|
||||||
glfwWindowHint(GLFW_SAMPLES, 4);
|
glfwWindowHint(GLFW_SAMPLES, 4);
|
||||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE); // Valid only in OpenGL 3.2+, see: https://stackoverflow.com/a/70519392/16255372
|
GLFWwindow *window = glfwCreateWindow(1200, 900, "OpenBlocks Client ALPHA", NULL, NULL);
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
|
||||||
GLFWwindow *window = glfwCreateWindow(1200, 900, title.c_str(), NULL, NULL);
|
|
||||||
glfwSetKeyCallback(window, keyCallback);
|
glfwSetKeyCallback(window, keyCallback);
|
||||||
glfwSetMouseButtonCallback(window, mouseButtonCallback);
|
glfwSetMouseButtonCallback(window, mouseButtonCallback);
|
||||||
glfwSetCursorPosCallback(window, mouseCallback);
|
glfwSetCursorPosCallback(window, mouseCallback);
|
||||||
glfwSetFramebufferSizeCallback(window, resizeCallback);
|
glfwSetFramebufferSizeCallback(window, resizeCallback);
|
||||||
|
|
||||||
glfwMakeContextCurrent(window);
|
glfwMakeContextCurrent(window);
|
||||||
int version = gladLoadGL(glfwGetProcAddress);
|
glewInit();
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
physicsInit();
|
|
||||||
gDataModel->Init();
|
gDataModel->Init();
|
||||||
renderInit(1200, 900);
|
renderInit(1200, 900);
|
||||||
|
|
||||||
|
@ -71,7 +55,7 @@ int main() {
|
||||||
|
|
||||||
for (std::shared_ptr<Instance> inst : gWorkspace()->GetChildren()) {
|
for (std::shared_ptr<Instance> inst : gWorkspace()->GetChildren()) {
|
||||||
if (inst->GetClass()->className != "Part") continue;
|
if (inst->GetClass()->className != "Part") continue;
|
||||||
std::shared_ptr<BasePart> part = std::dynamic_pointer_cast<BasePart>(inst);
|
std::shared_ptr<Part> part = std::dynamic_pointer_cast<Part>(inst);
|
||||||
gWorkspace()->SyncPartPhysics(part);
|
gWorkspace()->SyncPartPhysics(part);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,13 +72,12 @@ int main() {
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
} while(!glfwWindowShouldClose(window));
|
} while(!glfwWindowShouldClose(window));
|
||||||
|
|
||||||
physicsDeinit();
|
|
||||||
glfwTerminate();
|
glfwTerminate();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void errorCatcher(int id, const char* str) {
|
void errorCatcher(int id, const char* str) {
|
||||||
Logger::fatalErrorf("GLFW Error: [%d] %s", id, str);
|
Logger::fatalError(std::format("GLFW Error: [{}] {}", id, str));
|
||||||
}
|
}
|
||||||
|
|
||||||
float lastTime;
|
float lastTime;
|
||||||
|
@ -165,7 +148,6 @@ void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool doDebugRender = false;
|
|
||||||
void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
|
void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
|
||||||
if (key == GLFW_KEY_F && action == GLFW_PRESS) {
|
if (key == GLFW_KEY_F && action == GLFW_PRESS) {
|
||||||
gWorkspace()->AddChild(lastPart = Part::New({
|
gWorkspace()->AddChild(lastPart = Part::New({
|
||||||
|
@ -209,8 +191,6 @@ void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods
|
||||||
if (key == GLFW_KEY_M && action == GLFW_PRESS) mode = 0;
|
if (key == GLFW_KEY_M && action == GLFW_PRESS) mode = 0;
|
||||||
if (key == GLFW_KEY_E && action == GLFW_PRESS) mode = 1; // Enlarge
|
if (key == GLFW_KEY_E && action == GLFW_PRESS) mode = 1; // Enlarge
|
||||||
if (key == GLFW_KEY_R && action == GLFW_PRESS) mode = 2;
|
if (key == GLFW_KEY_R && action == GLFW_PRESS) mode = 2;
|
||||||
|
|
||||||
if (key == GLFW_KEY_LEFT_BRACKET && action == GLFW_PRESS) setDebugRendererEnabled(doDebugRender = !doDebugRender);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void resizeCallback(GLFWwindow* window, int width, int height) {
|
void resizeCallback(GLFWwindow* window, int width, int height) {
|
||||||
|
|
|
@ -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})
|
|
|
@ -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
|
@ -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)
|
|
@ -1,40 +0,0 @@
|
||||||
|
|
||||||
# https://jonathanhamberg.com/post/cmake-embedding-git-hash/
|
|
||||||
|
|
||||||
# Detect current version from git
|
|
||||||
execute_process(
|
|
||||||
COMMAND git rev-parse HEAD
|
|
||||||
OUTPUT_VARIABLE GIT_COMMIT_HASH RESULT_VARIABLE GIT_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET)
|
|
||||||
|
|
||||||
execute_process(
|
|
||||||
COMMAND git describe --abbrev=0
|
|
||||||
OUTPUT_VARIABLE GIT_VERSION RESULT_VARIABLE GIT_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET)
|
|
||||||
|
|
||||||
execute_process(
|
|
||||||
COMMAND git describe --dirty
|
|
||||||
OUTPUT_VARIABLE GIT_VERSION_LONG RESULT_VARIABLE GIT_RESULT OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET)
|
|
||||||
|
|
||||||
# For some reason, CMake sets CMAKE_*_DIR all to be CMAKE_CURRENT_BINARY_DIR
|
|
||||||
# so we have to bypass this by passing in custom "orig_" variables
|
|
||||||
if (NOT GIT_STATE_WITHIN)
|
|
||||||
# Re-run this target always so that the version can be checked
|
|
||||||
add_custom_target(recheck_git_version ALL COMMAND ${CMAKE_COMMAND}
|
|
||||||
-DGIT_STATE_WITHIN=1
|
|
||||||
-DORIG_BINARY_DIR=${CMAKE_BINARY_DIR}
|
|
||||||
-DORIG_CURRENT_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}
|
|
||||||
-DORIG_SOURCE_DIR=${CMAKE_SOURCE_DIR}
|
|
||||||
-DORIG_CURRENT_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}
|
|
||||||
-P ${CMAKE_MODULE_PATH}/gitversion.cmake
|
|
||||||
BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/src/version.cpp
|
|
||||||
)
|
|
||||||
else ()
|
|
||||||
# # Set defaults if the git commands fail
|
|
||||||
if (NOT GIT_RESULT EQUAL 0)
|
|
||||||
set(GIT_COMMIT_HASH "unknown")
|
|
||||||
set(GIT_VERSION "unknown")
|
|
||||||
set(GIT_VERSION_LONG "unknown")
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
# configure_file only touches the file if it has been changed, so no caching is necessary
|
|
||||||
configure_file(${ORIG_CURRENT_SOURCE_DIR}/src/version.cpp.in ${ORIG_CURRENT_BINARY_DIR}/src/version.cpp @ONLY)
|
|
||||||
endif ()
|
|
|
@ -1,177 +1,29 @@
|
||||||
include(${CMAKE_CURRENT_SOURCE_DIR}/deps.cmake)
|
find_package(OpenGL REQUIRED COMPONENTS OpenGL)
|
||||||
|
|
||||||
## Sources
|
find_package(GLEW REQUIRED)
|
||||||
set(SOURCES
|
include_directories(${GLEW_INCLUDE_DIRS})
|
||||||
src/stb.cpp
|
|
||||||
src/glad.cpp
|
|
||||||
|
|
||||||
src/ptr_helpers.h
|
find_package(OpenGL)
|
||||||
src/enum/part.h
|
find_package(glm CONFIG REQUIRED)
|
||||||
src/enum/surface.cpp
|
find_package(ReactPhysics3D REQUIRED)
|
||||||
src/enum/meta.h
|
find_package(pugixml 1.15 REQUIRED)
|
||||||
src/enum/annotation.h
|
find_package(Freetype)
|
||||||
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/physics/world.h
|
|
||||||
src/physics/world.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/luaapis.h
|
|
||||||
src/math_helper.h
|
|
||||||
)
|
|
||||||
|
|
||||||
set(AUTOGEN_SOURCES
|
find_package(Stb REQUIRED)
|
||||||
# Objects
|
include_directories(${Stb_INCLUDE_DIR})
|
||||||
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
|
# PkgConfig packages
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
pkg_check_modules(LUAJIT REQUIRED luajit)
|
||||||
|
link_directories(${LUAJIT_LIBRARY_DIRS})
|
||||||
|
|
||||||
|
# Run 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
|
# https://cmake.org/cmake/help/book/mastering-cmake/chapter/Custom%20Commands.html
|
||||||
foreach (SRC ${AUTOGEN_SOURCES})
|
foreach (SRC ${AUTOGEN_SOURCES})
|
||||||
string(REGEX REPLACE "[.]h$" ".cpp" OUT_SRC_NAME ${SRC})
|
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}")
|
set(OUT_PATH "${CMAKE_BINARY_DIR}/generated/${OUT_SRC_NAME}")
|
||||||
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
|
@ -184,22 +36,17 @@ foreach (SRC ${AUTOGEN_SOURCES})
|
||||||
list(APPEND AUTOGEN_OUTS "${OUT_PATH}")
|
list(APPEND AUTOGEN_OUTS "${OUT_PATH}")
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
### /Autogen
|
|
||||||
|
|
||||||
# Add version info into the build
|
|
||||||
include(gitversion)
|
|
||||||
|
|
||||||
add_custom_target(autogen_build ALL
|
add_custom_target(autogen_build ALL
|
||||||
DEPENDS ${AUTOGEN_OUTS}
|
DEPENDS ${AUTOGEN_OUTS}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE SOURCES "src/*.cpp" "src/*.h")
|
||||||
list(APPEND SOURCES ${AUTOGEN_OUTS})
|
list(APPEND SOURCES ${AUTOGEN_OUTS})
|
||||||
list(APPEND SOURCES ${CMAKE_CURRENT_BINARY_DIR}/src/version.cpp)
|
|
||||||
add_library(openblocks STATIC ${SOURCES})
|
add_library(openblocks STATIC ${SOURCES})
|
||||||
set_target_properties(openblocks PROPERTIES OUTPUT_NAME "openblocks")
|
set_target_properties(openblocks PROPERTIES OUTPUT_NAME "openblocks")
|
||||||
target_link_directories(openblocks PUBLIC ${LUAJIT_LIBRARY_DIRS})
|
target_link_directories(openblocks PUBLIC ${LUAJIT_LIBRARY_DIRS})
|
||||||
target_link_libraries(openblocks Jolt pugixml::pugixml Freetype::Freetype glm::glm libluajit ${LuaJIT_LIBRARIES})
|
target_link_libraries(openblocks ${GLEW_LIBRARIES} ${LUAJIT_LIBRARIES} OpenGL::GL ReactPhysics3D::ReactPhysics3D pugixml::pugixml Freetype::Freetype)
|
||||||
target_include_directories(openblocks PUBLIC "src" "../include" "${CMAKE_SOURCE_DIR}/external/glad" ${LUAJIT_INCLUDE_DIRS} ${stb_SOURCE_DIR})
|
target_include_directories(openblocks PUBLIC "src" "../include" ${LUAJIT_INCLUDE_DIRS})
|
||||||
add_dependencies(openblocks autogen_build autogen)
|
add_dependencies(openblocks autogen_build autogen)
|
||||||
|
|
||||||
# Windows-specific dependencies
|
# Windows-specific dependencies
|
||||||
|
|
|
@ -1,30 +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 Jolt GIT_REPOSITORY "https://github.com/jrouwe/JoltPhysics" VERSION 5.3.0 SOURCE_SUBDIR "Build")
|
|
||||||
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})
|
|
|
@ -8,8 +8,9 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class Instance;
|
class Instance;
|
||||||
typedef std::function<void(std::shared_ptr<Instance> object, nullable std::shared_ptr<Instance> oldParent, nullable std::shared_ptr<Instance> newParent)> HierarchyPreUpdateHandler;
|
// typedef std::function<void(std::shared_ptr<Instance> element, std::optional<std::shared_ptr<Instance>> newParent)> HierarchyUpdateHandler;
|
||||||
typedef std::function<void(std::shared_ptr<Instance> object, nullable std::shared_ptr<Instance> oldParent, nullable std::shared_ptr<Instance> newParent)> HierarchyPostUpdateHandler;
|
typedef std::function<void(std::shared_ptr<Instance> object, std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent)> HierarchyPreUpdateHandler;
|
||||||
|
typedef std::function<void(std::shared_ptr<Instance> object, std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent)> HierarchyPostUpdateHandler;
|
||||||
typedef std::function<void(std::shared_ptr<Instance> instance, std::string property, Variant newValue)> PropertyUpdateHandler;
|
typedef std::function<void(std::shared_ptr<Instance> instance, std::string property, Variant newValue)> PropertyUpdateHandler;
|
||||||
|
|
||||||
// TEMPORARY COMMON DATA FOR VARIOUS INTERNAL COMPONENTS
|
// TEMPORARY COMMON DATA FOR VARIOUS INTERNAL COMPONENTS
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
#include "cframe.h"
|
#include "cframe.h"
|
||||||
#include "datatypes/vector.h"
|
#include "datatypes/vector.h"
|
||||||
#include "error/data.h"
|
#include "error/data.h"
|
||||||
|
#include "physics/util.h"
|
||||||
#include <glm/ext/matrix_transform.hpp>
|
#include <glm/ext/matrix_transform.hpp>
|
||||||
#include <glm/gtc/matrix_inverse.hpp>
|
#include <glm/gtc/matrix_inverse.hpp>
|
||||||
#include <glm/gtc/quaternion.hpp>
|
#include <glm/gtc/quaternion.hpp>
|
||||||
#include <glm/matrix.hpp>
|
#include <glm/matrix.hpp>
|
||||||
|
#include <reactphysics3d/mathematics/Transform.h>
|
||||||
#include "datatypes/variant.h"
|
#include "datatypes/variant.h"
|
||||||
#include <pugixml.hpp>
|
#include <pugixml.hpp>
|
||||||
#define GLM_ENABLE_EXPERIMENTAL
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
|
@ -38,6 +40,9 @@ CFrame::CFrame(Vector3 position, glm::quat quat)
|
||||||
, rotation(quat) {
|
, rotation(quat) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CFrame::CFrame(const rp::Transform& transform) : CFrame::CFrame(rpToGlm(transform.getPosition()), rpToGlm(transform.getOrientation())) {
|
||||||
|
}
|
||||||
|
|
||||||
glm::mat3 lookAt(Vector3 position, Vector3 lookAt, Vector3 up) {
|
glm::mat3 lookAt(Vector3 position, Vector3 lookAt, Vector3 up) {
|
||||||
// https://github.com/sgorsten/linalg/issues/29#issuecomment-743989030
|
// https://github.com/sgorsten/linalg/issues/29#issuecomment-743989030
|
||||||
Vector3 f = (lookAt - position).Unit(); // Forward/Look
|
Vector3 f = (lookAt - position).Unit(); // Forward/Look
|
||||||
|
@ -72,6 +77,10 @@ CFrame::operator glm::mat4() const {
|
||||||
return glm::translate(glm::mat4(1.0f), this->translation) * glm::mat4(this->rotation);
|
return glm::translate(glm::mat4(1.0f), this->translation) * glm::mat4(this->rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CFrame::operator rp::Transform() const {
|
||||||
|
return rp::Transform(glmToRp(translation), glmToRp(rotation));
|
||||||
|
}
|
||||||
|
|
||||||
Vector3 CFrame::ToEulerAnglesXYZ() {
|
Vector3 CFrame::ToEulerAnglesXYZ() {
|
||||||
float x;
|
float x;
|
||||||
float y;
|
float y;
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
#include <glm/gtc/matrix_access.hpp>
|
#include <glm/gtc/matrix_access.hpp>
|
||||||
#include <glm/matrix.hpp>
|
#include <glm/matrix.hpp>
|
||||||
|
|
||||||
|
namespace reactphysics3d { class Transform; };
|
||||||
|
|
||||||
class DEF_DATA_(name="CoordinateFrame") CFrame {
|
class DEF_DATA_(name="CoordinateFrame") CFrame {
|
||||||
AUTOGEN_PREAMBLE_DATA
|
AUTOGEN_PREAMBLE_DATA
|
||||||
|
|
||||||
|
@ -22,6 +24,7 @@ public:
|
||||||
DEF_DATA_CTOR CFrame();
|
DEF_DATA_CTOR CFrame();
|
||||||
DEF_DATA_CTOR CFrame(float x, float y, float z, float R00, float R01, float R02, float R10, float R11, float R12, float R20, float R21, float R22);
|
DEF_DATA_CTOR CFrame(float x, float y, float z, float R00, float R01, float R02, float R10, float R11, float R12, float R20, float R21, float R22);
|
||||||
DEF_DATA_CTOR CFrame(Vector3 , Vector3 lookAt, Vector3 up = Vector3(0, 1, 0));
|
DEF_DATA_CTOR CFrame(Vector3 , Vector3 lookAt, Vector3 up = Vector3(0, 1, 0));
|
||||||
|
CFrame(const reactphysics3d::Transform&);
|
||||||
CFrame(Vector3 position, glm::quat quat);
|
CFrame(Vector3 position, glm::quat quat);
|
||||||
virtual ~CFrame();
|
virtual ~CFrame();
|
||||||
|
|
||||||
|
@ -43,11 +46,11 @@ public:
|
||||||
static void PushLuaLibrary(lua_State*);
|
static void PushLuaLibrary(lua_State*);
|
||||||
|
|
||||||
operator glm::mat4() const;
|
operator glm::mat4() const;
|
||||||
|
operator reactphysics3d::Transform() const;
|
||||||
|
|
||||||
//inline static CFrame identity() { }
|
//inline static CFrame identity() { }
|
||||||
DEF_DATA_PROP inline Vector3 Position() const { return translation; }
|
DEF_DATA_PROP inline Vector3 Position() const { return translation; }
|
||||||
DEF_DATA_PROP inline CFrame Rotation() const { return CFrame { glm::vec3(0, 0, 0), rotation }; }
|
DEF_DATA_PROP inline CFrame Rotation() const { return CFrame { glm::vec3(0, 0, 0), rotation }; }
|
||||||
inline glm::mat3 RotMatrix() const { return rotation; }
|
|
||||||
DEF_DATA_METHOD CFrame Inverse() const;
|
DEF_DATA_METHOD CFrame Inverse() const;
|
||||||
DEF_DATA_PROP inline float X() const { return translation.x; }
|
DEF_DATA_PROP inline float X() const { return translation.x; }
|
||||||
DEF_DATA_PROP inline float Y() const { return translation.y; }
|
DEF_DATA_PROP inline float Y() const { return translation.y; }
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
Color3::Color3() {};
|
|
||||||
Color3::Color3(float r, float g, float b) : r(std::clamp(r, 0.f, 1.f)), g(std::clamp(g, 0.f, 1.f)), b(std::clamp(b, 0.f, 1.f)) {};
|
Color3::Color3(float r, float g, float b) : r(std::clamp(r, 0.f, 1.f)), g(std::clamp(g, 0.f, 1.f)), b(std::clamp(b, 0.f, 1.f)) {};
|
||||||
Color3::Color3(const glm::vec3& vec) : r(std::clamp(vec.x, 0.f, 1.f)), g(std::clamp(vec.y, 0.f, 1.f)), b(std::clamp(vec.z, 0.f, 1.f)) {};
|
Color3::Color3(const glm::vec3& vec) : r(std::clamp(vec.x, 0.f, 1.f)), g(std::clamp(vec.y, 0.f, 1.f)), b(std::clamp(vec.z, 0.f, 1.f)) {};
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ class DEF_DATA Color3 {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DEF_DATA_CTOR Color3(float r, float g, float b);
|
DEF_DATA_CTOR Color3(float r, float g, float b);
|
||||||
Color3();
|
|
||||||
Color3(const glm::vec3&);
|
Color3(const glm::vec3&);
|
||||||
virtual ~Color3();
|
virtual ~Color3();
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ void Bool_PushLuaValue(Variant self, lua_State* L) {
|
||||||
result<Variant, LuaCastError> Bool_FromLuaValue(lua_State* L, int idx) {
|
result<Variant, LuaCastError> Bool_FromLuaValue(lua_State* L, int idx) {
|
||||||
if (!lua_isboolean(L, idx))
|
if (!lua_isboolean(L, idx))
|
||||||
return LuaCastError(lua_typename(L, idx), "boolean");
|
return LuaCastError(lua_typename(L, idx), "boolean");
|
||||||
return Variant((bool)lua_toboolean(L, idx));
|
return Variant(lua_toboolean(L, idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
const TypeDesc BOOL_TYPE {
|
const TypeDesc BOOL_TYPE {
|
||||||
|
|
|
@ -151,9 +151,9 @@ static int inst_index(lua_State* L) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for child
|
// Look for child
|
||||||
nullable std::shared_ptr<Instance> child = inst->FindFirstChild(key);
|
std::optional<std::shared_ptr<Instance>> child = inst->FindFirstChild(key);
|
||||||
if (child) {
|
if (child) {
|
||||||
InstanceRef(child).PushLuaValue(L);
|
InstanceRef(child.value()).PushLuaValue(L);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,7 +173,7 @@ static int inst_newindex(lua_State* L) {
|
||||||
if (meta->flags & PROP_READONLY)
|
if (meta->flags & PROP_READONLY)
|
||||||
return luaL_error(L, "'%s' of %s is read-only", key.c_str(), inst->GetClass()->className.c_str());
|
return luaL_error(L, "'%s' of %s is read-only", key.c_str(), inst->GetClass()->className.c_str());
|
||||||
if (key == "Parent" && inst->IsParentLocked())
|
if (key == "Parent" && inst->IsParentLocked())
|
||||||
return luaL_error(L, "Cannot set property Parent (%s) of %s, parent is locked", inst->GetParent() ? inst->GetParent()->name.c_str() : "NULL", inst->GetClass()->className.c_str());
|
return luaL_error(L, "Cannot set property Parent (%s) of %s, parent is locked", inst->GetParent() ? inst->GetParent().value()->name.c_str() : "NULL", inst->GetClass()->className.c_str());
|
||||||
|
|
||||||
// TODO: Make this work for enums, this is not a solution!!
|
// TODO: Make this work for enums, this is not a solution!!
|
||||||
result<Variant, LuaCastError> value = meta->type.descriptor->fromLuaValue(L, -1);
|
result<Variant, LuaCastError> value = meta->type.descriptor->fromLuaValue(L, -1);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
extern const char* WRAPPER_SRC; // TODO: Move this to a shared header
|
||||||
int script_errhandler(lua_State*); // extern
|
int script_errhandler(lua_State*); // extern
|
||||||
|
|
||||||
SignalSource::SignalSource() : std::shared_ptr<Signal>(std::make_shared<Signal>()) {}
|
SignalSource::SignalSource() : std::shared_ptr<Signal>(std::make_shared<Signal>()) {}
|
||||||
|
@ -38,11 +39,30 @@ LuaSignalConnection::~LuaSignalConnection() {
|
||||||
luaL_unref(state, LUA_REGISTRYINDEX, thread);
|
luaL_unref(state, LUA_REGISTRYINDEX, thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static void stackdump(lua_State* L) {
|
||||||
|
printf("%d\n", lua_gettop(L));
|
||||||
|
fflush(stdout);
|
||||||
|
lua_getfield(L, LUA_GLOBALSINDEX, "tostring");
|
||||||
|
for (int i = lua_gettop(L)-1; i >= 1; i--) {
|
||||||
|
lua_pushvalue(L, -1);
|
||||||
|
lua_pushvalue(L, i);
|
||||||
|
lua_call(L, 1, 1);
|
||||||
|
const char* str = lua_tostring(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
printf("%s: %s\n", lua_typename(L, lua_type(L, i)), str);
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
printf("\n\n");
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void LuaSignalConnection::Call(std::vector<Variant> args) {
|
void LuaSignalConnection::Call(std::vector<Variant> args) {
|
||||||
lua_State* thread = lua_newthread(state);
|
lua_State* thread = lua_newthread(state);
|
||||||
|
|
||||||
// Push wrapepr as thread function
|
// Push wrapepr as thread function
|
||||||
lua_getfield(thread, LUA_REGISTRYINDEX, "LuaPCallWrapper");
|
luaL_loadbuffer(thread, WRAPPER_SRC, strlen(WRAPPER_SRC), "=PCALL_WRAPPER");
|
||||||
|
|
||||||
// Push function as upvalue for wrapper
|
// Push function as upvalue for wrapper
|
||||||
lua_rawgeti(thread, LUA_REGISTRYINDEX, function);
|
lua_rawgeti(thread, LUA_REGISTRYINDEX, function);
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <glm/ext/quaternion_geometric.hpp>
|
#include <glm/ext/quaternion_geometric.hpp>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
#include <reactphysics3d/mathematics/Vector3.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <pugixml.hpp>
|
#include <pugixml.hpp>
|
||||||
#include "datatypes/base.h"
|
#include "datatypes/base.h"
|
||||||
|
@ -10,8 +11,11 @@
|
||||||
#include "error/data.h"
|
#include "error/data.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace rp = reactphysics3d;
|
||||||
|
|
||||||
Vector3::Vector3() : vector(glm::vec3(0, 0, 0)) {};
|
Vector3::Vector3() : vector(glm::vec3(0, 0, 0)) {};
|
||||||
Vector3::Vector3(const glm::vec3& src) : vector(src) {};
|
Vector3::Vector3(const glm::vec3& src) : vector(src) {};
|
||||||
|
Vector3::Vector3(const rp::Vector3& src) : vector(glm::vec3(src.x, src.y, src.z)) {};
|
||||||
Vector3::Vector3(float x, const float y, float z) : vector(glm::vec3(x, y, z)) {};
|
Vector3::Vector3(float x, const float y, float z) : vector(glm::vec3(x, y, z)) {};
|
||||||
|
|
||||||
Vector3::~Vector3() = default;
|
Vector3::~Vector3() = default;
|
||||||
|
@ -27,6 +31,7 @@ const std::string Vector3::ToString() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3::operator glm::vec3() const { return vector; };
|
Vector3::operator glm::vec3() const { return vector; };
|
||||||
|
Vector3::operator rp::Vector3() const { return rp::Vector3(X(), Y(), Z()); };
|
||||||
|
|
||||||
// Operators
|
// Operators
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
#include "error/data.h"
|
#include "error/data.h"
|
||||||
#include <glm/ext/vector_float3.hpp>
|
#include <glm/ext/vector_float3.hpp>
|
||||||
#include <glm/geometric.hpp>
|
#include <glm/geometric.hpp>
|
||||||
|
#include <reactphysics3d/mathematics/Vector3.h>
|
||||||
|
|
||||||
|
// namespace reactphysics3d { class Vector3; };
|
||||||
|
|
||||||
class DEF_DATA Vector3 {
|
class DEF_DATA Vector3 {
|
||||||
AUTOGEN_PREAMBLE_DATA
|
AUTOGEN_PREAMBLE_DATA
|
||||||
|
@ -15,6 +18,7 @@ public:
|
||||||
DEF_DATA_CTOR Vector3(float x, float y, float z);
|
DEF_DATA_CTOR Vector3(float x, float y, float z);
|
||||||
inline Vector3(float value) : Vector3(value, value, value) {}
|
inline Vector3(float value) : Vector3(value, value, value) {}
|
||||||
Vector3(const glm::vec3&);
|
Vector3(const glm::vec3&);
|
||||||
|
Vector3(const reactphysics3d::Vector3&);
|
||||||
virtual ~Vector3();
|
virtual ~Vector3();
|
||||||
|
|
||||||
DEF_DATA_PROP static Vector3 ZERO;
|
DEF_DATA_PROP static Vector3 ZERO;
|
||||||
|
@ -29,6 +33,7 @@ public:
|
||||||
static void PushLuaLibrary(lua_State*);
|
static void PushLuaLibrary(lua_State*);
|
||||||
|
|
||||||
operator glm::vec3() const;
|
operator glm::vec3() const;
|
||||||
|
operator reactphysics3d::Vector3() const;
|
||||||
|
|
||||||
DEF_DATA_PROP inline float X() const { return vector.x; }
|
DEF_DATA_PROP inline float X() const { return vector.x; }
|
||||||
DEF_DATA_PROP inline float Y() const { return vector.y; }
|
DEF_DATA_PROP inline float Y() const { return vector.y; }
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "datatypes/enum.h"
|
|
||||||
#include "enum/annotation.h"
|
|
||||||
|
|
||||||
|
|
||||||
enum class DEF_ENUM PartType {
|
|
||||||
Ball = 0,
|
|
||||||
Block = 1,
|
|
||||||
Cylinder = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace EnumType {
|
|
||||||
extern const Enum PartType;
|
|
||||||
};
|
|
|
@ -1,2 +0,0 @@
|
||||||
#define GLAD_GL_IMPLEMENTATION
|
|
||||||
#include <glad/gl.h>
|
|
|
@ -8,6 +8,10 @@
|
||||||
#include <glm/ext/scalar_common.hpp>
|
#include <glm/ext/scalar_common.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <reactphysics3d/collision/RaycastInfo.h>
|
||||||
|
#include <reactphysics3d/engine/PhysicsCommon.h>
|
||||||
|
#include <reactphysics3d/engine/PhysicsWorld.h>
|
||||||
|
#include <reactphysics3d/mathematics/Transform.h>
|
||||||
|
|
||||||
HandleFace HandleFace::XPos(0, glm::vec3(1,0,0));
|
HandleFace HandleFace::XPos(0, glm::vec3(1,0,0));
|
||||||
HandleFace HandleFace::XNeg(1, glm::vec3(-1,0,0));
|
HandleFace HandleFace::XNeg(1, glm::vec3(-1,0,0));
|
||||||
|
@ -19,11 +23,15 @@ std::array<HandleFace, 6> HandleFace::Faces { HandleFace::XPos, HandleFace::XNeg
|
||||||
|
|
||||||
static CFrame XYZToZXY(glm::vec3(0, 0, 0), -glm::vec3(1, 0, 0), glm::vec3(0, 0, 1));
|
static CFrame XYZToZXY(glm::vec3(0, 0, 0), -glm::vec3(1, 0, 0), glm::vec3(0, 0, 1));
|
||||||
|
|
||||||
std::shared_ptr<BasePart> getHandleAdornee() {
|
// Shitty solution
|
||||||
|
static rp3d::PhysicsCommon common;
|
||||||
|
static rp3d::PhysicsWorld* world = common.createPhysicsWorld();
|
||||||
|
|
||||||
|
std::shared_ptr<Part> getHandleAdornee() {
|
||||||
std::shared_ptr<Selection> selection = gDataModel->GetService<Selection>();
|
std::shared_ptr<Selection> selection = gDataModel->GetService<Selection>();
|
||||||
for (std::weak_ptr<Instance> inst : selection->Get()) {
|
for (std::weak_ptr<Instance> inst : selection->Get()) {
|
||||||
if (!inst.expired() && inst.lock()->IsA<BasePart>())
|
if (!inst.expired() && inst.lock()->IsA<Part>())
|
||||||
return inst.lock()->CastTo<BasePart>().expect();
|
return inst.lock()->CastTo<Part>().expect();
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
@ -44,25 +52,24 @@ CFrame partCFrameFromHandlePos(HandleFace face, Vector3 newPos) {
|
||||||
return adornee->cframe.Rotation() + newPartPos;
|
return adornee->cframe.Rotation() + newPartPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<HandleFace> raycastHandle(Vector3 rayStart, Vector3 rayEnd) {
|
std::optional<HandleFace> raycastHandle(rp3d::Ray ray) {
|
||||||
std::optional<HandleFace> closestFace = {};
|
|
||||||
float closestDistance = -1;
|
|
||||||
|
|
||||||
for (HandleFace face : HandleFace::Faces) {
|
for (HandleFace face : HandleFace::Faces) {
|
||||||
CFrame cframe = getHandleCFrame(face);
|
CFrame cframe = getHandleCFrame(face);
|
||||||
|
// Implement manual detection via boxes instead of... this shit
|
||||||
|
// This code also hardly works, and is not good at all... Hooo nope.
|
||||||
|
rp3d::RigidBody* body = world->createRigidBody(CFrame::IDENTITY + cframe.Position());
|
||||||
|
body->addCollider(common.createBoxShape(cframe.Rotation() * Vector3(handleSize(face) / 2.f)), rp3d::Transform::identity());
|
||||||
|
|
||||||
Vector3 halfSize = (cframe.Rotation() * Vector3(handleSize(face) / 2.f)).Abs();
|
rp3d::RaycastInfo info;
|
||||||
Vector3 minB = cframe.Position() - halfSize, maxB = cframe.Position() + halfSize;
|
if (body->raycast(ray, info)) {
|
||||||
|
world->destroyRigidBody(body);
|
||||||
glm::vec3 hitPoint;
|
return face;
|
||||||
bool hit = HitBoundingBox(minB, maxB, rayStart, (rayEnd - rayStart).Unit(), hitPoint);
|
|
||||||
float distance = ((Vector3)hitPoint - rayStart).Magnitude();
|
|
||||||
|
|
||||||
if (hit && (closestDistance == -1 || distance < closestDistance))
|
|
||||||
closestFace = face, closestDistance = distance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return closestFace;
|
world->destroyRigidBody(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 handleSize(HandleFace face) {
|
Vector3 handleSize(HandleFace face) {
|
||||||
|
@ -75,8 +82,8 @@ static int getAABBOfSelection(glm::vec3& pos, glm::vec3& size, glm::vec3& min, g
|
||||||
int count = 0;
|
int count = 0;
|
||||||
std::shared_ptr<Selection> selection = gDataModel->GetService<Selection>();
|
std::shared_ptr<Selection> selection = gDataModel->GetService<Selection>();
|
||||||
for (std::weak_ptr<Instance> inst : selection->Get()) {
|
for (std::weak_ptr<Instance> inst : selection->Get()) {
|
||||||
if (inst.expired() || !inst.lock()->IsA<BasePart>()) continue;
|
if (inst.expired() || !inst.lock()->IsA<Part>()) continue;
|
||||||
std::shared_ptr<BasePart> part = inst.lock()->CastTo<BasePart>().expect();
|
std::shared_ptr<Part> part = inst.lock()->CastTo<Part>().expect();
|
||||||
|
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
min = part->position(), max = part->position();
|
min = part->position(), max = part->position();
|
||||||
|
@ -92,12 +99,12 @@ static int getAABBOfSelection(glm::vec3& pos, glm::vec3& size, glm::vec3& min, g
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::shared_ptr<BasePart> getFirstSelectedPart() {
|
static std::shared_ptr<Part> getFirstSelectedPart() {
|
||||||
std::shared_ptr<Selection> selection = gDataModel->GetService<Selection>();
|
std::shared_ptr<Selection> selection = gDataModel->GetService<Selection>();
|
||||||
for (std::weak_ptr<Instance> inst : selection->Get()) {
|
for (std::weak_ptr<Instance> inst : selection->Get()) {
|
||||||
if (inst.expired() || !inst.lock()->IsA<BasePart>()) continue;
|
if (inst.expired() || !inst.lock()->IsA<Part>()) continue;
|
||||||
|
|
||||||
return inst.lock()->CastTo<BasePart>().expect();
|
return inst.lock()->CastTo<Part>().expect();
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "datatypes/cframe.h"
|
#include "datatypes/cframe.h"
|
||||||
#include "objects/part/part.h"
|
#include "objects/part.h"
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
@ -36,11 +36,11 @@ struct Handles {
|
||||||
bool worldMode = false;
|
bool worldMode = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<BasePart> getHandleAdornee();
|
std::shared_ptr<Part> getHandleAdornee();
|
||||||
CFrame getHandleCFrame(HandleFace face);
|
CFrame getHandleCFrame(HandleFace face);
|
||||||
CFrame partCFrameFromHandlePos(HandleFace face, Vector3 newPos);
|
CFrame partCFrameFromHandlePos(HandleFace face, Vector3 newPos);
|
||||||
Vector3 handleSize(HandleFace face);
|
Vector3 handleSize(HandleFace face);
|
||||||
std::optional<HandleFace> raycastHandle(Vector3 rayStart, Vector3 rayEnd);
|
std::optional<HandleFace> raycastHandle(rp3d::Ray ray);
|
||||||
|
|
||||||
// Gets the cframe of the handle local to the center of the selected objects
|
// Gets the cframe of the handle local to the center of the selected objects
|
||||||
CFrame getLocalHandleCFrame(HandleFace face);
|
CFrame getLocalHandleCFrame(HandleFace face);
|
||||||
|
|
|
@ -9,33 +9,26 @@
|
||||||
|
|
||||||
static std::ofstream logStream;
|
static std::ofstream logStream;
|
||||||
static std::vector<Logger::LogListener> logListeners;
|
static std::vector<Logger::LogListener> logListeners;
|
||||||
|
static std::vector<Logger::TraceLogListener> traceLogListeners;
|
||||||
std::string Logger::currentLogDir = "NULL";
|
std::string Logger::currentLogDir = "NULL";
|
||||||
static std::stringstream* rawOutputBuffer = nullptr;
|
|
||||||
|
|
||||||
void Logger::init() {
|
void Logger::init() {
|
||||||
initProgramLogsDir();
|
initProgramLogsDir();
|
||||||
|
|
||||||
const auto now = std::chrono::system_clock::now();
|
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));
|
logStream = std::ofstream(currentLogDir = (getProgramLogsDir() + "/" + fileName));
|
||||||
Logger::debug("Logger initialized");
|
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() {
|
void Logger::finish() {
|
||||||
Logger::debug("Closing logger...");
|
Logger::debug("Closing logger...");
|
||||||
logStream.close();
|
logStream.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::log(std::string message, Logger::LogLevel logLevel, ScriptSource source) {
|
void Logger::log(std::string message, Logger::LogLevel logLevel) {
|
||||||
std::string logLevelStr = logLevel == Logger::LogLevel::INFO ? "INFO" :
|
std::string logLevelStr = logLevel == Logger::LogLevel::INFO ? "INFO" :
|
||||||
logLevel == Logger::LogLevel::DEBUG ? "DEBUG" :
|
logLevel == Logger::LogLevel::DEBUG ? "DEBUG" :
|
||||||
logLevel == Logger::LogLevel::TRACE ? "TRACE" :
|
logLevel == Logger::LogLevel::TRACE ? "TRACE" :
|
||||||
|
@ -49,10 +42,9 @@ void Logger::log(std::string message, Logger::LogLevel logLevel, ScriptSource so
|
||||||
|
|
||||||
logStream << formattedLogLine << std::endl;
|
logStream << formattedLogLine << std::endl;
|
||||||
printf("%s\n", formattedLogLine.c_str());
|
printf("%s\n", formattedLogLine.c_str());
|
||||||
if (rawOutputBuffer != nullptr) *rawOutputBuffer << logLevelStr << ": " << message << "\n";
|
|
||||||
|
|
||||||
for (Logger::LogListener listener : logListeners) {
|
for (Logger::LogListener listener : logListeners) {
|
||||||
listener(logLevel, message, source);
|
listener(logLevel, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logLevel == Logger::LogLevel::FATAL_ERROR) {
|
if (logLevel == Logger::LogLevel::FATAL_ERROR) {
|
||||||
|
@ -60,10 +52,20 @@ void Logger::log(std::string message, Logger::LogLevel logLevel, ScriptSource so
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Logger::trace(std::string source, int line, void* userData) {
|
||||||
|
std::string message = "'" + source + "' Line " + std::to_string(line);
|
||||||
|
|
||||||
|
log(message, Logger::LogLevel::TRACE);
|
||||||
|
|
||||||
|
for (Logger::TraceLogListener listener : traceLogListeners) {
|
||||||
|
listener(message, source, line, userData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Logger::addLogListener(Logger::LogListener listener) {
|
void Logger::addLogListener(Logger::LogListener listener) {
|
||||||
logListeners.push_back(listener);
|
logListeners.push_back(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::resetLogListeners() {
|
void Logger::addLogListener(Logger::TraceLogListener listener) {
|
||||||
logListeners.clear();
|
traceLogListeners.push_back(listener);
|
||||||
}
|
}
|
|
@ -1,12 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <format>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
|
||||||
#include <ostream>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class Script;
|
|
||||||
|
|
||||||
namespace Logger {
|
namespace Logger {
|
||||||
enum class LogLevel {
|
enum class LogLevel {
|
||||||
INFO,
|
INFO,
|
||||||
|
@ -17,39 +14,32 @@ namespace Logger {
|
||||||
FATAL_ERROR,
|
FATAL_ERROR,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ScriptSource {
|
typedef std::function<void(LogLevel logLevel, std::string message)> LogListener;
|
||||||
std::shared_ptr<Script> script;
|
typedef std::function<void(std::string message, std::string source, int line, void* userData)> TraceLogListener;
|
||||||
int line;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::function<void(LogLevel logLevel, std::string message, ScriptSource source)> LogListener;
|
|
||||||
|
|
||||||
extern std::string currentLogDir;
|
extern std::string currentLogDir;
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
void initTest(std::stringstream* out); // Testing only!
|
|
||||||
void finish();
|
void finish();
|
||||||
void addLogListener(LogListener);
|
void addLogListener(LogListener);
|
||||||
void resetLogListeners(); // Testing only!
|
void addLogListener(TraceLogListener);
|
||||||
|
|
||||||
void log(std::string message, LogLevel logLevel, ScriptSource source = {});
|
void log(std::string message, LogLevel logLevel);
|
||||||
inline void info(std::string message) { log(message, LogLevel::INFO); }
|
inline void info(std::string message) { log(message, LogLevel::INFO); }
|
||||||
inline void debug(std::string message) { log(message, LogLevel::DEBUG); }
|
inline void debug(std::string message) { log(message, LogLevel::DEBUG); }
|
||||||
inline void warning(std::string message) { log(message, LogLevel::WARNING); }
|
inline void warning(std::string message) { log(message, LogLevel::WARNING); }
|
||||||
inline void error(std::string message) { log(message, LogLevel::ERROR); }
|
inline void error(std::string message) { log(message, LogLevel::ERROR); }
|
||||||
inline void fatalError(std::string message) { log(message, LogLevel::FATAL_ERROR); }
|
inline void fatalError(std::string message) { log(message, LogLevel::FATAL_ERROR); }
|
||||||
inline void trace(std::string message) { log(message, LogLevel::TRACE); };
|
|
||||||
|
|
||||||
template <typename ...Args>
|
inline void traceStart() { log("Stack start", LogLevel::TRACE); }
|
||||||
void scriptLogf(std::string format, LogLevel logLevel, ScriptSource source, Args&&... args) {
|
inline void traceEnd() { log("Stack end", LogLevel::TRACE); }
|
||||||
char message[200];
|
void trace(std::string source, int line, void* userData = nullptr);
|
||||||
sprintf(message, format.c_str(), args...);
|
|
||||||
log(message, logLevel, source);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename ...Args>
|
template <typename ...Args>
|
||||||
void logf(std::string format, LogLevel logLevel, Args&&... args) {
|
void logf(std::string format, LogLevel logLevel, Args&&... args) {
|
||||||
scriptLogf(format, logLevel, {}, args...);
|
char message[200];
|
||||||
|
sprintf(message, format.c_str(), args...);
|
||||||
|
log(message, logLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ...Args> inline void infof(std::string format, Args&&... args) { logf(format, LogLevel::INFO, args...); }
|
template <typename ...Args> inline void infof(std::string format, Args&&... args) { logf(format, LogLevel::INFO, args...); }
|
||||||
|
|
|
@ -6,8 +6,6 @@ extern "C" {
|
||||||
#include <lua.h>
|
#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) {
|
inline const char* x_luaL_udatatname (lua_State *L, int ud) {
|
||||||
void *p = lua_touserdata(L, ud);
|
void *p = lua_touserdata(L, ud);
|
||||||
if (p != NULL) {
|
if (p != NULL) {
|
||||||
|
@ -19,5 +17,3 @@ inline const char* x_luaL_udatatname (lua_State *L, int ud) {
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define LUA_OK 0
|
|
|
@ -2,65 +2,9 @@
|
||||||
|
|
||||||
#define CMP_EPSILON 0.00001
|
#define CMP_EPSILON 0.00001
|
||||||
|
|
||||||
|
|
||||||
void expandAABB(glm::vec3& min, glm::vec3& max, glm::vec3 point) {
|
|
||||||
min = glm::vec3(glm::min(min.x, point.x), glm::min(min.y, point.y), glm::min(min.z, point.z));
|
|
||||||
max = glm::vec3(glm::max(max.x, point.x), glm::max(max.y, point.y), glm::max(max.z, point.z));
|
|
||||||
}
|
|
||||||
|
|
||||||
void computeAABBFromPoints(glm::vec3& min, glm::vec3& max, glm::vec3* points, int count) {
|
|
||||||
if (count == 0) return;
|
|
||||||
|
|
||||||
min = points[0];
|
|
||||||
max = points[0];
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
min = glm::vec3(glm::min(min.x, points[i].x), glm::min(min.y, points[i].y), glm::min(min.z, points[i].z));
|
|
||||||
max = glm::vec3(glm::max(max.x, points[i].x), glm::max(max.y, points[i].y), glm::max(max.z, points[i].z));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void getAABBCoords(glm::vec3 &pos, glm::vec3 &size, glm::vec3 min, glm::vec3 max) {
|
|
||||||
pos = (max + min) / 2.f;
|
|
||||||
size = (max - min);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ==================== THIRD-PARTY SOURCE CODE ==================== //
|
|
||||||
|
|
||||||
// After a long time researching, I was able to use and adapt Godot's implementation of movable handles (godot/editor/plugins/gizmos/gizmo_3d_helper.cpp)
|
// After a long time researching, I was able to use and adapt Godot's implementation of movable handles (godot/editor/plugins/gizmos/gizmo_3d_helper.cpp)
|
||||||
// All thanks goes to them and David Eberly for his algorithm.
|
// All thanks goes to them and David Eberly for his algorithm.
|
||||||
|
|
||||||
/**************************************************************************/
|
|
||||||
/* geometry_3d.cpp */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* This file is part of: */
|
|
||||||
/* GODOT ENGINE */
|
|
||||||
/* https://godotengine.org */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
|
||||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
|
||||||
/* */
|
|
||||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
|
||||||
/* a copy of this software and associated documentation files (the */
|
|
||||||
/* "Software"), to deal in the Software without restriction, including */
|
|
||||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
||||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
|
||||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
|
||||||
/* the following conditions: */
|
|
||||||
/* */
|
|
||||||
/* The above copyright notice and this permission notice shall be */
|
|
||||||
/* included in all copies or substantial portions of the Software. */
|
|
||||||
/* */
|
|
||||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
|
||||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
|
||||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
|
||||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
|
||||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
|
||||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
||||||
/**************************************************************************/
|
|
||||||
|
|
||||||
void get_closest_points_between_segments(const glm::vec3 &p_p0, const glm::vec3 &p_p1, const glm::vec3 &p_q0, const glm::vec3 &p_q1, glm::vec3 &r_ps, glm::vec3 &r_qt) {
|
void get_closest_points_between_segments(const glm::vec3 &p_p0, const glm::vec3 &p_p1, const glm::vec3 &p_q0, const glm::vec3 &p_q1, glm::vec3 &r_ps, glm::vec3 &r_qt) {
|
||||||
// Based on David Eberly's Computation of Distance Between Line Segments algorithm.
|
// Based on David Eberly's Computation of Distance Between Line Segments algorithm.
|
||||||
|
|
||||||
|
@ -158,83 +102,24 @@ void get_closest_points_between_segments(const glm::vec3 &p_p0, const glm::vec3
|
||||||
r_qt = (1 - t) * p_q0 + t * p_q1;
|
r_qt = (1 - t) * p_q0 + t * p_q1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/erich666/GraphicsGems/tree/master?tab=License-1-ov-file#readme
|
void expandAABB(glm::vec3& min, glm::vec3& max, glm::vec3 point) {
|
||||||
// Note: The code below predates open source
|
min = glm::vec3(glm::min(min.x, point.x), glm::min(min.y, point.y), glm::min(min.z, point.z));
|
||||||
|
max = glm::vec3(glm::max(max.x, point.x), glm::max(max.y, point.y), glm::max(max.z, point.z));
|
||||||
/*
|
|
||||||
* EULA: The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code as your own
|
|
||||||
* and resell it. Using the code is permitted in any program, product, or library, non-commercial or commercial. Giving
|
|
||||||
* credit is not required, though is a nice gesture. The code comes as-is, and if there are any flaws or problems with
|
|
||||||
* any Gems code, nobody involved with Gems - authors, editors, publishers, or webmasters - are to be held responsible.
|
|
||||||
* Basically, don't be a jerk, and remember that anything free comes with no guarantee.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Fast Ray-Box Intersection
|
|
||||||
by Andrew Woo
|
|
||||||
from "Graphics Gems", Academic Press, 1990
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define RIGHT 0
|
|
||||||
#define LEFT 1
|
|
||||||
#define MIDDLE 2
|
|
||||||
|
|
||||||
bool HitBoundingBox(
|
|
||||||
glm::vec3 minB, glm::vec3 maxB, /*box */
|
|
||||||
glm::vec3 origin, glm::vec3 dir, /*ray */
|
|
||||||
glm::vec3 &coord /* hit point */
|
|
||||||
) {
|
|
||||||
bool inside = true;
|
|
||||||
glm::vec3 quadrant;
|
|
||||||
int i;
|
|
||||||
int whichPlane;
|
|
||||||
glm::vec3 maxT;
|
|
||||||
glm::vec3 candidatePlane;
|
|
||||||
|
|
||||||
/* Find candidate planes; this loop can be avoided if
|
|
||||||
rays cast all from the eye(assume perpsective view) */
|
|
||||||
for (i = 0; i < 3; i++)
|
|
||||||
if(origin[i] < minB[i]) {
|
|
||||||
quadrant[i] = LEFT;
|
|
||||||
candidatePlane[i] = minB[i];
|
|
||||||
inside = false;
|
|
||||||
}else if (origin[i] > maxB[i]) {
|
|
||||||
quadrant[i] = RIGHT;
|
|
||||||
candidatePlane[i] = maxB[i];
|
|
||||||
inside = false;
|
|
||||||
}else {
|
|
||||||
quadrant[i] = MIDDLE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ray origin inside bounding box */
|
void computeAABBFromPoints(glm::vec3& min, glm::vec3& max, glm::vec3* points, int count) {
|
||||||
if (inside) {
|
if (count == 0) return;
|
||||||
coord = origin;
|
|
||||||
return (true);
|
min = points[0];
|
||||||
|
max = points[0];
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
min = glm::vec3(glm::min(min.x, points[i].x), glm::min(min.y, points[i].y), glm::min(min.z, points[i].z));
|
||||||
|
max = glm::vec3(glm::max(max.x, points[i].x), glm::max(max.y, points[i].y), glm::max(max.z, points[i].z));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void getAABBCoords(glm::vec3 &pos, glm::vec3 &size, glm::vec3 min, glm::vec3 max) {
|
||||||
/* Calculate T distances to candidate planes */
|
pos = (max + min) / 2.f;
|
||||||
for (i = 0; i < 3; i++)
|
size = (max - min);
|
||||||
if (quadrant[i] != MIDDLE && dir[i] !=0.)
|
|
||||||
maxT[i] = (candidatePlane[i]-origin[i]) / dir[i];
|
|
||||||
else
|
|
||||||
maxT[i] = -1.;
|
|
||||||
|
|
||||||
/* Get largest of the maxT's for final choice of intersection */
|
|
||||||
whichPlane = 0;
|
|
||||||
for (i = 1; i < 3; i++)
|
|
||||||
if (maxT[whichPlane] < maxT[i])
|
|
||||||
whichPlane = i;
|
|
||||||
|
|
||||||
/* Check final candidate actually inside box */
|
|
||||||
if (maxT[whichPlane] < 0.) return (false);
|
|
||||||
for (i = 0; i < 3; i++)
|
|
||||||
if (whichPlane != i) {
|
|
||||||
coord[i] = origin[i] + maxT[whichPlane] * dir[i];
|
|
||||||
if (coord[i] < minB[i] || coord[i] > maxB[i])
|
|
||||||
return (false);
|
|
||||||
} else {
|
|
||||||
coord[i] = candidatePlane[i];
|
|
||||||
}
|
|
||||||
return true; /* ray hits box */
|
|
||||||
}
|
}
|
|
@ -1,20 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
void expandAABB(glm::vec3& min, glm::vec3& max, glm::vec3 point);
|
|
||||||
void computeAABBFromPoints(glm::vec3& min, glm::vec3& max, glm::vec3* points, int count);
|
|
||||||
void getAABBCoords(glm::vec3& pos, glm::vec3& size, glm::vec3 min, glm::vec3 max);
|
|
||||||
|
|
||||||
// From godot/editor/plugins/gizmos/gizmo_3d_helper.h
|
// From godot/editor/plugins/gizmos/gizmo_3d_helper.h
|
||||||
void get_closest_points_between_segments(const glm::vec3 &p_p0, const glm::vec3 &p_p1, const glm::vec3 &p_q0, const glm::vec3 &p_q1, glm::vec3 &r_ps, glm::vec3 &r_qt);
|
void get_closest_points_between_segments(const glm::vec3 &p_p0, const glm::vec3 &p_p1, const glm::vec3 &p_q0, const glm::vec3 &p_q1, glm::vec3 &r_ps, glm::vec3 &r_qt);
|
||||||
|
|
||||||
/*
|
void expandAABB(glm::vec3& min, glm::vec3& max, glm::vec3 point);
|
||||||
Fast Ray-Box Intersection
|
void computeAABBFromPoints(glm::vec3& min, glm::vec3& max, glm::vec3* points, int count);
|
||||||
by Andrew Woo
|
void getAABBCoords(glm::vec3& pos, glm::vec3& size, glm::vec3 min, glm::vec3 max);
|
||||||
from "Graphics Gems", Academic Press, 1990
|
|
||||||
*/
|
|
||||||
bool HitBoundingBox(
|
|
||||||
glm::vec3 minB, glm::vec3 maxB, /*box */
|
|
||||||
glm::vec3 origin, glm::vec3 dir, /*ray */
|
|
||||||
glm::vec3 &coord /* hit point */
|
|
||||||
);
|
|
|
@ -44,16 +44,21 @@ Instance::Instance(const InstanceType* type) {
|
||||||
Instance::~Instance () {
|
Instance::~Instance () {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::weak_ptr<T> optional_to_weak(std::optional<std::shared_ptr<T>> a) {
|
||||||
|
return a ? a.value() : std::weak_ptr<T>();
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Test this
|
// TODO: Test this
|
||||||
bool Instance::ancestryContinuityCheck(nullable std::shared_ptr<Instance> newParent) {
|
bool Instance::ancestryContinuityCheck(std::optional<std::shared_ptr<Instance>> newParent) {
|
||||||
for (std::shared_ptr<Instance> currentParent = newParent; currentParent != nullptr; currentParent = currentParent->GetParent()) {
|
for (std::optional<std::shared_ptr<Instance>> currentParent = newParent; currentParent.has_value(); currentParent = currentParent.value()->GetParent()) {
|
||||||
if (currentParent == this->shared_from_this())
|
if (currentParent.value() == this->shared_from_this())
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Instance::SetParent(nullable std::shared_ptr<Instance> newParent) {
|
bool Instance::SetParent(std::optional<std::shared_ptr<Instance>> newParent) {
|
||||||
if (this->parentLocked || !ancestryContinuityCheck(newParent))
|
if (this->parentLocked || !ancestryContinuityCheck(newParent))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -65,10 +70,10 @@ bool Instance::SetParent(nullable std::shared_ptr<Instance> newParent) {
|
||||||
oldParent->children.erase(std::find(oldParent->children.begin(), oldParent->children.end(), this->shared_from_this()));
|
oldParent->children.erase(std::find(oldParent->children.begin(), oldParent->children.end(), this->shared_from_this()));
|
||||||
}
|
}
|
||||||
// Add ourselves to the new parent
|
// Add ourselves to the new parent
|
||||||
if (newParent != nullptr) {
|
if (newParent.has_value()) {
|
||||||
newParent->children.push_back(this->shared_from_this());
|
newParent.value()->children.push_back(this->shared_from_this());
|
||||||
}
|
}
|
||||||
this->parent = newParent;
|
this->parent = optional_to_weak(newParent);
|
||||||
// TODO: Add code for sending signals for parent updates
|
// TODO: Add code for sending signals for parent updates
|
||||||
// TODO: Yeahhh maybe this isn't the best way of doing this?
|
// TODO: Yeahhh maybe this isn't the best way of doing this?
|
||||||
if (hierarchyPostUpdateHandler.has_value()) hierarchyPostUpdateHandler.value()(this->shared_from_this(), lastParent, newParent);
|
if (hierarchyPostUpdateHandler.has_value()) hierarchyPostUpdateHandler.value()(this->shared_from_this(), lastParent, newParent);
|
||||||
|
@ -80,21 +85,21 @@ bool Instance::SetParent(nullable std::shared_ptr<Instance> newParent) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::updateAncestry(nullable std::shared_ptr<Instance> updatedChild, nullable std::shared_ptr<Instance> newParent) {
|
void Instance::updateAncestry(std::optional<std::shared_ptr<Instance>> updatedChild, std::optional<std::shared_ptr<Instance>> newParent) {
|
||||||
auto oldDataModel = _dataModel;
|
auto oldDataModel = _dataModel;
|
||||||
auto oldWorkspace = _workspace;
|
auto oldWorkspace = _workspace;
|
||||||
|
|
||||||
// Update parent data model and workspace, if applicable
|
// Update parent data model and workspace, if applicable
|
||||||
if (GetParent() != nullptr) {
|
if (GetParent()) {
|
||||||
this->_dataModel = GetParent()->GetClass() == &DataModel::TYPE ? std::dynamic_pointer_cast<DataModel>(GetParent()) : GetParent()->_dataModel;
|
this->_dataModel = GetParent().value()->GetClass() == &DataModel::TYPE ? std::dynamic_pointer_cast<DataModel>(GetParent().value()) : GetParent().value()->_dataModel;
|
||||||
this->_workspace = GetParent()->GetClass() == &Workspace::TYPE ? std::dynamic_pointer_cast<Workspace>(GetParent()) : GetParent()->_workspace;
|
this->_workspace = GetParent().value()->GetClass() == &Workspace::TYPE ? std::dynamic_pointer_cast<Workspace>(GetParent().value()) : GetParent().value()->_workspace;
|
||||||
} else {
|
} else {
|
||||||
this->_dataModel = {};
|
this->_dataModel = {};
|
||||||
this->_workspace = {};
|
this->_workspace = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
OnAncestryChanged(updatedChild, newParent);
|
OnAncestryChanged(updatedChild, newParent);
|
||||||
AncestryChanged->Fire({updatedChild != nullptr ? InstanceRef(updatedChild) : InstanceRef(), newParent != nullptr ? InstanceRef(newParent) : InstanceRef()});
|
AncestryChanged->Fire({updatedChild.has_value() ? InstanceRef(updatedChild.value()) : InstanceRef(), newParent.has_value() ? InstanceRef(newParent.value()) : InstanceRef()});
|
||||||
|
|
||||||
// Old workspace used to exist, and workspaces differ
|
// Old workspace used to exist, and workspaces differ
|
||||||
if (!oldWorkspace.expired() && oldWorkspace != _workspace) {
|
if (!oldWorkspace.expired() && oldWorkspace != _workspace) {
|
||||||
|
@ -103,7 +108,7 @@ void Instance::updateAncestry(nullable std::shared_ptr<Instance> updatedChild, n
|
||||||
|
|
||||||
// New workspace exists, and workspaces differ
|
// New workspace exists, and workspaces differ
|
||||||
if (!_workspace.expired() && (_workspace != oldWorkspace)) {
|
if (!_workspace.expired() && (_workspace != oldWorkspace)) {
|
||||||
OnWorkspaceAdded(oldWorkspace.expired() ? nullptr : oldWorkspace.lock(), _workspace.lock());
|
OnWorkspaceAdded(!oldWorkspace.expired() ? std::make_optional(oldWorkspace.lock()) : std::nullopt, _workspace.lock());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update ancestry in descendants
|
// Update ancestry in descendants
|
||||||
|
@ -112,22 +117,23 @@ void Instance::updateAncestry(nullable std::shared_ptr<Instance> updatedChild, n
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nullable std::shared_ptr<DataModel> Instance::dataModel() {
|
std::optional<std::shared_ptr<DataModel>> Instance::dataModel() {
|
||||||
return _dataModel.expired() ? nullptr : _dataModel.lock();
|
return (_dataModel.expired()) ? std::nullopt : std::make_optional(_dataModel.lock());
|
||||||
}
|
}
|
||||||
|
|
||||||
nullable std::shared_ptr<Workspace> Instance::workspace() {
|
std::optional<std::shared_ptr<Workspace>> Instance::workspace() {
|
||||||
return _workspace.expired() ? nullptr : _workspace.lock();
|
return (_workspace.expired()) ? std::nullopt : std::make_optional(_workspace.lock());
|
||||||
}
|
}
|
||||||
|
|
||||||
nullable std::shared_ptr<Instance> Instance::GetParent() {
|
std::optional<std::shared_ptr<Instance>> Instance::GetParent() {
|
||||||
return parent.expired() ? nullptr : parent.lock();
|
if (parent.expired()) return std::nullopt;
|
||||||
|
return parent.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::Destroy() {
|
void Instance::Destroy() {
|
||||||
if (parentLocked) return;
|
if (parentLocked) return;
|
||||||
// TODO: Implement proper distruction stuff
|
// TODO: Implement proper distruction stuff
|
||||||
SetParent(nullptr);
|
SetParent(std::nullopt);
|
||||||
parentLocked = true;
|
parentLocked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,12 +143,12 @@ bool Instance::IsA(std::string className) {
|
||||||
return cur != nullptr;
|
return cur != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
nullable std::shared_ptr<Instance> Instance::FindFirstChild(std::string name) {
|
std::optional<std::shared_ptr<Instance>> Instance::FindFirstChild(std::string name) {
|
||||||
for (auto child : children) {
|
for (auto child : children) {
|
||||||
if (child->name == name)
|
if (child->name == name)
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::shared_ptr<Instance> DUMMY_INSTANCE;
|
static std::shared_ptr<Instance> DUMMY_INSTANCE;
|
||||||
|
@ -158,15 +164,15 @@ bool Instance::IsParentLocked() {
|
||||||
return this->parentLocked;
|
return this->parentLocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::OnParentUpdated(nullable std::shared_ptr<Instance> oldParent, nullable std::shared_ptr<Instance> newParent) {
|
void Instance::OnParentUpdated(std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent) {
|
||||||
// Empty stub
|
// Empty stub
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::OnAncestryChanged(nullable std::shared_ptr<Instance> child, nullable std::shared_ptr<Instance> newParent) {
|
void Instance::OnAncestryChanged(std::optional<std::shared_ptr<Instance>> child, std::optional<std::shared_ptr<Instance>> newParent) {
|
||||||
// Empty stub
|
// Empty stub
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::OnWorkspaceAdded(nullable std::shared_ptr<Workspace> oldWorkspace, std::shared_ptr<Workspace> newWorkspace) {
|
void Instance::OnWorkspaceAdded(std::optional<std::shared_ptr<Workspace>> oldWorkspace, std::shared_ptr<Workspace> newWorkspace) {
|
||||||
// Empty stub
|
// Empty stub
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,7 +230,7 @@ fallible<MemberNotFound, AssignToReadOnlyMember> Instance::InternalSetPropertyVa
|
||||||
this->name = (std::string)value.get<std::string>();
|
this->name = (std::string)value.get<std::string>();
|
||||||
} else if (name == "Parent") {
|
} else if (name == "Parent") {
|
||||||
std::weak_ptr<Instance> ref = value.get<InstanceRef>();
|
std::weak_ptr<Instance> ref = value.get<InstanceRef>();
|
||||||
SetParent(ref.expired() ? nullptr : ref.lock());
|
SetParent(ref.expired() ? std::nullopt : std::make_optional(ref.lock()));
|
||||||
} else if (name == "ClassName") {
|
} else if (name == "ClassName") {
|
||||||
return AssignToReadOnlyMember(GetClass()->className, name);
|
return AssignToReadOnlyMember(GetClass()->className, name);
|
||||||
} else {
|
} else {
|
||||||
|
@ -424,9 +430,9 @@ DescendantsIterator::self_type DescendantsIterator::operator++(int _) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we've hit the end of this item's children, move one up
|
// If we've hit the end of this item's children, move one up
|
||||||
while (current->GetParent() != nullptr && current->GetParent()->GetChildren().size() <= size_t(siblingIndex.back() + 1)) {
|
while (current->GetParent() && current->GetParent().value()->GetChildren().size() <= size_t(siblingIndex.back() + 1)) {
|
||||||
siblingIndex.pop_back();
|
siblingIndex.pop_back();
|
||||||
current = current->GetParent();
|
current = current->GetParent().value();
|
||||||
|
|
||||||
// But not if one up is null or the root element
|
// But not if one up is null or the root element
|
||||||
if (!current->GetParent() || current == root) {
|
if (!current->GetParent() || current == root) {
|
||||||
|
@ -437,12 +443,12 @@ DescendantsIterator::self_type DescendantsIterator::operator++(int _) {
|
||||||
|
|
||||||
// Now move to the next sibling
|
// Now move to the next sibling
|
||||||
siblingIndex.back()++;
|
siblingIndex.back()++;
|
||||||
current = current->GetParent()->GetChildren()[siblingIndex.back()];
|
current = current->GetParent().value()->GetChildren()[siblingIndex.back()];
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
nullable std::shared_ptr<Instance> Instance::Clone(RefStateClone state) {
|
std::optional<std::shared_ptr<Instance>> Instance::Clone(RefStateClone state) {
|
||||||
if (state == nullptr) state = std::make_shared<__RefStateClone>();
|
if (state == nullptr) state = std::make_shared<__RefStateClone>();
|
||||||
std::shared_ptr<Instance> newInstance = GetClass()->constructor();
|
std::shared_ptr<Instance> newInstance = GetClass()->constructor();
|
||||||
|
|
||||||
|
@ -488,9 +494,9 @@ nullable std::shared_ptr<Instance> Instance::Clone(RefStateClone state) {
|
||||||
|
|
||||||
// Clone children
|
// Clone children
|
||||||
for (std::shared_ptr<Instance> child : GetChildren()) {
|
for (std::shared_ptr<Instance> child : GetChildren()) {
|
||||||
nullable std::shared_ptr<Instance> clonedChild = child->Clone(state);
|
std::optional<std::shared_ptr<Instance>> clonedChild = child->Clone(state);
|
||||||
if (clonedChild)
|
if (clonedChild)
|
||||||
newInstance->AddChild(clonedChild);
|
newInstance->AddChild(clonedChild.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
return newInstance;
|
return newInstance;
|
||||||
|
@ -515,12 +521,12 @@ std::vector<std::pair<std::string, std::shared_ptr<Instance>>> Instance::GetRefe
|
||||||
|
|
||||||
std::string Instance::GetFullName() {
|
std::string Instance::GetFullName() {
|
||||||
std::string currentName = name;
|
std::string currentName = name;
|
||||||
nullable std::shared_ptr<Instance> currentParent = GetParent();
|
std::optional<std::shared_ptr<Instance>> currentParent = GetParent();
|
||||||
|
|
||||||
while (currentParent && !currentParent->IsA("DataModel")) {
|
while (currentParent.has_value() && !currentParent.value()->IsA("DataModel")) {
|
||||||
currentName = currentParent->name + "." + currentName;
|
currentName = currentParent.value()->name + "." + currentName;
|
||||||
|
|
||||||
currentParent = currentParent->GetParent();
|
currentParent = currentParent.value()->GetParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
return currentName;
|
return currentName;
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
#include "error/result.h"
|
#include "error/result.h"
|
||||||
#include "member.h"
|
#include "member.h"
|
||||||
#include "objects/base/refstate.h"
|
#include "objects/base/refstate.h"
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
class Instance;
|
class Instance;
|
||||||
typedef std::shared_ptr<Instance>(*InstanceConstructor)();
|
typedef std::shared_ptr<Instance>(*InstanceConstructor)();
|
||||||
|
@ -60,8 +59,8 @@ private:
|
||||||
std::weak_ptr<DataModel> _dataModel;
|
std::weak_ptr<DataModel> _dataModel;
|
||||||
std::weak_ptr<Workspace> _workspace;
|
std::weak_ptr<Workspace> _workspace;
|
||||||
|
|
||||||
bool ancestryContinuityCheck(nullable std::shared_ptr<Instance> newParent);
|
bool ancestryContinuityCheck(std::optional<std::shared_ptr<Instance>> newParent);
|
||||||
void updateAncestry(nullable std::shared_ptr<Instance> child, nullable std::shared_ptr<Instance> newParent);
|
void updateAncestry(std::optional<std::shared_ptr<Instance>> child, std::optional<std::shared_ptr<Instance>> newParent);
|
||||||
|
|
||||||
friend JointInstance; // This isn't ideal, but oh well
|
friend JointInstance; // This isn't ideal, but oh well
|
||||||
protected:
|
protected:
|
||||||
|
@ -76,17 +75,17 @@ protected:
|
||||||
virtual void InternalUpdateProperty(std::string name);
|
virtual void InternalUpdateProperty(std::string name);
|
||||||
virtual std::vector<std::string> InternalGetProperties();
|
virtual std::vector<std::string> InternalGetProperties();
|
||||||
|
|
||||||
virtual void OnParentUpdated(nullable std::shared_ptr<Instance> oldParent, nullable std::shared_ptr<Instance> newParent);
|
virtual void OnParentUpdated(std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent);
|
||||||
virtual void OnAncestryChanged(nullable std::shared_ptr<Instance> child, nullable std::shared_ptr<Instance> newParent);
|
virtual void OnAncestryChanged(std::optional<std::shared_ptr<Instance>> child, std::optional<std::shared_ptr<Instance>> newParent);
|
||||||
virtual void OnWorkspaceAdded(nullable std::shared_ptr<Workspace> oldWorkspace, std::shared_ptr<Workspace> newWorkspace);
|
virtual void OnWorkspaceAdded(std::optional<std::shared_ptr<Workspace>> oldWorkspace, std::shared_ptr<Workspace> newWorkspace);
|
||||||
virtual void OnWorkspaceRemoved(std::shared_ptr<Workspace> oldWorkspace);
|
virtual void OnWorkspaceRemoved(std::shared_ptr<Workspace> oldWorkspace);
|
||||||
|
|
||||||
// The root data model this object is a descendant of
|
// The root data model this object is a descendant of
|
||||||
nullable std::shared_ptr<DataModel> dataModel();
|
std::optional<std::shared_ptr<DataModel>> dataModel();
|
||||||
// The root workspace this object is a descendant of
|
// The root workspace this object is a descendant of
|
||||||
// NOTE: This value is not necessarily present if dataModel is present
|
// NOTE: This value is not necessarily present if dataModel is present
|
||||||
// Objects under services other than workspace will NOT have this field set
|
// Objects under services other than workspace will NOT have this field set
|
||||||
nullable std::shared_ptr<Workspace> workspace();
|
std::optional<std::shared_ptr<Workspace>> workspace();
|
||||||
public:
|
public:
|
||||||
const static InstanceType TYPE;
|
const static InstanceType TYPE;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
@ -97,8 +96,8 @@ public:
|
||||||
// Instance is abstract, so it should not implement GetClass directly
|
// Instance is abstract, so it should not implement GetClass directly
|
||||||
virtual const InstanceType* GetClass() = 0;
|
virtual const InstanceType* GetClass() = 0;
|
||||||
static void PushLuaLibrary(lua_State*); // Defined in lua/instancelib.cpp
|
static void PushLuaLibrary(lua_State*); // Defined in lua/instancelib.cpp
|
||||||
bool SetParent(nullable std::shared_ptr<Instance> newParent);
|
bool SetParent(std::optional<std::shared_ptr<Instance>> newParent);
|
||||||
nullable std::shared_ptr<Instance> GetParent();
|
std::optional<std::shared_ptr<Instance>> GetParent();
|
||||||
bool IsParentLocked();
|
bool IsParentLocked();
|
||||||
inline const std::vector<std::shared_ptr<Instance>> GetChildren() { return children; }
|
inline const std::vector<std::shared_ptr<Instance>> GetChildren() { return children; }
|
||||||
void Destroy();
|
void Destroy();
|
||||||
|
@ -112,7 +111,7 @@ public:
|
||||||
DescendantsIterator GetDescendantsEnd();
|
DescendantsIterator GetDescendantsEnd();
|
||||||
// Utility functions
|
// Utility functions
|
||||||
inline void AddChild(std::shared_ptr<Instance> object) { object->SetParent(this->shared_from_this()); }
|
inline void AddChild(std::shared_ptr<Instance> object) { object->SetParent(this->shared_from_this()); }
|
||||||
nullable std::shared_ptr<Instance> FindFirstChild(std::string);
|
std::optional<std::shared_ptr<Instance>> FindFirstChild(std::string);
|
||||||
std::string GetFullName();
|
std::string GetFullName();
|
||||||
|
|
||||||
// Properties
|
// Properties
|
||||||
|
@ -137,7 +136,7 @@ public:
|
||||||
// Serialization
|
// Serialization
|
||||||
void Serialize(pugi::xml_node parent, RefStateSerialize state = {});
|
void Serialize(pugi::xml_node parent, RefStateSerialize state = {});
|
||||||
static result<std::shared_ptr<Instance>, NoSuchInstance> Deserialize(pugi::xml_node node, RefStateDeserialize state = {});
|
static result<std::shared_ptr<Instance>, NoSuchInstance> Deserialize(pugi::xml_node node, RefStateDeserialize state = {});
|
||||||
nullable std::shared_ptr<Instance> Clone(RefStateClone state = {});
|
std::optional<std::shared_ptr<Instance>> Clone(RefStateClone state = {});
|
||||||
};
|
};
|
||||||
|
|
||||||
// https://gist.github.com/jeetsukumaran/307264
|
// https://gist.github.com/jeetsukumaran/307264
|
||||||
|
@ -159,7 +158,7 @@ public:
|
||||||
|
|
||||||
self_type operator++(int _);
|
self_type operator++(int _);
|
||||||
private:
|
private:
|
||||||
nullable std::shared_ptr<Instance> root;
|
std::optional<std::shared_ptr<Instance>> root;
|
||||||
std::shared_ptr<Instance> current;
|
std::shared_ptr<Instance> current;
|
||||||
std::vector<int> siblingIndex;
|
std::vector<int> siblingIndex;
|
||||||
};
|
};
|
|
@ -7,9 +7,9 @@
|
||||||
Service::Service(const InstanceType* type) : Instance(type){}
|
Service::Service(const InstanceType* type) : Instance(type){}
|
||||||
|
|
||||||
// Fail if parented to non-datamodel, otherwise lock parent
|
// Fail if parented to non-datamodel, otherwise lock parent
|
||||||
void Service::OnParentUpdated(nullable std::shared_ptr<Instance> oldParent, nullable std::shared_ptr<Instance> newParent) {
|
void Service::OnParentUpdated(std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent) {
|
||||||
if (!newParent || newParent->GetClass() != &DataModel::TYPE) {
|
if (!newParent || newParent.value()->GetClass() != &DataModel::TYPE) {
|
||||||
Logger::fatalErrorf("Service %s was parented to object of type %s", GetClass()->className.c_str(), newParent ? newParent->GetClass()->className.c_str() : "NULL");
|
Logger::fatalErrorf("Service %s was parented to object of type %s", GetClass()->className.c_str(), newParent ? newParent.value()->GetClass()->className.c_str() : "NULL");
|
||||||
panic();
|
panic();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ protected:
|
||||||
virtual void InitService();
|
virtual void InitService();
|
||||||
virtual void OnRun();
|
virtual void OnRun();
|
||||||
|
|
||||||
void OnParentUpdated(nullable std::shared_ptr<Instance> oldParent, nullable std::shared_ptr<Instance> newParent) override;
|
void OnParentUpdated(std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent) override;
|
||||||
|
|
||||||
friend class DataModel;
|
friend class DataModel;
|
||||||
};
|
};
|
|
@ -20,12 +20,6 @@ DataModel::DataModel()
|
||||||
this->name = "Place";
|
this->name = "Place";
|
||||||
}
|
}
|
||||||
|
|
||||||
DataModel::~DataModel() {
|
|
||||||
#ifndef NDEBUG
|
|
||||||
printf("Datamodel successfully destroyed\n");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataModel::Init(bool runMode) {
|
void DataModel::Init(bool runMode) {
|
||||||
// Create default services
|
// Create default services
|
||||||
GetService<Workspace>();
|
GetService<Workspace>();
|
||||||
|
@ -113,14 +107,14 @@ result<std::shared_ptr<Service>, NoSuchService> DataModel::GetService(std::strin
|
||||||
return std::dynamic_pointer_cast<Service>(services[className]);
|
return std::dynamic_pointer_cast<Service>(services[className]);
|
||||||
}
|
}
|
||||||
|
|
||||||
result<nullable std::shared_ptr<Service>, NoSuchService> DataModel::FindService(std::string className) {
|
result<std::optional<std::shared_ptr<Service>>, NoSuchService> DataModel::FindService(std::string className) {
|
||||||
if (!INSTANCE_MAP[className] || (INSTANCE_MAP[className]->flags ^ (INSTANCE_NOTCREATABLE | INSTANCE_SERVICE)) != 0) {
|
if (!INSTANCE_MAP[className] || (INSTANCE_MAP[className]->flags ^ (INSTANCE_NOTCREATABLE | INSTANCE_SERVICE)) != 0) {
|
||||||
return NoSuchService(className);
|
return NoSuchService(className);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (services.count(className) != 0)
|
if (services.count(className) != 0)
|
||||||
return std::dynamic_pointer_cast<Service>(services[className]);
|
return std::make_optional(std::dynamic_pointer_cast<Service>(services[className]));
|
||||||
return nullptr;
|
return (std::optional<std::shared_ptr<Service>>)std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<DataModel> DataModel::CloneModel() {
|
std::shared_ptr<DataModel> DataModel::CloneModel() {
|
||||||
|
@ -172,11 +166,11 @@ std::shared_ptr<DataModel> DataModel::CloneModel() {
|
||||||
if (!result)
|
if (!result)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
newModel->AddChild(result);
|
newModel->AddChild(result.value());
|
||||||
|
|
||||||
// Special case: Ignore instances parented to DataModel which are not services
|
// Special case: Ignore instances parented to DataModel which are not services
|
||||||
if (child->GetClass()->flags & INSTANCE_SERVICE) {
|
if (child->GetClass()->flags & INSTANCE_SERVICE) {
|
||||||
newModel->services[child->GetClass()->className] = std::dynamic_pointer_cast<Service>(result);
|
newModel->services[child->GetClass()->className] = std::dynamic_pointer_cast<Service>(result.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,13 +24,12 @@ public:
|
||||||
std::optional<std::string> currentFile;
|
std::optional<std::string> currentFile;
|
||||||
|
|
||||||
DataModel();
|
DataModel();
|
||||||
~DataModel();
|
|
||||||
void Init(bool runMode = false);
|
void Init(bool runMode = false);
|
||||||
|
|
||||||
static inline std::shared_ptr<DataModel> New() { return std::make_shared<DataModel>(); };
|
static inline std::shared_ptr<DataModel> New() { return std::make_shared<DataModel>(); };
|
||||||
|
|
||||||
result<std::shared_ptr<Service>, NoSuchService> GetService(std::string className);
|
result<std::shared_ptr<Service>, NoSuchService> GetService(std::string className);
|
||||||
result<nullable std::shared_ptr<Service>, NoSuchService> FindService(std::string className);
|
result<std::optional<std::shared_ptr<Service>>, NoSuchService> FindService(std::string className);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::shared_ptr<T> GetService() {
|
std::shared_ptr<T> GetService() {
|
||||||
|
@ -39,10 +38,10 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
nullable std::shared_ptr<T> FindService() {
|
std::optional<std::shared_ptr<T>> FindService() {
|
||||||
auto result = FindService(T::TYPE.className).expect("FindService<T>() was called with a non-service instance type");
|
auto result = FindService(T::TYPE.className).expect("FindService<T>() was called with a non-service instance type");
|
||||||
if (!result) return nullptr;
|
if (!result) return std::nullopt;
|
||||||
return std::dynamic_pointer_cast<T>(result);
|
return std::dynamic_pointer_cast<T>(result.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Saving/loading
|
// Saving/loading
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
#include "hint.h"
|
|
||||||
|
|
||||||
Hint::Hint(): Message(&TYPE) {}
|
|
||||||
Hint::~Hint() = default;
|
|
|
@ -1,18 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "objects/annotation.h"
|
|
||||||
#include "objects/base/instance.h"
|
|
||||||
#include "objects/message.h"
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
// Dims the player's screen and displays some centered text
|
|
||||||
class DEF_INST_(explorer_icon="message") Hint : public Message {
|
|
||||||
AUTOGEN_PREAMBLE
|
|
||||||
|
|
||||||
public:
|
|
||||||
Hint();
|
|
||||||
~Hint();
|
|
||||||
|
|
||||||
static inline std::shared_ptr<Hint> New() { return std::make_shared<Hint>(); };
|
|
||||||
static inline std::shared_ptr<Instance> Create() { return std::make_shared<Hint>(); };
|
|
||||||
};
|
|
|
@ -1,11 +1,15 @@
|
||||||
#include "jointinstance.h"
|
#include "jointinstance.h"
|
||||||
|
|
||||||
|
#include "datatypes/cframe.h"
|
||||||
#include "datatypes/ref.h"
|
#include "datatypes/ref.h"
|
||||||
#include "objects/datamodel.h"
|
#include "objects/datamodel.h"
|
||||||
#include "objects/service/jointsservice.h"
|
#include "objects/service/jointsservice.h"
|
||||||
#include "objects/part/basepart.h"
|
#include "objects/part.h"
|
||||||
#include "objects/service/workspace.h"
|
#include "objects/service/workspace.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <reactphysics3d/constraint/FixedJoint.h>
|
||||||
|
#include <reactphysics3d/engine/PhysicsWorld.h>
|
||||||
|
#include "ptr_helpers.h"
|
||||||
|
|
||||||
JointInstance::JointInstance(const InstanceType* type): Instance(type) {
|
JointInstance::JointInstance(const InstanceType* type): Instance(type) {
|
||||||
}
|
}
|
||||||
|
@ -13,49 +17,43 @@ JointInstance::JointInstance(const InstanceType* type): Instance(type) {
|
||||||
JointInstance::~JointInstance() {
|
JointInstance::~JointInstance() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void JointInstance::OnAncestryChanged(nullable std::shared_ptr<Instance>, nullable std::shared_ptr<Instance>) {
|
void JointInstance::OnAncestryChanged(std::optional<std::shared_ptr<Instance>>, std::optional<std::shared_ptr<Instance>>) {
|
||||||
Update();
|
// Destroy and rebuild the joint, it's the simplest solution that actually works
|
||||||
|
|
||||||
|
breakJoint();
|
||||||
|
buildJoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JointInstance::OnPartParamsUpdated() {
|
void JointInstance::onUpdated(std::string property) {
|
||||||
}
|
// Add ourselves to the attached parts, or remove, if applicable
|
||||||
|
|
||||||
void JointInstance::Update() {
|
// Parts differ, delete
|
||||||
// To keep it simple compared to our previous algorithm, this one is pretty barebones:
|
if (part0 != oldPart0 && !oldPart0.expired()) {
|
||||||
// 1. Every time we update, (whether our parent changed, or a property), destroy the current joints
|
|
||||||
// 2. If the new configuration is valid, rebuild our joints
|
|
||||||
|
|
||||||
if (!jointWorkspace.expired()) {
|
|
||||||
jointWorkspace.lock()->DestroyJoint(joint);
|
|
||||||
if (!oldPart0.expired())
|
|
||||||
oldPart0.lock()->untrackJoint(shared<JointInstance>());
|
oldPart0.lock()->untrackJoint(shared<JointInstance>());
|
||||||
if (!oldPart1.expired())
|
}
|
||||||
|
|
||||||
|
if (part1 != oldPart1 && !oldPart1.expired()) {
|
||||||
oldPart1.lock()->untrackJoint(shared<JointInstance>());
|
oldPart1.lock()->untrackJoint(shared<JointInstance>());
|
||||||
}
|
}
|
||||||
|
|
||||||
oldPart0 = part0;
|
// Parts differ, add
|
||||||
oldPart1 = part1;
|
if (part0 != oldPart0 && !part0.expired()) {
|
||||||
|
|
||||||
// Don't build the joint if we're not part of either a workspace or JointsService
|
|
||||||
if ((!GetParent() || GetParent()->GetClass() != &JointsService::TYPE) && !workspace()) return;
|
|
||||||
|
|
||||||
// If either part is invalid or they are part of separate worlds, fail
|
|
||||||
if (part0.expired()
|
|
||||||
|| part1.expired()
|
|
||||||
|| !workspaceOfPart(part0.lock())
|
|
||||||
|| !workspaceOfPart(part1.lock())
|
|
||||||
|| workspaceOfPart(part0.lock()) != workspaceOfPart(part1.lock())
|
|
||||||
) return;
|
|
||||||
|
|
||||||
// TODO: Add joint continuity check here
|
|
||||||
|
|
||||||
// Finally, build the joint
|
|
||||||
buildJoint();
|
|
||||||
|
|
||||||
part0.lock()->trackJoint(shared<JointInstance>());
|
part0.lock()->trackJoint(shared<JointInstance>());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (part1 != oldPart1 && !part1.expired()) {
|
||||||
part1.lock()->trackJoint(shared<JointInstance>());
|
part1.lock()->trackJoint(shared<JointInstance>());
|
||||||
}
|
}
|
||||||
|
|
||||||
nullable std::shared_ptr<Workspace> JointInstance::workspaceOfPart(std::shared_ptr<BasePart> part) {
|
// Destroy and rebuild the joint, if applicable
|
||||||
|
|
||||||
|
breakJoint();
|
||||||
|
buildJoint();
|
||||||
|
|
||||||
|
oldPart0 = part0;
|
||||||
|
oldPart1 = part1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::shared_ptr<Workspace>> JointInstance::workspaceOfPart(std::shared_ptr<Part> part) {
|
||||||
return part->workspace();
|
return part->workspace();
|
||||||
}
|
}
|
|
@ -3,46 +3,39 @@
|
||||||
#include "objects/base/instance.h"
|
#include "objects/base/instance.h"
|
||||||
#include "../annotation.h"
|
#include "../annotation.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include "datatypes/cframe.h"
|
#include "datatypes/cframe.h"
|
||||||
#include "physics/world.h"
|
|
||||||
|
|
||||||
//this is necessary ebcause we use std::weak_ptr<Part> without including it in this file
|
//this is necessary ebcause we use std::weak_ptr<Part> without including it in this file
|
||||||
#ifdef __AUTOGEN_EXTRA_INCLUDES__
|
#ifdef __AUTOGEN_EXTRA_INCLUDES__
|
||||||
#include "objects/part/part.h"
|
#include "../part.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DEF_PROP_PHYS DEF_PROP_(on_update=onUpdated)
|
class Part;
|
||||||
|
|
||||||
class BasePart;
|
|
||||||
class Workspace;
|
class Workspace;
|
||||||
|
|
||||||
class DEF_INST_ABSTRACT JointInstance : public Instance {
|
class DEF_INST_ABSTRACT JointInstance : public Instance {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
|
|
||||||
std::weak_ptr<BasePart> oldPart0;
|
std::weak_ptr<Part> oldPart0;
|
||||||
std::weak_ptr<BasePart> oldPart1;
|
std::weak_ptr<Part> oldPart1;
|
||||||
protected:
|
protected:
|
||||||
// The workspace the joint was created in, if it exists
|
// The workspace the joint was created in, if it exists
|
||||||
std::weak_ptr<Workspace> jointWorkspace;
|
std::weak_ptr<Workspace> jointWorkspace;
|
||||||
PhysJoint joint;
|
|
||||||
|
|
||||||
void OnAncestryChanged(nullable std::shared_ptr<Instance>, nullable std::shared_ptr<Instance>) override;
|
void OnAncestryChanged(std::optional<std::shared_ptr<Instance>>, std::optional<std::shared_ptr<Instance>>) override;
|
||||||
|
|
||||||
nullable std::shared_ptr<Workspace> workspaceOfPart(std::shared_ptr<BasePart>);
|
|
||||||
inline void onUpdated(std::string property) { Update(); };
|
|
||||||
|
|
||||||
|
std::optional<std::shared_ptr<Workspace>> workspaceOfPart(std::shared_ptr<Part>);
|
||||||
|
void onUpdated(std::string property);
|
||||||
virtual void buildJoint() = 0;
|
virtual void buildJoint() = 0;
|
||||||
|
virtual void breakJoint() = 0;
|
||||||
public:
|
public:
|
||||||
void Update();
|
|
||||||
virtual void OnPartParamsUpdated();
|
|
||||||
|
|
||||||
DEF_PROP_PHYS std::weak_ptr<BasePart> part0;
|
DEF_PROP_(on_update=onUpdated) std::weak_ptr<Part> part0;
|
||||||
DEF_PROP_PHYS std::weak_ptr<BasePart> part1;
|
DEF_PROP_(on_update=onUpdated) std::weak_ptr<Part> part1;
|
||||||
DEF_PROP_PHYS CFrame c0;
|
DEF_PROP_(on_update=onUpdated) CFrame c0;
|
||||||
DEF_PROP_PHYS CFrame c1;
|
DEF_PROP_(on_update=onUpdated) CFrame c1;
|
||||||
|
|
||||||
JointInstance(const InstanceType*);
|
JointInstance(const InstanceType*);
|
||||||
~JointInstance();
|
~JointInstance();
|
||||||
};
|
};
|
||||||
|
|
||||||
#undef DEF_PROP_PHYS
|
|
|
@ -1,8 +1,9 @@
|
||||||
#include "rotate.h"
|
#include "rotate.h"
|
||||||
#include "objects/service/jointsservice.h"
|
#include "objects/service/jointsservice.h"
|
||||||
#include "objects/part/part.h"
|
#include "objects/part.h"
|
||||||
#include "objects/service/workspace.h"
|
#include "objects/service/workspace.h"
|
||||||
#include "rendering/renderer.h"
|
#include "rendering/renderer.h"
|
||||||
|
#include <reactphysics3d/constraint/HingeJoint.h>
|
||||||
|
|
||||||
Rotate::Rotate(): JointInstance(&TYPE) {
|
Rotate::Rotate(): JointInstance(&TYPE) {
|
||||||
}
|
}
|
||||||
|
@ -12,15 +13,35 @@ Rotate::~Rotate() {
|
||||||
static CFrame XYZToZXY(glm::vec3(0, 0, 0), -glm::vec3(1, 0, 0), glm::vec3(0, 0, 1));
|
static CFrame XYZToZXY(glm::vec3(0, 0, 0), -glm::vec3(1, 0, 0), glm::vec3(0, 0, 1));
|
||||||
|
|
||||||
void Rotate::buildJoint() {
|
void Rotate::buildJoint() {
|
||||||
std::shared_ptr<Workspace> workspace = workspaceOfPart(part0.lock());
|
// Only if both parts are set, are not the same part, are part of a workspace, and are part of the same workspace, we build the joint
|
||||||
|
if (part0.expired() || part1.expired() || part0.lock() == part1.lock() || !workspaceOfPart(part0.lock()) || workspaceOfPart(part0.lock()) != workspaceOfPart(part1.lock())) return;
|
||||||
|
|
||||||
|
// Don't build the joint if we're not part of either a workspace or JointsService
|
||||||
|
if ((!GetParent() || GetParent().value()->GetClass() != &JointsService::TYPE) && !workspace()) return;
|
||||||
|
|
||||||
|
std::shared_ptr<Workspace> workspace = workspaceOfPart(part0.lock()).value();
|
||||||
|
|
||||||
// Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it
|
// Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it
|
||||||
// used to be rather than specifying an anchor rotation, so whatever.
|
// used to be rather than specifying an anchor rotation, so whatever.
|
||||||
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
||||||
part1.lock()->cframe = newFrame;
|
part1.lock()->cframe = newFrame;
|
||||||
|
workspace->SyncPartPhysics(part1.lock());
|
||||||
// Do NOT use Abs() in this scenario. For some reason that breaks it
|
// Do NOT use Abs() in this scenario. For some reason that breaks it
|
||||||
PhysRotatingJointInfo jointInfo(c0, c1);
|
rp::HingeJointInfo jointInfo(part0.lock()->rigidBody, part1.lock()->rigidBody, (part0.lock()->cframe * c0).Position(), -(part0.lock()->cframe * c0).LookVector().Unit());
|
||||||
this->joint = workspace->CreateJoint(jointInfo, part0.lock(), part1.lock());
|
this->joint = dynamic_cast<rp::HingeJoint*>(workspace->CreateJoint(jointInfo));
|
||||||
jointWorkspace = workspace;
|
jointWorkspace = workspace;
|
||||||
|
|
||||||
|
// part1.lock()->rigidBody->getCollider(0)->setCollideWithMaskBits(0b10);
|
||||||
|
// part1.lock()->rigidBody->getCollider(0)->setCollisionCategoryBits(0b10);
|
||||||
|
// part0.lock()->rigidBody->getCollider(0)->setCollideWithMaskBits(0b01);
|
||||||
|
// part0.lock()->rigidBody->getCollider(0)->setCollisionCategoryBits(0b01);
|
||||||
|
}
|
||||||
|
|
||||||
|
// !!! REMINDER: This has to be called manually when parts are destroyed/removed from the workspace, or joints will linger
|
||||||
|
void Rotate::breakJoint() {
|
||||||
|
// If the joint doesn't exist, or its workspace expired (not our problem anymore), then no need to do anything
|
||||||
|
if (!this->joint || jointWorkspace.expired()) return;
|
||||||
|
|
||||||
|
jointWorkspace.lock()->DestroyJoint(this->joint);
|
||||||
|
this->joint = nullptr;
|
||||||
}
|
}
|
|
@ -5,10 +5,15 @@
|
||||||
#include "objects/joint/jointinstance.h"
|
#include "objects/joint/jointinstance.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
namespace reactphysics3d { class HingeJoint; }
|
||||||
|
|
||||||
class DEF_INST Rotate : public JointInstance {
|
class DEF_INST Rotate : public JointInstance {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
|
|
||||||
|
reactphysics3d::HingeJoint* joint = nullptr;
|
||||||
|
|
||||||
virtual void buildJoint() override;
|
virtual void buildJoint() override;
|
||||||
|
virtual void breakJoint() override;
|
||||||
public:
|
public:
|
||||||
Rotate();
|
Rotate();
|
||||||
~Rotate();
|
~Rotate();
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
#include "rotatev.h"
|
#include "rotatev.h"
|
||||||
#include "objects/service/jointsservice.h"
|
#include "objects/service/jointsservice.h"
|
||||||
#include "objects/part/part.h"
|
#include "objects/part.h"
|
||||||
#include "objects/service/workspace.h"
|
#include "objects/service/workspace.h"
|
||||||
#include "rendering/renderer.h"
|
#include "rendering/renderer.h"
|
||||||
|
#include <reactphysics3d/constraint/HingeJoint.h>
|
||||||
|
|
||||||
#define PI 3.14159
|
#define PI 3.14159
|
||||||
|
|
||||||
|
@ -14,21 +15,39 @@ RotateV::~RotateV() {
|
||||||
static CFrame XYZToZXY(glm::vec3(0, 0, 0), -glm::vec3(1, 0, 0), glm::vec3(0, 0, 1));
|
static CFrame XYZToZXY(glm::vec3(0, 0, 0), -glm::vec3(1, 0, 0), glm::vec3(0, 0, 1));
|
||||||
|
|
||||||
void RotateV::buildJoint() {
|
void RotateV::buildJoint() {
|
||||||
std::shared_ptr<Workspace> workspace = workspaceOfPart(part0.lock());
|
// Only if both parts are set, are not the same part, are part of a workspace, and are part of the same workspace, we build the joint
|
||||||
|
if (part0.expired() || part1.expired() || part0.lock() == part1.lock() || !workspaceOfPart(part0.lock()) || workspaceOfPart(part0.lock()) != workspaceOfPart(part1.lock())) return;
|
||||||
|
|
||||||
|
// Don't build the joint if we're not part of either a workspace or JointsService
|
||||||
|
if ((!GetParent() || GetParent().value()->GetClass() != &JointsService::TYPE) && !workspace()) return;
|
||||||
|
|
||||||
|
std::shared_ptr<Workspace> workspace = workspaceOfPart(part0.lock()).value();
|
||||||
|
|
||||||
|
|
||||||
// Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it
|
// Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it
|
||||||
// used to be rather than specifying an anchor rotation, so whatever.
|
// used to be rather than specifying an anchor rotation, so whatever.
|
||||||
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
||||||
part1.lock()->cframe = newFrame;
|
part1.lock()->cframe = newFrame;
|
||||||
|
workspace->SyncPartPhysics(part1.lock());
|
||||||
// Do NOT use Abs() in this scenario. For some reason that breaks it
|
// Do NOT use Abs() in this scenario. For some reason that breaks it
|
||||||
float vel = part0.lock()->GetSurfaceParamB(-c0.LookVector().Unit()) * 6.28;
|
rp::HingeJointInfo jointInfo(part0.lock()->rigidBody, part1.lock()->rigidBody, (part0.lock()->cframe * c0).Position(), -(part0.lock()->cframe * c0).LookVector().Unit());
|
||||||
PhysRotatingJointInfo jointInfo(c0, c1, vel);
|
|
||||||
|
|
||||||
this->joint = workspace->CreateJoint(jointInfo, part0.lock(), part1.lock());
|
jointInfo.isCollisionEnabled = false;
|
||||||
|
|
||||||
|
this->joint = dynamic_cast<rp::HingeJoint*>(workspace->CreateJoint(jointInfo));
|
||||||
jointWorkspace = workspace;
|
jointWorkspace = workspace;
|
||||||
|
|
||||||
|
|
||||||
|
// part1.lock()->rigidBody->getCollider(0)->setCollideWithMaskBits(0b10);
|
||||||
|
// part1.lock()->rigidBody->getCollider(0)->setCollisionCategoryBits(0b10);
|
||||||
|
// part0.lock()->rigidBody->getCollider(0)->setCollideWithMaskBits(0b01);
|
||||||
|
// part0.lock()->rigidBody->getCollider(0)->setCollisionCategoryBits(0b01);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RotateV::OnPartParamsUpdated() {
|
void RotateV::breakJoint() {
|
||||||
float vel = part0.lock()->GetSurfaceParamB(-c0.LookVector().Unit()) * 6.28;
|
// If the joint doesn't exist, or its workspace expired (not our problem anymore), then no need to do anything
|
||||||
this->joint.setAngularVelocity(vel);
|
if (!this->joint || jointWorkspace.expired()) return;
|
||||||
|
|
||||||
|
jointWorkspace.lock()->DestroyJoint(this->joint);
|
||||||
|
this->joint = nullptr;
|
||||||
}
|
}
|
|
@ -4,17 +4,19 @@
|
||||||
#include "objects/base/instance.h"
|
#include "objects/base/instance.h"
|
||||||
#include "objects/joint/jointinstance.h"
|
#include "objects/joint/jointinstance.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
namespace reactphysics3d { class HingeJoint; }
|
||||||
|
|
||||||
class DEF_INST RotateV : public JointInstance {
|
class DEF_INST RotateV : public JointInstance {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
|
|
||||||
|
reactphysics3d::HingeJoint* joint = nullptr;
|
||||||
|
|
||||||
virtual void buildJoint() override;
|
virtual void buildJoint() override;
|
||||||
|
virtual void breakJoint() override;
|
||||||
public:
|
public:
|
||||||
RotateV();
|
RotateV();
|
||||||
~RotateV();
|
~RotateV();
|
||||||
|
|
||||||
void OnPartParamsUpdated() override;
|
|
||||||
|
|
||||||
static inline std::shared_ptr<RotateV> New() { return std::make_shared<RotateV>(); };
|
static inline std::shared_ptr<RotateV> New() { return std::make_shared<RotateV>(); };
|
||||||
static inline std::shared_ptr<Instance> Create() { return std::make_shared<RotateV>(); };
|
static inline std::shared_ptr<Instance> Create() { return std::make_shared<RotateV>(); };
|
||||||
};
|
};
|
|
@ -4,10 +4,11 @@
|
||||||
#include "objects/datamodel.h"
|
#include "objects/datamodel.h"
|
||||||
#include "objects/joint/jointinstance.h"
|
#include "objects/joint/jointinstance.h"
|
||||||
#include "objects/service/jointsservice.h"
|
#include "objects/service/jointsservice.h"
|
||||||
#include "objects/part/part.h"
|
#include "objects/part.h"
|
||||||
#include "objects/service/workspace.h"
|
#include "objects/service/workspace.h"
|
||||||
#include "physics/world.h"
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <reactphysics3d/constraint/FixedJoint.h>
|
||||||
|
#include <reactphysics3d/engine/PhysicsWorld.h>
|
||||||
|
|
||||||
Snap::Snap(): JointInstance(&TYPE) {
|
Snap::Snap(): JointInstance(&TYPE) {
|
||||||
}
|
}
|
||||||
|
@ -16,14 +17,30 @@ Snap::~Snap() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Snap::buildJoint() {
|
void Snap::buildJoint() {
|
||||||
std::shared_ptr<Workspace> workspace = workspaceOfPart(part0.lock());
|
// Only if both parts are set, are not the same part, are part of a workspace, and are part of the same workspace, we build the joint
|
||||||
|
if (part0.expired() || part1.expired() || part0.lock() == part1.lock() || !workspaceOfPart(part0.lock()) || workspaceOfPart(part0.lock()) != workspaceOfPart(part1.lock())) return;
|
||||||
|
|
||||||
|
// Don't build the joint if we're not part of either a workspace or JointsService
|
||||||
|
if ((!GetParent() || GetParent().value()->GetClass() != &JointsService::TYPE) && !workspace()) return;
|
||||||
|
|
||||||
|
std::shared_ptr<Workspace> workspace = workspaceOfPart(part0.lock()).value();
|
||||||
|
|
||||||
// Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it
|
// Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it
|
||||||
// used to be rather than specifying an anchor rotation, so whatever.
|
// used to be rather than specifying an anchor rotation, so whatever.
|
||||||
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
||||||
part1.lock()->cframe = newFrame;
|
part1.lock()->cframe = newFrame;
|
||||||
|
workspace->SyncPartPhysics(part1.lock());
|
||||||
|
|
||||||
PhysFixedJointInfo jointInfo(c0, c1);
|
rp::FixedJointInfo jointInfo(part0.lock()->rigidBody, part1.lock()->rigidBody, (c0.Inverse() * c1).Position());
|
||||||
this->joint = workspace->CreateJoint(jointInfo, part0.lock(), part1.lock());
|
this->joint = dynamic_cast<rp::FixedJoint*>(workspace->CreateJoint(jointInfo));
|
||||||
jointWorkspace = workspace;
|
jointWorkspace = workspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// !!! REMINDER: This has to be called manually when parts are destroyed/removed from the workspace, or joints will linger
|
||||||
|
void Snap::breakJoint() {
|
||||||
|
// If the joint doesn't exist, or its workspace expired (not our problem anymore), then no need to do anything
|
||||||
|
if (!this->joint || jointWorkspace.expired()) return;
|
||||||
|
|
||||||
|
jointWorkspace.lock()->DestroyJoint(this->joint);
|
||||||
|
this->joint = nullptr;
|
||||||
|
}
|
|
@ -5,10 +5,15 @@
|
||||||
#include "objects/joint/jointinstance.h"
|
#include "objects/joint/jointinstance.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
namespace reactphysics3d { class FixedJoint; }
|
||||||
|
|
||||||
class DEF_INST Snap : public JointInstance {
|
class DEF_INST Snap : public JointInstance {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
|
|
||||||
|
reactphysics3d::FixedJoint* joint = nullptr;
|
||||||
|
|
||||||
virtual void buildJoint() override;
|
virtual void buildJoint() override;
|
||||||
|
virtual void breakJoint() override;
|
||||||
public:
|
public:
|
||||||
Snap();
|
Snap();
|
||||||
~Snap();
|
~Snap();
|
||||||
|
|
|
@ -4,10 +4,11 @@
|
||||||
#include "objects/datamodel.h"
|
#include "objects/datamodel.h"
|
||||||
#include "objects/joint/jointinstance.h"
|
#include "objects/joint/jointinstance.h"
|
||||||
#include "objects/service/jointsservice.h"
|
#include "objects/service/jointsservice.h"
|
||||||
#include "objects/part/part.h"
|
#include "objects/part.h"
|
||||||
#include "objects/service/workspace.h"
|
#include "objects/service/workspace.h"
|
||||||
#include "physics/world.h"
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <reactphysics3d/constraint/FixedJoint.h>
|
||||||
|
#include <reactphysics3d/engine/PhysicsWorld.h>
|
||||||
|
|
||||||
Weld::Weld(): JointInstance(&TYPE) {
|
Weld::Weld(): JointInstance(&TYPE) {
|
||||||
}
|
}
|
||||||
|
@ -16,14 +17,30 @@ Weld::~Weld() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Weld::buildJoint() {
|
void Weld::buildJoint() {
|
||||||
std::shared_ptr<Workspace> workspace = workspaceOfPart(part0.lock());
|
// Only if both parts are set, are not the same part, are part of a workspace, and are part of the same workspace, we build the joint
|
||||||
|
if (part0.expired() || part1.expired() || part0.lock() == part1.lock() || !workspaceOfPart(part0.lock()) || workspaceOfPart(part0.lock()) != workspaceOfPart(part1.lock())) return;
|
||||||
|
|
||||||
|
// Don't build the joint if we're not part of either a workspace or JointsService
|
||||||
|
if ((!GetParent() || GetParent().value()->GetClass() != &JointsService::TYPE) && !workspace()) return;
|
||||||
|
|
||||||
|
std::shared_ptr<Workspace> workspace = workspaceOfPart(part0.lock()).value();
|
||||||
|
|
||||||
// Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it
|
// Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it
|
||||||
// used to be rather than specifying an anchor rotation, so whatever.
|
// used to be rather than specifying an anchor rotation, so whatever.
|
||||||
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse());
|
||||||
part1.lock()->cframe = newFrame;
|
part1.lock()->cframe = newFrame;
|
||||||
|
workspace->SyncPartPhysics(part1.lock());
|
||||||
|
|
||||||
PhysFixedJointInfo jointInfo(c0, c1);
|
rp::FixedJointInfo jointInfo(part0.lock()->rigidBody, part1.lock()->rigidBody, (c0.Inverse() * c1).Position());
|
||||||
this->joint = workspace->CreateJoint(jointInfo, part0.lock(), part1.lock());
|
this->joint = dynamic_cast<rp::FixedJoint*>(workspace->CreateJoint(jointInfo));
|
||||||
jointWorkspace = workspace;
|
jointWorkspace = workspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// !!! REMINDER: This has to be called manually when parts are destroyed/removed from the workspace, or joints will linger
|
||||||
|
void Weld::breakJoint() {
|
||||||
|
// If the joint doesn't exist, or its workspace expired (not our problem anymore), then no need to do anything
|
||||||
|
if (!this->joint || jointWorkspace.expired()) return;
|
||||||
|
|
||||||
|
jointWorkspace.lock()->DestroyJoint(this->joint);
|
||||||
|
this->joint = nullptr;
|
||||||
|
}
|
|
@ -5,10 +5,15 @@
|
||||||
#include "objects/joint/jointinstance.h"
|
#include "objects/joint/jointinstance.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
namespace reactphysics3d { class FixedJoint; }
|
||||||
|
|
||||||
class DEF_INST Weld : public JointInstance {
|
class DEF_INST Weld : public JointInstance {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
|
|
||||||
|
reactphysics3d::FixedJoint* joint = nullptr;
|
||||||
|
|
||||||
virtual void buildJoint() override;
|
virtual void buildJoint() override;
|
||||||
|
virtual void breakJoint() override;
|
||||||
public:
|
public:
|
||||||
Weld();
|
Weld();
|
||||||
~Weld();
|
~Weld();
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
#include "message.h"
|
|
||||||
|
|
||||||
Message::Message(const InstanceType* type) : Instance(type) {}
|
|
||||||
Message::Message(): Instance(&TYPE) {}
|
|
||||||
Message::~Message() = default;
|
|
|
@ -1,21 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "objects/annotation.h"
|
|
||||||
#include "objects/base/instance.h"
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
// Dims the player's screen and displays some centered text
|
|
||||||
class DEF_INST_(explorer_icon="message") Message : public Instance {
|
|
||||||
AUTOGEN_PREAMBLE
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Message(const InstanceType* type);
|
|
||||||
public:
|
|
||||||
Message();
|
|
||||||
~Message();
|
|
||||||
|
|
||||||
DEF_PROP std::string text;
|
|
||||||
|
|
||||||
static inline std::shared_ptr<Message> New() { return std::make_shared<Message>(); };
|
|
||||||
static inline std::shared_ptr<Instance> Create() { return std::make_shared<Message>(); };
|
|
||||||
};
|
|
|
@ -1,15 +1,12 @@
|
||||||
#include "meta.h"
|
#include "meta.h"
|
||||||
#include "objects/folder.h"
|
#include "objects/folder.h"
|
||||||
#include "objects/hint.h"
|
|
||||||
#include "objects/joint/jointinstance.h"
|
#include "objects/joint/jointinstance.h"
|
||||||
#include "objects/joint/rotate.h"
|
#include "objects/joint/rotate.h"
|
||||||
#include "objects/joint/rotatev.h"
|
#include "objects/joint/rotatev.h"
|
||||||
#include "objects/joint/weld.h"
|
#include "objects/joint/weld.h"
|
||||||
#include "objects/message.h"
|
|
||||||
#include "objects/part/wedgepart.h"
|
|
||||||
#include "objects/service/jointsservice.h"
|
#include "objects/service/jointsservice.h"
|
||||||
#include "objects/model.h"
|
#include "objects/model.h"
|
||||||
#include "objects/part/part.h"
|
#include "objects/part.h"
|
||||||
#include "objects/joint/snap.h"
|
#include "objects/joint/snap.h"
|
||||||
#include "objects/script.h"
|
#include "objects/script.h"
|
||||||
#include "objects/service/script/scriptcontext.h"
|
#include "objects/service/script/scriptcontext.h"
|
||||||
|
@ -22,9 +19,7 @@ std::map<std::string, const InstanceType*> INSTANCE_MAP = {
|
||||||
{ "Instance", &Instance::TYPE },
|
{ "Instance", &Instance::TYPE },
|
||||||
{ "DataModel", &DataModel::TYPE },
|
{ "DataModel", &DataModel::TYPE },
|
||||||
|
|
||||||
{ "BasePart", &BasePart::TYPE },
|
|
||||||
{ "Part", &Part::TYPE },
|
{ "Part", &Part::TYPE },
|
||||||
{ "WedgePart", &WedgePart::TYPE },
|
|
||||||
{ "Snap", &Snap::TYPE },
|
{ "Snap", &Snap::TYPE },
|
||||||
{ "Weld", &Weld::TYPE },
|
{ "Weld", &Weld::TYPE },
|
||||||
{ "Rotate", &Rotate::TYPE },
|
{ "Rotate", &Rotate::TYPE },
|
||||||
|
@ -32,8 +27,6 @@ std::map<std::string, const InstanceType*> INSTANCE_MAP = {
|
||||||
{ "JointInstance", &JointInstance::TYPE },
|
{ "JointInstance", &JointInstance::TYPE },
|
||||||
{ "Script", &Script::TYPE },
|
{ "Script", &Script::TYPE },
|
||||||
{ "Model", &Model::TYPE },
|
{ "Model", &Model::TYPE },
|
||||||
{ "Message", &Message::TYPE },
|
|
||||||
{ "Hint", &Hint::TYPE },
|
|
||||||
// { "Folder", &Folder::TYPE },
|
// { "Folder", &Folder::TYPE },
|
||||||
|
|
||||||
// Services
|
// Services
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include "basepart.h"
|
#include "part.h"
|
||||||
#include "objects/base/instance.h"
|
#include "base/instance.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "datatypes/base.h"
|
#include "datatypes/base.h"
|
||||||
#include "datatypes/cframe.h"
|
#include "datatypes/cframe.h"
|
||||||
|
@ -14,29 +14,34 @@
|
||||||
#include "objects/joint/snap.h"
|
#include "objects/joint/snap.h"
|
||||||
#include "rendering/renderer.h"
|
#include "rendering/renderer.h"
|
||||||
#include "enum/surface.h"
|
#include "enum/surface.h"
|
||||||
|
#include <cstdio>
|
||||||
#include <glm/common.hpp>
|
#include <glm/common.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
BasePart::BasePart(const InstanceType* type): BasePart(type, PartConstructParams { .size = glm::vec3(4, 1.2, 2), .color = Color3(0.639216f, 0.635294f, 0.647059f) }) {
|
Part::Part(): Part(PartConstructParams { .size = glm::vec3(2, 1.2, 4), .color = Color3(0.639216f, 0.635294f, 0.647059f) }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
BasePart::BasePart(const InstanceType* type, PartConstructParams params): PVInstance(type), cframe(CFrame::FromEulerAnglesXYZ((Vector3)params.rotation) + params.position),
|
Part::Part(PartConstructParams params): PVInstance(&TYPE), cframe(CFrame::FromEulerAnglesXYZ((Vector3)params.rotation) + params.position),
|
||||||
size(params.size), color(params.color), anchored(params.anchored), locked(params.locked) {
|
size(params.size), color(params.color), anchored(params.anchored), locked(params.locked) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BasePart::~BasePart() {
|
Part::~Part() {
|
||||||
if (workspace() != nullptr) {
|
// This relies on physicsCommon still existing. Be very careful.
|
||||||
workspace()->RemoveBody(shared<BasePart>());
|
if (this->rigidBody && workspace()) {
|
||||||
|
workspace().value()->DestroyRigidBody(rigidBody);
|
||||||
|
this->rigidBody = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void BasePart::OnAncestryChanged(nullable std::shared_ptr<Instance> child, nullable std::shared_ptr<Instance> newParent) {
|
void Part::OnAncestryChanged(std::optional<std::shared_ptr<Instance>> child, std::optional<std::shared_ptr<Instance>> newParent) {
|
||||||
this->rigidBody.setActive(workspace() != nullptr);
|
if (this->rigidBody)
|
||||||
|
this->rigidBody->setIsActive(workspace().has_value());
|
||||||
|
|
||||||
if (workspace() != nullptr)
|
if (workspace())
|
||||||
workspace()->SyncPartPhysics(std::dynamic_pointer_cast<BasePart>(this->shared_from_this()));
|
workspace().value()->SyncPartPhysics(std::dynamic_pointer_cast<Part>(this->shared_from_this()));
|
||||||
|
|
||||||
// Destroy joints
|
// Destroy joints
|
||||||
if (!workspace()) BreakJoints();
|
if (!workspace()) BreakJoints();
|
||||||
|
@ -44,41 +49,28 @@ void BasePart::OnAncestryChanged(nullable std::shared_ptr<Instance> child, nulla
|
||||||
// TODO: Sleeping bodies that touch this one also need to be updated
|
// TODO: Sleeping bodies that touch this one also need to be updated
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasePart::OnWorkspaceAdded(nullable std::shared_ptr<Workspace> oldWorkspace, std::shared_ptr<Workspace> newWorkspace) {
|
void Part::OnWorkspaceAdded(std::optional<std::shared_ptr<Workspace>> oldWorkspace, std::shared_ptr<Workspace> newWorkspace) {
|
||||||
newWorkspace->AddBody(shared<BasePart>());
|
newWorkspace->AddBody(shared<Part>());
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasePart::OnWorkspaceRemoved(std::shared_ptr<Workspace> oldWorkspace) {
|
void Part::OnWorkspaceRemoved(std::shared_ptr<Workspace> oldWorkspace) {
|
||||||
BreakJoints();
|
if (simulationTicket.has_value())
|
||||||
oldWorkspace->RemoveBody(shared<BasePart>());
|
oldWorkspace->RemoveBody(shared<Part>());
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasePart::onUpdated(std::string property) {
|
void Part::onUpdated(std::string property) {
|
||||||
bool reset = property == "Position" || property == "Rotation" || property == "CFrame" || property == "Size" || property == "Shape";
|
// Reset velocity
|
||||||
|
if (property != "Velocity")
|
||||||
|
velocity = Vector3::ZERO;
|
||||||
|
|
||||||
// Sanitize size
|
if (workspace())
|
||||||
// TODO: Replace this with a validator instead
|
workspace().value()->SyncPartPhysics(std::dynamic_pointer_cast<Part>(this->shared_from_this()));
|
||||||
if (property == "Size") {
|
|
||||||
size = glm::max((glm::vec3)size, glm::vec3(0.1f, 0.1f, 0.1f));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (workspace() != nullptr)
|
|
||||||
workspace()->SyncPartPhysics(std::dynamic_pointer_cast<BasePart>(this->shared_from_this()));
|
|
||||||
|
|
||||||
// When position/rotation/size is manually edited, break all joints, they don't apply anymore
|
// When position/rotation/size is manually edited, break all joints, they don't apply anymore
|
||||||
if (reset)
|
if (property != "Anchored")
|
||||||
BreakJoints();
|
BreakJoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasePart::onParamUpdated(std::string property) {
|
|
||||||
// Send signal to joints to update themselves
|
|
||||||
for (std::weak_ptr<JointInstance> joint : primaryJoints) {
|
|
||||||
if (joint.expired()) continue;
|
|
||||||
|
|
||||||
joint.lock()->OnPartParamsUpdated();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expands provided extents to fit point
|
// Expands provided extents to fit point
|
||||||
static void expandMaxExtents(Vector3* min, Vector3* max, Vector3 point) {
|
static void expandMaxExtents(Vector3* min, Vector3* max, Vector3 point) {
|
||||||
*min = Vector3(glm::min(min->X(), point.X()), glm::min(min->Y(), point.Y()), glm::min(min->Z(), point.Z()));
|
*min = Vector3(glm::min(min->X(), point.X()), glm::min(min->Y(), point.Y()), glm::min(min->Z(), point.Z()));
|
||||||
|
@ -96,7 +88,7 @@ static Vector3 verts[8] {
|
||||||
{1, 1, 1},
|
{1, 1, 1},
|
||||||
};
|
};
|
||||||
|
|
||||||
Vector3 BasePart::GetAABB() {
|
Vector3 Part::GetAABB() {
|
||||||
Vector3 min(0, 0, 0);
|
Vector3 min(0, 0, 0);
|
||||||
Vector3 max(0, 0, 0);
|
Vector3 max(0, 0, 0);
|
||||||
for (Vector3 vert : verts) {
|
for (Vector3 vert : verts) {
|
||||||
|
@ -107,7 +99,7 @@ Vector3 BasePart::GetAABB() {
|
||||||
return (min - max).Abs() / 2;
|
return (min - max).Abs() / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasePart::BreakJoints() {
|
void Part::BreakJoints() {
|
||||||
for (std::weak_ptr<JointInstance> joint : primaryJoints) {
|
for (std::weak_ptr<JointInstance> joint : primaryJoints) {
|
||||||
if (joint.expired()) continue;
|
if (joint.expired()) continue;
|
||||||
joint.lock()->Destroy();
|
joint.lock()->Destroy();
|
||||||
|
@ -128,7 +120,7 @@ static Vector3 FACES[6] = {
|
||||||
{0, 0, -1},
|
{0, 0, -1},
|
||||||
};
|
};
|
||||||
|
|
||||||
SurfaceType BasePart::surfaceFromFace(NormalId face) {
|
SurfaceType Part::surfaceFromFace(NormalId face) {
|
||||||
switch (face) {
|
switch (face) {
|
||||||
case Top: return topSurface;
|
case Top: return topSurface;
|
||||||
case Bottom: return bottomSurface;
|
case Bottom: return bottomSurface;
|
||||||
|
@ -140,7 +132,7 @@ SurfaceType BasePart::surfaceFromFace(NormalId face) {
|
||||||
return SurfaceType::Smooth; // Unreachable
|
return SurfaceType::Smooth; // Unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
float BasePart::GetSurfaceParamA(Vector3 face) {
|
float Part::GetSurfaceParamA(Vector3 face) {
|
||||||
switch (faceFromNormal(face)) {
|
switch (faceFromNormal(face)) {
|
||||||
case Top: return topParamA;
|
case Top: return topParamA;
|
||||||
case Bottom: return bottomParamA;
|
case Bottom: return bottomParamA;
|
||||||
|
@ -152,7 +144,7 @@ float BasePart::GetSurfaceParamA(Vector3 face) {
|
||||||
return 0; // Unreachable
|
return 0; // Unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
float BasePart::GetSurfaceParamB(Vector3 face) {
|
float Part::GetSurfaceParamB(Vector3 face) {
|
||||||
switch (faceFromNormal(face)) {
|
switch (faceFromNormal(face)) {
|
||||||
case Top: return topParamB;
|
case Top: return topParamB;
|
||||||
case Bottom: return bottomParamB;
|
case Bottom: return bottomParamB;
|
||||||
|
@ -164,18 +156,14 @@ float BasePart::GetSurfaceParamB(Vector3 face) {
|
||||||
return 0; // Unreachable
|
return 0; // Unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 BasePart::GetEffectiveSize() {
|
bool Part::checkJointContinuity(std::shared_ptr<Part> otherPart) {
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BasePart::checkJointContinuity(std::shared_ptr<BasePart> otherPart) {
|
|
||||||
// Make sure that the two parts don't depend on one another
|
// Make sure that the two parts don't depend on one another
|
||||||
|
|
||||||
return checkJointContinuityUp(otherPart) && checkJointContinuityDown(otherPart);
|
return checkJointContinuityUp(otherPart) && checkJointContinuityDown(otherPart);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BasePart::checkJointContinuityDown(std::shared_ptr<BasePart> otherPart) {
|
bool Part::checkJointContinuityDown(std::shared_ptr<Part> otherPart) {
|
||||||
if (shared<BasePart>() == otherPart) return false;
|
if (shared<Part>() == otherPart) return false;
|
||||||
for (auto joint : primaryJoints) {
|
for (auto joint : primaryJoints) {
|
||||||
if (joint.expired() || joint.lock()->part1.expired()) continue;
|
if (joint.expired() || joint.lock()->part1.expired()) continue;
|
||||||
if (!joint.lock()->part1.lock()->checkJointContinuityDown(otherPart))
|
if (!joint.lock()->part1.lock()->checkJointContinuityDown(otherPart))
|
||||||
|
@ -184,8 +172,8 @@ bool BasePart::checkJointContinuityDown(std::shared_ptr<BasePart> otherPart) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BasePart::checkJointContinuityUp(std::shared_ptr<BasePart> otherPart) {
|
bool Part::checkJointContinuityUp(std::shared_ptr<Part> otherPart) {
|
||||||
if (shared<BasePart>() == otherPart) return false;
|
if (shared<Part>() == otherPart) return false;
|
||||||
for (auto joint : secondaryJoints) {
|
for (auto joint : secondaryJoints) {
|
||||||
if (joint.expired() || joint.lock()->part0.expired()) continue;
|
if (joint.expired() || joint.lock()->part0.expired()) continue;
|
||||||
if (!joint.lock()->part0.lock()->checkJointContinuityUp(otherPart))
|
if (!joint.lock()->part0.lock()->checkJointContinuityUp(otherPart))
|
||||||
|
@ -194,7 +182,7 @@ bool BasePart::checkJointContinuityUp(std::shared_ptr<BasePart> otherPart) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BasePart::checkSurfacesTouching(CFrame surfaceFrame, Vector3 size, Vector3 myFace, Vector3 otherFace, std::shared_ptr<BasePart> otherPart) {
|
bool Part::checkSurfacesTouching(CFrame surfaceFrame, Vector3 size, Vector3 myFace, Vector3 otherFace, std::shared_ptr<Part> otherPart) {
|
||||||
Vector3 farCorner0 = surfaceFrame.Inverse() * otherPart->cframe * (Vector3::ONE * (otherPart->size / 2.f));
|
Vector3 farCorner0 = surfaceFrame.Inverse() * otherPart->cframe * (Vector3::ONE * (otherPart->size / 2.f));
|
||||||
Vector3 farCorner1 = surfaceFrame.Inverse() * otherPart->cframe * (-Vector3::ONE * (otherPart->size / 2.f));
|
Vector3 farCorner1 = surfaceFrame.Inverse() * otherPart->cframe * (-Vector3::ONE * (otherPart->size / 2.f));
|
||||||
|
|
||||||
|
@ -217,7 +205,7 @@ bool BasePart::checkSurfacesTouching(CFrame surfaceFrame, Vector3 size, Vector3
|
||||||
return horizOverlap && vertOverlap;
|
return horizOverlap && vertOverlap;
|
||||||
}
|
}
|
||||||
|
|
||||||
nullable std::shared_ptr<JointInstance> makeJointFromSurfaces(SurfaceType a, SurfaceType b) {
|
std::optional<std::shared_ptr<JointInstance>> makeJointFromSurfaces(SurfaceType a, SurfaceType b) {
|
||||||
if (a == SurfaceType::Weld || b == SurfaceType::Weld || a == SurfaceType::Glue || b == SurfaceType::Glue) return Weld::New();
|
if (a == SurfaceType::Weld || b == SurfaceType::Weld || a == SurfaceType::Glue || b == SurfaceType::Glue) return Weld::New();
|
||||||
if ((a == SurfaceType::Studs && (b == SurfaceType::Inlet || b == SurfaceType::Universal))
|
if ((a == SurfaceType::Studs && (b == SurfaceType::Inlet || b == SurfaceType::Universal))
|
||||||
|| (a == SurfaceType::Inlet && (b == SurfaceType::Studs || b == SurfaceType::Universal))
|
|| (a == SurfaceType::Inlet && (b == SurfaceType::Studs || b == SurfaceType::Universal))
|
||||||
|
@ -227,10 +215,10 @@ nullable std::shared_ptr<JointInstance> makeJointFromSurfaces(SurfaceType a, Sur
|
||||||
return Rotate::New();
|
return Rotate::New();
|
||||||
if (a == SurfaceType::Motor)
|
if (a == SurfaceType::Motor)
|
||||||
return RotateV::New();
|
return RotateV::New();
|
||||||
return nullptr;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasePart::MakeJoints() {
|
void Part::MakeJoints() {
|
||||||
// Algorithm: Find nearby parts
|
// Algorithm: Find nearby parts
|
||||||
// Make sure parts are not dependant on each other (via primary/secondaryJoints)
|
// Make sure parts are not dependant on each other (via primary/secondaryJoints)
|
||||||
// Find matching surfaces (surface normal dot product < -0.999)
|
// Find matching surfaces (surface normal dot product < -0.999)
|
||||||
|
@ -242,11 +230,11 @@ void BasePart::MakeJoints() {
|
||||||
|
|
||||||
// TEMPORARY
|
// TEMPORARY
|
||||||
// TODO: Use more efficient algorithm to *actually* find nearby parts)
|
// TODO: Use more efficient algorithm to *actually* find nearby parts)
|
||||||
for (auto it = workspace()->GetDescendantsStart(); it != workspace()->GetDescendantsEnd(); it++) {
|
for (auto it = workspace().value()->GetDescendantsStart(); it != workspace().value()->GetDescendantsEnd(); it++) {
|
||||||
std::shared_ptr<Instance> obj = *it;
|
std::shared_ptr<Instance> obj = *it;
|
||||||
if (obj == shared_from_this()) continue; // Skip ourselves
|
if (obj == shared_from_this()) continue; // Skip ourselves
|
||||||
if (!obj->IsA<BasePart>()) continue;
|
if (obj->GetClass()->className != "Part") continue; // TODO: Replace this with a .IsA call instead of comparing the class name directly
|
||||||
std::shared_ptr<BasePart> otherPart = obj->CastTo<BasePart>().expect();
|
std::shared_ptr<Part> otherPart = obj->CastTo<Part>().expect();
|
||||||
|
|
||||||
for (Vector3 myFace : FACES) {
|
for (Vector3 myFace : FACES) {
|
||||||
Vector3 myWorldNormal = cframe.Rotation() * myFace;
|
Vector3 myWorldNormal = cframe.Rotation() * myFace;
|
||||||
|
@ -289,23 +277,21 @@ void BasePart::MakeJoints() {
|
||||||
|
|
||||||
auto joint_ = makeJointFromSurfaces(mySurface, otherSurface);
|
auto joint_ = makeJointFromSurfaces(mySurface, otherSurface);
|
||||||
if (!joint_) continue;
|
if (!joint_) continue;
|
||||||
std::shared_ptr<JointInstance> joint = joint_;
|
std::shared_ptr<JointInstance> joint = joint_.value();
|
||||||
joint->part0 = shared<BasePart>();
|
joint->part0 = shared<Part>();
|
||||||
joint->part1 = otherPart->shared<BasePart>();
|
joint->part1 = otherPart->shared<Part>();
|
||||||
joint->c0 = contact0;
|
joint->c0 = contact0;
|
||||||
joint->c1 = contact1;
|
joint->c1 = contact1;
|
||||||
// // If both parts touch directly, this can cause friction in Rotate and RotateV joints, so we leave a little extra space
|
dataModel().value()->GetService<JointsService>()->AddChild(joint);
|
||||||
// if (joint->IsA("Rotate") || joint->IsA("RotateV"))
|
|
||||||
// joint->c1 = joint->c1 + joint->c1.LookVector() * 0.02f,
|
|
||||||
// joint->c0 = joint->c0 - joint->c0.LookVector() * 0.02f;
|
|
||||||
dataModel()->GetService<JointsService>()->AddChild(joint);
|
|
||||||
joint->UpdateProperty("Part0");
|
joint->UpdateProperty("Part0");
|
||||||
|
|
||||||
|
Logger::debugf("Made joint between %s and %s!\n", name.c_str(), otherPart->name.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasePart::trackJoint(std::shared_ptr<JointInstance> joint) {
|
void Part::trackJoint(std::shared_ptr<JointInstance> joint) {
|
||||||
if (!joint->part0.expired() && joint->part0.lock() == shared_from_this()) {
|
if (!joint->part0.expired() && joint->part0.lock() == shared_from_this()) {
|
||||||
for (auto it = primaryJoints.begin(); it != primaryJoints.end();) {
|
for (auto it = primaryJoints.begin(); it != primaryJoints.end();) {
|
||||||
// Clean expired refs
|
// Clean expired refs
|
||||||
|
@ -339,7 +325,7 @@ void BasePart::trackJoint(std::shared_ptr<JointInstance> joint) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasePart::untrackJoint(std::shared_ptr<JointInstance> joint) {
|
void Part::untrackJoint(std::shared_ptr<JointInstance> joint) {
|
||||||
for (auto it = primaryJoints.begin(); it != primaryJoints.end();) {
|
for (auto it = primaryJoints.begin(); it != primaryJoints.end();) {
|
||||||
// Clean expired refs
|
// Clean expired refs
|
||||||
if (it->expired() || it->lock() == joint) {
|
if (it->expired() || it->lock() == joint) {
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/ext.hpp>
|
#include <glm/ext.hpp>
|
||||||
|
@ -9,14 +10,14 @@
|
||||||
#include "datatypes/vector.h"
|
#include "datatypes/vector.h"
|
||||||
#include "objects/base/instance.h"
|
#include "objects/base/instance.h"
|
||||||
#include "enum/surface.h"
|
#include "enum/surface.h"
|
||||||
|
#include <mutex>
|
||||||
|
#include <optional>
|
||||||
|
#include <reactphysics3d/reactphysics3d.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "objects/annotation.h"
|
#include "annotation.h"
|
||||||
#include "objects/pvinstance.h"
|
#include "objects/pvinstance.h"
|
||||||
#include "physics/world.h"
|
|
||||||
|
|
||||||
// Common macro for part properties
|
namespace rp = reactphysics3d;
|
||||||
#define DEF_PROP_PHYS DEF_PROP_(on_update=onUpdated)
|
|
||||||
#define DEF_PROP_PHYSPARAM DEF_PROP_(on_update=onParamUpdated)
|
|
||||||
|
|
||||||
// For easy construction from C++. Maybe should be removed?
|
// For easy construction from C++. Maybe should be removed?
|
||||||
struct PartConstructParams {
|
struct PartConstructParams {
|
||||||
|
@ -29,9 +30,15 @@ struct PartConstructParams {
|
||||||
bool locked = false;
|
bool locked = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PhysWorld;
|
class Workspace;
|
||||||
|
|
||||||
class DEF_INST_ABSTRACT_(explorer_icon="part") BasePart : public PVInstance {
|
#ifndef __SIMULATION_TICKET
|
||||||
|
#define __SIMULATION_TICKET
|
||||||
|
class Part;
|
||||||
|
typedef std::list<std::shared_ptr<Part>>::iterator SimulationTicket;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class DEF_INST_(explorer_icon="part") Part : public PVInstance {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
protected:
|
protected:
|
||||||
// Joints where this part is Part0
|
// Joints where this part is Part0
|
||||||
|
@ -43,41 +50,36 @@ protected:
|
||||||
void untrackJoint(std::shared_ptr<JointInstance>);
|
void untrackJoint(std::shared_ptr<JointInstance>);
|
||||||
|
|
||||||
SurfaceType surfaceFromFace(NormalId);
|
SurfaceType surfaceFromFace(NormalId);
|
||||||
bool checkJointContinuity(std::shared_ptr<BasePart>);
|
bool checkJointContinuity(std::shared_ptr<Part>);
|
||||||
bool checkJointContinuityUp(std::shared_ptr<BasePart>);
|
bool checkJointContinuityUp(std::shared_ptr<Part>);
|
||||||
bool checkJointContinuityDown(std::shared_ptr<BasePart>);
|
bool checkJointContinuityDown(std::shared_ptr<Part>);
|
||||||
bool checkSurfacesTouching(CFrame surfaceFrame, Vector3 size, Vector3 myFace, Vector3 otherFace, std::shared_ptr<BasePart> otherPart);
|
bool checkSurfacesTouching(CFrame surfaceFrame, Vector3 size, Vector3 myFace, Vector3 otherFace, std::shared_ptr<Part> otherPart);
|
||||||
|
|
||||||
friend JointInstance;
|
friend JointInstance;
|
||||||
friend PhysWorld;
|
friend Workspace;
|
||||||
|
|
||||||
virtual void OnWorkspaceAdded(nullable std::shared_ptr<Workspace> oldWorkspace, std::shared_ptr<Workspace> newWorkspace) override;
|
virtual void OnWorkspaceAdded(std::optional<std::shared_ptr<Workspace>> oldWorkspace, std::shared_ptr<Workspace> newWorkspace) override;
|
||||||
virtual void OnWorkspaceRemoved(std::shared_ptr<Workspace> oldWorkspace) override;
|
virtual void OnWorkspaceRemoved(std::shared_ptr<Workspace> oldWorkspace) override;
|
||||||
void OnAncestryChanged(nullable std::shared_ptr<Instance> child, nullable std::shared_ptr<Instance> newParent) override;
|
void OnAncestryChanged(std::optional<std::shared_ptr<Instance>> child, std::optional<std::shared_ptr<Instance>> newParent) override;
|
||||||
void onUpdated(std::string);
|
void onUpdated(std::string);
|
||||||
void onParamUpdated(std::string);
|
|
||||||
|
|
||||||
BasePart(const InstanceType*);
|
|
||||||
BasePart(const InstanceType*, PartConstructParams params);
|
|
||||||
public:
|
public:
|
||||||
DEF_PROP_CATEGORY(DATA)
|
DEF_PROP_CATEGORY(DATA)
|
||||||
DEF_PROP_PHYS Vector3 velocity;
|
DEF_PROP_(on_update=onUpdated) Vector3 velocity;
|
||||||
[[ def_prop(name="CFrame", on_update=onUpdated), cframe_position_prop(name="Position"), cframe_rotation_prop(name="Rotation") ]]
|
[[ def_prop(name="CFrame", on_update=onUpdated), cframe_position_prop(name="Position"), cframe_rotation_prop(name="Rotation") ]]
|
||||||
CFrame cframe;
|
CFrame cframe;
|
||||||
|
|
||||||
DEF_PROP_CATEGORY(PART)
|
DEF_PROP_CATEGORY(PART)
|
||||||
// Special compatibility changes for this property were made in
|
// Special compatibility changes for this property were made in
|
||||||
// Instance::Serialize
|
// Instance::Serialize
|
||||||
DEF_PROP_PHYS Vector3 size;
|
DEF_PROP_(on_update=onUpdated) Vector3 size;
|
||||||
|
|
||||||
DEF_PROP_CATEGORY(APPEARANCE)
|
DEF_PROP_CATEGORY(APPEARANCE)
|
||||||
DEF_PROP Color3 color;
|
DEF_PROP Color3 color;
|
||||||
DEF_PROP float transparency = 0.f;
|
DEF_PROP float transparency = 0.f;
|
||||||
DEF_PROP float reflectance = 0.f;
|
|
||||||
|
|
||||||
DEF_PROP_CATEGORY(BEHAVIOR)
|
DEF_PROP_CATEGORY(BEHAVIOR)
|
||||||
DEF_PROP_PHYS bool anchored = false;
|
DEF_PROP_(on_update=onUpdated) bool anchored = false;
|
||||||
DEF_PROP_PHYS bool canCollide = true;
|
DEF_PROP_(on_update=onUpdated) bool canCollide = true;
|
||||||
DEF_PROP bool locked = false;
|
DEF_PROP bool locked = false;
|
||||||
|
|
||||||
DEF_PROP_CATEGORY(SURFACE)
|
DEF_PROP_CATEGORY(SURFACE)
|
||||||
|
@ -89,31 +91,38 @@ public:
|
||||||
DEF_PROP SurfaceType backSurface = SurfaceType::Smooth;
|
DEF_PROP SurfaceType backSurface = SurfaceType::Smooth;
|
||||||
|
|
||||||
DEF_PROP_CATEGORY(SURFACE_INPUT)
|
DEF_PROP_CATEGORY(SURFACE_INPUT)
|
||||||
DEF_PROP_PHYSPARAM float topParamA = -0.5;
|
DEF_PROP float topParamA = -0.5;
|
||||||
DEF_PROP_PHYSPARAM float bottomParamA = -0.5;
|
DEF_PROP float bottomParamA = -0.5;
|
||||||
DEF_PROP_PHYSPARAM float leftParamA = -0.5;
|
DEF_PROP float leftParamA = -0.5;
|
||||||
DEF_PROP_PHYSPARAM float rightParamA = -0.5;
|
DEF_PROP float rightParamA = -0.5;
|
||||||
DEF_PROP_PHYSPARAM float frontParamA = -0.5;
|
DEF_PROP float frontParamA = -0.5;
|
||||||
DEF_PROP_PHYSPARAM float backParamA = -0.5;
|
DEF_PROP float backParamA = -0.5;
|
||||||
|
|
||||||
DEF_PROP_PHYSPARAM float topParamB = 0.5;
|
DEF_PROP float topParamB = 0.5;
|
||||||
DEF_PROP_PHYSPARAM float bottomParamB = 0.5;
|
DEF_PROP float bottomParamB = 0.5;
|
||||||
DEF_PROP_PHYSPARAM float leftParamB = 0.5;
|
DEF_PROP float leftParamB = 0.5;
|
||||||
DEF_PROP_PHYSPARAM float rightParamB = 0.5;
|
DEF_PROP float rightParamB = 0.5;
|
||||||
DEF_PROP_PHYSPARAM float frontParamB = 0.5;
|
DEF_PROP float frontParamB = 0.5;
|
||||||
DEF_PROP_PHYSPARAM float backParamB = 0.5;
|
DEF_PROP float backParamB = 0.5;
|
||||||
|
|
||||||
DEF_SIGNAL SignalSource Touched;
|
DEF_SIGNAL SignalSource Touched;
|
||||||
DEF_SIGNAL SignalSource TouchEnded;
|
DEF_SIGNAL SignalSource TouchEnded;
|
||||||
|
|
||||||
PhysRigidBody rigidBody;
|
rp::RigidBody* rigidBody = nullptr;
|
||||||
|
std::optional<SimulationTicket> simulationTicket;
|
||||||
|
bool rigidBodyDirty = true;
|
||||||
|
|
||||||
inline SurfaceType GetSurfaceFromFace(NormalId face) { return surfaceFromFace(face); }
|
inline SurfaceType GetSurfaceFromFace(NormalId face) { return surfaceFromFace(face); }
|
||||||
float GetSurfaceParamA(Vector3 face);
|
float GetSurfaceParamA(Vector3 face);
|
||||||
float GetSurfaceParamB(Vector3 face);
|
float GetSurfaceParamB(Vector3 face);
|
||||||
virtual Vector3 GetEffectiveSize();
|
|
||||||
|
|
||||||
~BasePart() override;
|
Part();
|
||||||
|
Part(PartConstructParams params);
|
||||||
|
~Part() override;
|
||||||
|
|
||||||
|
static inline std::shared_ptr<Part> New() { return std::make_shared<Part>(); };
|
||||||
|
static inline std::shared_ptr<Part> New(PartConstructParams params) { return std::make_shared<Part>(params); };
|
||||||
|
static inline std::shared_ptr<Instance> Create() { return std::make_shared<Part>(); };
|
||||||
|
|
||||||
inline Vector3 position() { return cframe.Position(); }
|
inline Vector3 position() { return cframe.Position(); }
|
||||||
|
|
||||||
|
@ -123,6 +132,3 @@ public:
|
||||||
// Calculate size of axis-aligned bounding box
|
// Calculate size of axis-aligned bounding box
|
||||||
Vector3 GetAABB();
|
Vector3 GetAABB();
|
||||||
};
|
};
|
||||||
|
|
||||||
#undef DEF_PROP_PHYS
|
|
||||||
#undef DEF_PROP_PHYSPARAM
|
|
|
@ -1,22 +0,0 @@
|
||||||
#include "part.h"
|
|
||||||
#include "enum/part.h"
|
|
||||||
#include <glm/common.hpp>
|
|
||||||
|
|
||||||
Part::Part(): BasePart(&TYPE) {
|
|
||||||
}
|
|
||||||
|
|
||||||
Part::Part(PartConstructParams params): BasePart(&TYPE, params) {
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector3 Part::GetEffectiveSize() {
|
|
||||||
float diameter;
|
|
||||||
switch (shape) {
|
|
||||||
case PartType::Ball:
|
|
||||||
return (Vector3)glm::vec3(glm::min(size.X(), size.Y(), size.Z()));
|
|
||||||
case PartType::Cylinder:
|
|
||||||
diameter = glm::min(size.Y(), size.Z());
|
|
||||||
return Vector3(size.X(), diameter, diameter);
|
|
||||||
default:
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "basepart.h"
|
|
||||||
#include "enum/part.h"
|
|
||||||
#include "objects/annotation.h"
|
|
||||||
|
|
||||||
class DEF_INST Part : public BasePart {
|
|
||||||
AUTOGEN_PREAMBLE
|
|
||||||
protected:
|
|
||||||
|
|
||||||
public:
|
|
||||||
Part();
|
|
||||||
Part(PartConstructParams params);
|
|
||||||
|
|
||||||
DEF_PROP_(on_update=onUpdated) PartType shape = PartType::Block;
|
|
||||||
|
|
||||||
Vector3 GetEffectiveSize() override;
|
|
||||||
|
|
||||||
static inline std::shared_ptr<Part> New() { return std::make_shared<Part>(); };
|
|
||||||
static inline std::shared_ptr<Part> New(PartConstructParams params) { return std::make_shared<Part>(params); };
|
|
||||||
static inline std::shared_ptr<Instance> Create() { return std::make_shared<Part>(); };
|
|
||||||
};
|
|
|
@ -1,6 +0,0 @@
|
||||||
#include "wedgepart.h"
|
|
||||||
|
|
||||||
WedgePart::WedgePart(): BasePart(&TYPE) {
|
|
||||||
}
|
|
||||||
|
|
||||||
WedgePart::WedgePart(PartConstructParams params): BasePart(&TYPE, params) {}
|
|
|
@ -1,16 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "basepart.h"
|
|
||||||
#include "objects/annotation.h"
|
|
||||||
|
|
||||||
class DEF_INST WedgePart : public BasePart {
|
|
||||||
AUTOGEN_PREAMBLE
|
|
||||||
|
|
||||||
public:
|
|
||||||
WedgePart();
|
|
||||||
WedgePart(PartConstructParams params);
|
|
||||||
|
|
||||||
static inline std::shared_ptr<WedgePart> New() { return std::make_shared<WedgePart>(); };
|
|
||||||
static inline std::shared_ptr<WedgePart> New(PartConstructParams params) { return std::make_shared<WedgePart>(params); };
|
|
||||||
static inline std::shared_ptr<Instance> Create() { return std::make_shared<WedgePart>(); };
|
|
||||||
};
|
|
|
@ -1,6 +1,5 @@
|
||||||
#include "script.h"
|
#include "script.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "datatypes/variant.h"
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "objects/base/instance.h"
|
#include "objects/base/instance.h"
|
||||||
|
@ -13,8 +12,13 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
int script_wait(lua_State*);
|
||||||
|
int script_delay(lua_State*);
|
||||||
int script_errhandler(lua_State*);
|
int script_errhandler(lua_State*);
|
||||||
|
|
||||||
|
// TODO: Move this to a shared header
|
||||||
|
const char* WRAPPER_SRC = "local func, errhandler = ... return function(...) local args = {...} xpcall(function() func(unpack(args)) end, errhandler) end";
|
||||||
|
|
||||||
Script::Script(): Instance(&TYPE) {
|
Script::Script(): Instance(&TYPE) {
|
||||||
source = "print(\"Hello, world!\")";
|
source = "print(\"Hello, world!\")";
|
||||||
}
|
}
|
||||||
|
@ -23,7 +27,7 @@ Script::~Script() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Script::Run() {
|
void Script::Run() {
|
||||||
std::shared_ptr<ScriptContext> scriptContext = dataModel()->GetService<ScriptContext>();
|
std::shared_ptr<ScriptContext> scriptContext = dataModel().value()->GetService<ScriptContext>();
|
||||||
|
|
||||||
lua_State* L = scriptContext->state;
|
lua_State* L = scriptContext->state;
|
||||||
int top = lua_gettop(L);
|
int top = lua_gettop(L);
|
||||||
|
@ -32,8 +36,30 @@ void Script::Run() {
|
||||||
this->thread = lua_newthread(L);
|
this->thread = lua_newthread(L);
|
||||||
lua_State* Lt = thread;
|
lua_State* Lt = thread;
|
||||||
|
|
||||||
|
// Initialize script globals
|
||||||
|
lua_getglobal(Lt, "_G");
|
||||||
|
|
||||||
|
InstanceRef(shared_from_this()).PushLuaValue(Lt);
|
||||||
|
lua_setfield(Lt, -2, "script");
|
||||||
|
|
||||||
|
InstanceRef(dataModel().value()).PushLuaValue(Lt);
|
||||||
|
lua_setfield(Lt, -2, "game");
|
||||||
|
|
||||||
|
InstanceRef(dataModel().value()->GetService<Workspace>()).PushLuaValue(Lt);
|
||||||
|
lua_setfield(Lt, -2, "workspace");
|
||||||
|
|
||||||
|
lua_pushlightuserdata(Lt, scriptContext.get());
|
||||||
|
lua_pushcclosure(Lt, script_wait, 1);
|
||||||
|
lua_setfield(Lt, -2, "wait");
|
||||||
|
|
||||||
|
lua_pushlightuserdata(Lt, scriptContext.get());
|
||||||
|
lua_pushcclosure(Lt, script_delay, 1);
|
||||||
|
lua_setfield(Lt, -2, "delay");
|
||||||
|
|
||||||
|
lua_pop(Lt, 1); // _G
|
||||||
|
|
||||||
// Push wrapper as thread function
|
// Push wrapper as thread function
|
||||||
lua_getfield(Lt, LUA_REGISTRYINDEX, "LuaPCallWrapper");
|
luaL_loadbuffer(Lt, WRAPPER_SRC, strlen(WRAPPER_SRC), "=PCALL_WRAPPER");
|
||||||
|
|
||||||
// Load source code and push onto thread as upvalue for wrapper
|
// Load source code and push onto thread as upvalue for wrapper
|
||||||
int status = luaL_loadbuffer(Lt, source.c_str(), source.size(), this->GetFullName().c_str());
|
int status = luaL_loadbuffer(Lt, source.c_str(), source.size(), this->GetFullName().c_str());
|
||||||
|
@ -45,21 +71,6 @@ void Script::Run() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize script globals
|
|
||||||
scriptContext->NewEnvironment(Lt); // Pushes envtable, metatable
|
|
||||||
|
|
||||||
// Set script in metatable source
|
|
||||||
InstanceRef(shared_from_this()).PushLuaValue(Lt);
|
|
||||||
lua_setfield(Lt, -2, "source");
|
|
||||||
|
|
||||||
lua_pop(Lt, 1); // Pop metatable
|
|
||||||
|
|
||||||
// Set script in environment
|
|
||||||
InstanceRef(shared_from_this()).PushLuaValue(Lt);
|
|
||||||
lua_setfield(Lt, -2, "script");
|
|
||||||
|
|
||||||
lua_setfenv(Lt, -2); // Set env of loaded function
|
|
||||||
|
|
||||||
// Push our error handler and then generate the wrapped function
|
// Push our error handler and then generate the wrapped function
|
||||||
lua_pushcfunction(Lt, script_errhandler);
|
lua_pushcfunction(Lt, script_errhandler);
|
||||||
lua_call(Lt, 2, 1);
|
lua_call(Lt, 2, 1);
|
||||||
|
@ -75,32 +86,33 @@ void Script::Stop() {
|
||||||
// TODO:
|
// TODO:
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::shared_ptr<Script> getfsource(lua_State* L, lua_Debug* dbg) {
|
int script_wait(lua_State* L) {
|
||||||
int top = lua_gettop(L);
|
ScriptContext* scriptContext = (ScriptContext*)lua_touserdata(L, lua_upvalueindex(1));
|
||||||
|
float secs = lua_gettop(L) == 0 ? 0.03 : std::max(luaL_checknumber(L, 1), 0.03);
|
||||||
|
if (lua_gettop(L) > 0) lua_pop(L, 1); // pop secs
|
||||||
|
|
||||||
lua_getinfo(L, "f", dbg);
|
scriptContext->PushThreadSleep(L, secs);
|
||||||
lua_getfenv(L, -1); // Get fenv of stack pos
|
|
||||||
if (lua_isnil(L, -1)) { // No env could be found
|
// Yield
|
||||||
lua_settop(L, top);
|
return lua_yield(L, 0);
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get source from metatable
|
int script_delay(lua_State* L) {
|
||||||
lua_getmetatable(L, -1);
|
ScriptContext* scriptContext = (ScriptContext*)lua_touserdata(L, lua_upvalueindex(1));
|
||||||
lua_getfield(L, -1, "source");
|
float secs = std::max(luaL_checknumber(L, 1), 0.03);
|
||||||
|
luaL_checktype(L, 2, LUA_TFUNCTION);
|
||||||
|
|
||||||
auto result = InstanceRef::FromLuaValue(L, -1);
|
lua_State* Lt = lua_newthread(L); // Create a new thread
|
||||||
if (!result) {
|
// I think this is memory abuse??
|
||||||
lua_settop(L, top);
|
// Wouldn't popping the thread in this case make it eligible for garbage collection?
|
||||||
return nullptr;
|
lua_pop(L, 1); // pop the newly created thread so that xmove moves func instead of it into itself
|
||||||
}
|
lua_xmove(L, Lt, 1); // move func
|
||||||
|
lua_pop(L, 1); // pop secs
|
||||||
|
|
||||||
lua_settop(L, top);
|
// Schedule next run
|
||||||
|
scriptContext->PushThreadSleep(Lt, secs);
|
||||||
|
|
||||||
std::shared_ptr<Instance> ref = result.expect().get<InstanceRef>();
|
return 0;
|
||||||
if (!ref->IsA<Script>()) return nullptr;
|
|
||||||
|
|
||||||
return ref->CastTo<Script>().expect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int script_errhandler(lua_State* L) {
|
int script_errhandler(lua_State* L) {
|
||||||
|
@ -109,7 +121,7 @@ int script_errhandler(lua_State* L) {
|
||||||
|
|
||||||
// Traceback
|
// Traceback
|
||||||
|
|
||||||
Logger::trace("Stack start");
|
Logger::traceStart();
|
||||||
|
|
||||||
lua_Debug dbg;
|
lua_Debug dbg;
|
||||||
int stack = 1;
|
int stack = 1;
|
||||||
|
@ -119,13 +131,10 @@ int script_errhandler(lua_State* L) {
|
||||||
if (strcmp(dbg.what, "C") == 0 || strcmp(dbg.source, "=PCALL_WRAPPER") == 0)
|
if (strcmp(dbg.what, "C") == 0 || strcmp(dbg.source, "=PCALL_WRAPPER") == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Find script source
|
Logger::trace(dbg.source, dbg.currentline);
|
||||||
std::shared_ptr<Script> source = getfsource(L, &dbg);
|
|
||||||
|
|
||||||
Logger::scriptLogf("'%s', Line %d", Logger::LogLevel::TRACE, {source, dbg.currentline}, dbg.source, dbg.currentline);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::trace("Stack end");
|
Logger::traceEnd();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
|
@ -18,8 +18,8 @@ void JointsService::InitService() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nullable std::shared_ptr<Workspace> JointsService::jointWorkspace() {
|
std::optional<std::shared_ptr<Workspace>> JointsService::jointWorkspace() {
|
||||||
if (!dataModel()) return nullptr;
|
if (!dataModel()) return std::nullopt;
|
||||||
|
|
||||||
return dataModel()->FindService<Workspace>();
|
return dataModel().value()->FindService<Workspace>();
|
||||||
}
|
}
|
|
@ -3,10 +3,10 @@
|
||||||
#include "objects/annotation.h"
|
#include "objects/annotation.h"
|
||||||
#include "objects/base/service.h"
|
#include "objects/base/service.h"
|
||||||
|
|
||||||
class DEF_INST_SERVICE_(hidden) JointsService : public Service {
|
class DEF_INST_SERVICE JointsService : public Service {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
private:
|
private:
|
||||||
nullable std::shared_ptr<Workspace> jointWorkspace();
|
std::optional<std::shared_ptr<Workspace>> jointWorkspace();
|
||||||
protected:
|
protected:
|
||||||
void InitService() override;
|
void InitService() override;
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
|
|
|
@ -1,32 +1,22 @@
|
||||||
#include "scriptcontext.h"
|
#include "scriptcontext.h"
|
||||||
#include "datatypes/cframe.h"
|
#include "datatypes/cframe.h"
|
||||||
#include "datatypes/color3.h"
|
#include "datatypes/color3.h"
|
||||||
#include "datatypes/ref.h"
|
|
||||||
#include "datatypes/vector.h"
|
#include "datatypes/vector.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "objects/datamodel.h"
|
|
||||||
#include "objects/service/workspace.h"
|
|
||||||
#include "timeutil.h"
|
#include "timeutil.h"
|
||||||
#include <chrono>
|
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "luaapis.h" // IWYU pragma: keep
|
#include "luaapis.h" // IWYU pragma: keep
|
||||||
|
|
||||||
const char* WRAPPER_SRC = "local func, errhandler = ... return function(...) local args = {...} xpcall(function() func(unpack(args)) end, errhandler) end";
|
|
||||||
|
|
||||||
int g_wait(lua_State*);
|
|
||||||
int g_delay(lua_State*);
|
|
||||||
int g_tick(lua_State*);
|
|
||||||
static int g_print(lua_State*);
|
static int g_print(lua_State*);
|
||||||
static int g_require(lua_State*);
|
static int g_require(lua_State*);
|
||||||
static const luaL_Reg luaglobals [] = {
|
static const struct luaL_Reg luaglobals [] = {
|
||||||
{"print", g_print},
|
{"print", g_print},
|
||||||
{"require", g_require},
|
{"require", g_require},
|
||||||
{NULL, NULL} /* end of array */
|
{NULL, NULL} /* end of array */
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string unsafe_globals[] = {
|
std::string unsafe_globals[] = {
|
||||||
// Todo implement our own "safe" setfenv/getfenv
|
|
||||||
"loadfile", "loadstring", "load", "dofile", "getfenv", "setfenv"
|
"loadfile", "loadstring", "load", "dofile", "getfenv", "setfenv"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -58,32 +48,6 @@ void ScriptContext::InitService() {
|
||||||
Color3::PushLuaLibrary(state);
|
Color3::PushLuaLibrary(state);
|
||||||
Instance::PushLuaLibrary(state);
|
Instance::PushLuaLibrary(state);
|
||||||
|
|
||||||
// Add other globals
|
|
||||||
lua_getglobal(state, "_G");
|
|
||||||
|
|
||||||
InstanceRef(dataModel()).PushLuaValue(state);
|
|
||||||
lua_setfield(state, -2, "game");
|
|
||||||
|
|
||||||
InstanceRef(dataModel()->GetService<Workspace>()).PushLuaValue(state);
|
|
||||||
lua_setfield(state, -2, "workspace");
|
|
||||||
|
|
||||||
lua_pushlightuserdata(state, this);
|
|
||||||
lua_pushcclosure(state, g_wait, 1);
|
|
||||||
lua_setfield(state, -2, "wait");
|
|
||||||
|
|
||||||
lua_pushlightuserdata(state, this);
|
|
||||||
lua_pushcclosure(state, g_delay, 1);
|
|
||||||
lua_setfield(state, -2, "delay");
|
|
||||||
|
|
||||||
lua_pushcclosure(state, g_tick, 0);
|
|
||||||
lua_setfield(state, -2, "tick");
|
|
||||||
|
|
||||||
lua_pop(state, 1); // _G
|
|
||||||
|
|
||||||
// Add wrapper function
|
|
||||||
luaL_loadbuffer(state, WRAPPER_SRC, strlen(WRAPPER_SRC), "=PCALL_WRAPPER");
|
|
||||||
lua_setfield(state, LUA_REGISTRYINDEX, "LuaPCallWrapper");
|
|
||||||
|
|
||||||
// TODO: custom os library
|
// TODO: custom os library
|
||||||
|
|
||||||
// Override print
|
// Override print
|
||||||
|
@ -167,27 +131,6 @@ void ScriptContext::RunSleepingThreads() {
|
||||||
schedTime = tu_clock_micros() - startTime;
|
schedTime = tu_clock_micros() - startTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptContext::NewEnvironment(lua_State* L) {
|
|
||||||
lua_newtable(L); // Env table
|
|
||||||
lua_newtable(L); // Metatable
|
|
||||||
|
|
||||||
// Push __index
|
|
||||||
lua_pushvalue(L, LUA_GLOBALSINDEX);
|
|
||||||
lua_setfield(L, -2, "__index");
|
|
||||||
|
|
||||||
// Push __metatable
|
|
||||||
lua_pushstring(L, "metatable is locked");
|
|
||||||
lua_setfield(L, -2, "__metatable");
|
|
||||||
|
|
||||||
// Copy metatable and set the env table's metatable
|
|
||||||
lua_pushvalue(L, -1);
|
|
||||||
lua_setmetatable(L, -3);
|
|
||||||
|
|
||||||
// Remainder on stack:
|
|
||||||
// 1. Env table
|
|
||||||
// 2. Metatable
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://www.lua.org/source/5.1/lbaselib.c.html
|
// https://www.lua.org/source/5.1/lbaselib.c.html
|
||||||
static int g_print(lua_State* L) {
|
static int g_print(lua_State* L) {
|
||||||
std::string buf;
|
std::string buf;
|
||||||
|
@ -219,42 +162,3 @@ static int g_require(lua_State* L) {
|
||||||
|
|
||||||
return luaL_error(L, "require is not yet implemented");
|
return luaL_error(L, "require is not yet implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
int g_wait(lua_State* L) {
|
|
||||||
ScriptContext* scriptContext = (ScriptContext*)lua_touserdata(L, lua_upvalueindex(1));
|
|
||||||
float secs = lua_gettop(L) == 0 ? 0.03 : std::max(luaL_checknumber(L, 1), 0.03);
|
|
||||||
if (lua_gettop(L) > 0) lua_pop(L, 1); // pop secs
|
|
||||||
|
|
||||||
scriptContext->PushThreadSleep(L, secs);
|
|
||||||
|
|
||||||
// Yield
|
|
||||||
return lua_yield(L, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int g_delay(lua_State* L) {
|
|
||||||
ScriptContext* scriptContext = (ScriptContext*)lua_touserdata(L, lua_upvalueindex(1));
|
|
||||||
float secs = std::max(luaL_checknumber(L, 1), 0.03);
|
|
||||||
luaL_checktype(L, 2, LUA_TFUNCTION);
|
|
||||||
|
|
||||||
lua_State* Lt = lua_newthread(L); // Create a new thread
|
|
||||||
// I think this is memory abuse??
|
|
||||||
// Wouldn't popping the thread in this case make it eligible for garbage collection?
|
|
||||||
lua_pop(L, 1); // pop the newly created thread so that xmove moves func instead of it into itself
|
|
||||||
lua_xmove(L, Lt, 1); // move func
|
|
||||||
lua_pop(L, 1); // pop secs
|
|
||||||
|
|
||||||
// Schedule next run
|
|
||||||
scriptContext->PushThreadSleep(Lt, secs);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int g_tick(lua_State* L) {
|
|
||||||
std::chrono::time_point now_local = std::chrono::current_zone()->to_local(std::chrono::system_clock::now());
|
|
||||||
std::chrono::microseconds us = std::chrono::duration_cast<std::chrono::microseconds>(now_local.time_since_epoch());
|
|
||||||
uint64_t _10millis = us.count() / 100;
|
|
||||||
double secs = (double)_10millis / 10000;
|
|
||||||
|
|
||||||
lua_pushnumber(L, secs);
|
|
||||||
return 1;
|
|
||||||
}
|
|
|
@ -15,7 +15,7 @@ struct SleepingThread {
|
||||||
|
|
||||||
class Script;
|
class Script;
|
||||||
|
|
||||||
class DEF_INST_SERVICE_(hidden) ScriptContext : public Service {
|
class DEF_INST_SERVICE ScriptContext : public Service {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
|
|
||||||
std::vector<SleepingThread> sleepingThreads;
|
std::vector<SleepingThread> sleepingThreads;
|
||||||
|
@ -32,8 +32,5 @@ public:
|
||||||
void PushThreadSleep(lua_State* thread, float delay);
|
void PushThreadSleep(lua_State* thread, float delay);
|
||||||
void RunSleepingThreads();
|
void RunSleepingThreads();
|
||||||
|
|
||||||
// Generates an environment with a metatable and pushes it both the env table and metatable in order onto the stack
|
|
||||||
void NewEnvironment(lua_State* state);
|
|
||||||
|
|
||||||
static inline std::shared_ptr<Instance> Create() { return std::make_shared<ScriptContext>(); };
|
static inline std::shared_ptr<Instance> Create() { return std::make_shared<ScriptContext>(); };
|
||||||
};
|
};
|
|
@ -14,7 +14,7 @@ void ServerScriptService::InitService() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerScriptService::OnRun() {
|
void ServerScriptService::OnRun() {
|
||||||
auto workspace = dataModel()->GetService<Workspace>();
|
auto workspace = dataModel().value()->GetService<Workspace>();
|
||||||
for (auto it = workspace->GetDescendantsStart(); it != workspace->GetDescendantsEnd(); it++) {
|
for (auto it = workspace->GetDescendantsStart(); it != workspace->GetDescendantsEnd(); it++) {
|
||||||
if (!it->IsA<Script>()) continue;
|
if (!it->IsA<Script>()) continue;
|
||||||
it->CastTo<Script>().expect()->Run();
|
it->CastTo<Script>().expect()->Run();
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
// Container class for server scripts
|
// Container class for server scripts
|
||||||
// Also handles/manages running server scripts on run
|
// Also handles/manages running server scripts on run
|
||||||
class DEF_INST_SERVICE_(explorer_icon="server-scripts", hidden) ServerScriptService : public Service {
|
class DEF_INST_SERVICE_(explorer_icon="server-scripts") ServerScriptService : public Service {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
protected:
|
protected:
|
||||||
void InitService() override;
|
void InitService() override;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class DEF_INST_SERVICE_(hidden) Selection : public Service {
|
class DEF_INST_SERVICE Selection : public Service {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
private:
|
private:
|
||||||
std::vector<std::shared_ptr<Instance>> selection;
|
std::vector<std::shared_ptr<Instance>> selection;
|
||||||
|
|
|
@ -4,32 +4,87 @@
|
||||||
#include "datatypes/vector.h"
|
#include "datatypes/vector.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "objects/base/instance.h"
|
#include "objects/base/instance.h"
|
||||||
#include "objects/part/part.h"
|
#include "objects/part.h"
|
||||||
#include "objects/part/wedgepart.h"
|
|
||||||
#include "objects/service/jointsservice.h"
|
#include "objects/service/jointsservice.h"
|
||||||
#include "objects/joint/jointinstance.h"
|
#include "objects/joint/jointinstance.h"
|
||||||
#include "objects/datamodel.h"
|
#include "objects/datamodel.h"
|
||||||
|
#include "physics/util.h"
|
||||||
#include "timeutil.h"
|
#include "timeutil.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <reactphysics3d/collision/CollisionCallback.h>
|
||||||
|
#include <reactphysics3d/collision/OverlapCallback.h>
|
||||||
|
#include <reactphysics3d/engine/PhysicsCommon.h>
|
||||||
|
|
||||||
Workspace::Workspace(): Service(&TYPE), physicsWorld(std::make_shared<PhysWorld>()) {
|
rp::PhysicsCommon* Workspace::physicsCommon = new rp::PhysicsCommon;
|
||||||
|
|
||||||
|
Workspace::Workspace(): Service(&TYPE), physicsEventListener(this) {
|
||||||
|
physicsWorld = physicsCommon->createPhysicsWorld();
|
||||||
}
|
}
|
||||||
|
|
||||||
Workspace::~Workspace() = default;
|
Workspace::~Workspace() {
|
||||||
|
if (physicsCommon)
|
||||||
|
physicsCommon->destroyPhysicsWorld(physicsWorld);
|
||||||
|
}
|
||||||
|
|
||||||
|
PhysicsEventListener::PhysicsEventListener(Workspace* parent) : workspace(parent) {}
|
||||||
|
|
||||||
|
void PhysicsEventListener::onContact(const rp::CollisionCallback::CallbackData& data) {
|
||||||
|
for (size_t i = 0; i < data.getNbContactPairs(); i++) {
|
||||||
|
auto pair = data.getContactPair(i);
|
||||||
|
auto type = pair.getEventType();
|
||||||
|
if (type == rp::CollisionCallback::ContactPair::EventType::ContactStay) continue;
|
||||||
|
|
||||||
|
auto part0 = reinterpret_cast<Part*>(pair.getBody1()->getUserData())->shared<Part>();
|
||||||
|
auto part1 = reinterpret_cast<Part*>(pair.getBody2()->getUserData())->shared<Part>();
|
||||||
|
|
||||||
|
if (type == reactphysics3d::CollisionCallback::ContactPair::EventType::ContactStart) {
|
||||||
|
part0->Touched->Fire({ (Variant)InstanceRef(part1) });
|
||||||
|
part1->Touched->Fire({ (Variant)InstanceRef(part0) });
|
||||||
|
} else if (type == reactphysics3d::CollisionCallback::ContactPair::EventType::ContactExit) {
|
||||||
|
part0->TouchEnded->Fire({ (Variant)InstanceRef(part1) });
|
||||||
|
part1->TouchEnded->Fire({ (Variant)InstanceRef(part0) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsEventListener::onTrigger(const rp::OverlapCallback::CallbackData& data) {
|
||||||
|
for (size_t i = 0; i < data.getNbOverlappingPairs(); i++) {
|
||||||
|
auto pair = data.getOverlappingPair(i);
|
||||||
|
auto type = pair.getEventType();
|
||||||
|
if (type == rp::OverlapCallback::OverlapPair::EventType::OverlapStay) continue;
|
||||||
|
|
||||||
|
auto part0 = reinterpret_cast<Part*>(pair.getBody1()->getUserData())->shared<Part>();
|
||||||
|
auto part1 = reinterpret_cast<Part*>(pair.getBody2()->getUserData())->shared<Part>();
|
||||||
|
|
||||||
|
if (type == reactphysics3d::OverlapCallback::OverlapPair::EventType::OverlapStart) {
|
||||||
|
part0->Touched->Fire({ (Variant)InstanceRef(part1) });
|
||||||
|
part1->Touched->Fire({ (Variant)InstanceRef(part0) });
|
||||||
|
} else if (type == reactphysics3d::OverlapCallback::OverlapPair::EventType::OverlapExit) {
|
||||||
|
part0->TouchEnded->Fire({ (Variant)InstanceRef(part1) });
|
||||||
|
part1->TouchEnded->Fire({ (Variant)InstanceRef(part0) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Workspace::InitService() {
|
void Workspace::InitService() {
|
||||||
if (initialized) return;
|
if (initialized) return;
|
||||||
initialized = true;
|
initialized = true;
|
||||||
|
|
||||||
// Create meshes
|
physicsWorld->setGravity(rp::Vector3(0, -196.2, 0));
|
||||||
// WedgePart::createWedgeShape(physicsCommon);
|
// world->setContactsPositionCorrectionTechnique(rp3d::ContactsPositionCorrectionTechnique::BAUMGARTE_CONTACTS);
|
||||||
|
physicsWorld->setNbIterationsPositionSolver(2000);
|
||||||
|
physicsWorld->setNbIterationsVelocitySolver(2000);
|
||||||
|
// physicsWorld->setSleepLinearVelocity(10);
|
||||||
|
// physicsWorld->setSleepAngularVelocity(5);
|
||||||
|
|
||||||
|
physicsWorld->setEventListener(&physicsEventListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspace::OnRun() {
|
void Workspace::OnRun() {
|
||||||
// Make joints
|
// Make joints
|
||||||
for (auto it = this->GetDescendantsStart(); it != this->GetDescendantsEnd(); it++) {
|
for (auto it = this->GetDescendantsStart(); it != this->GetDescendantsEnd(); it++) {
|
||||||
if (!it->IsA<BasePart>()) continue;
|
if (!it->IsA<Part>()) continue;
|
||||||
std::shared_ptr<BasePart> part = it->CastTo<BasePart>().expect();
|
std::shared_ptr<Part> part = it->CastTo<Part>().expect();
|
||||||
part->MakeJoints();
|
part->MakeJoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,29 +96,206 @@ void Workspace::OnRun() {
|
||||||
joint->UpdateProperty("Part0");
|
joint->UpdateProperty("Part0");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto obj : dataModel()->GetService<JointsService>()->GetChildren()) {
|
for (auto obj : dataModel().value()->GetService<JointsService>()->GetChildren()) {
|
||||||
if (!obj->IsA<JointInstance>()) continue;
|
if (!obj->IsA<JointInstance>()) continue;
|
||||||
std::shared_ptr<JointInstance> joint = obj->CastTo<JointInstance>().expect();
|
std::shared_ptr<JointInstance> joint = obj->CastTo<JointInstance>().expect();
|
||||||
joint->UpdateProperty("Part0");
|
joint->UpdateProperty("Part0");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspace::SyncPartPhysics(std::shared_ptr<BasePart> part) {
|
void Workspace::updatePartPhysics(std::shared_ptr<Part> part) {
|
||||||
physicsWorld->syncBodyProperties(part);
|
rp::Transform transform = part->cframe;
|
||||||
|
if (!part->rigidBody) {
|
||||||
|
part->rigidBody = physicsWorld->createRigidBody(transform);
|
||||||
|
} else {
|
||||||
|
part->rigidBody->setTransform(transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspace::PhysicsStep(float deltaTime) {
|
rp::BoxShape* shape = physicsCommon->createBoxShape(glmToRp(part->size * glm::vec3(0.5f)));
|
||||||
physicsWorld->step(deltaTime);
|
|
||||||
|
// Recreate the rigidbody if the shape changes
|
||||||
|
if (part->rigidBody->getNbColliders() > 0
|
||||||
|
&& dynamic_cast<rp::BoxShape*>(part->rigidBody->getCollider(0)->getCollisionShape())->getHalfExtents() != shape->getHalfExtents()) {
|
||||||
|
// TODO: This causes Touched to get called twice. Fix this.
|
||||||
|
part->rigidBody->removeCollider(part->rigidBody->getCollider(0));
|
||||||
|
part->rigidBody->addCollider(shape, rp::Transform());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (part->rigidBody->getNbColliders() == 0)
|
||||||
|
part->rigidBody->addCollider(shape, rp::Transform());
|
||||||
|
|
||||||
|
part->rigidBody->setType(part->anchored ? rp::BodyType::STATIC : rp::BodyType::DYNAMIC);
|
||||||
|
part->rigidBody->getCollider(0)->setCollisionCategoryBits(0b11);
|
||||||
|
|
||||||
|
part->rigidBody->getCollider(0)->setIsSimulationCollider(part->canCollide);
|
||||||
|
part->rigidBody->getCollider(0)->setIsTrigger(!part->canCollide);
|
||||||
|
|
||||||
|
rp::Material& material = part->rigidBody->getCollider(0)->getMaterial();
|
||||||
|
material.setFrictionCoefficient(0.35);
|
||||||
|
material.setMassDensity(1.f);
|
||||||
|
|
||||||
|
//https://github.com/DanielChappuis/reactphysics3d/issues/170#issuecomment-691514860
|
||||||
|
part->rigidBody->updateMassFromColliders();
|
||||||
|
part->rigidBody->updateLocalInertiaTensorFromColliders();
|
||||||
|
|
||||||
|
part->rigidBody->setLinearVelocity(part->velocity);
|
||||||
|
// part->rigidBody->setMass(density * part->size.x * part->size.y * part->size.z);
|
||||||
|
|
||||||
|
part->rigidBody->setUserData(&*part);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Workspace::SyncPartPhysics(std::shared_ptr<Part> part) {
|
||||||
|
if (globalPhysicsLock.try_lock()) {
|
||||||
|
updatePartPhysics(part);
|
||||||
|
globalPhysicsLock.unlock();
|
||||||
|
} else {
|
||||||
|
part->rigidBodyDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tu_time_t physTime;
|
||||||
|
void Workspace::PhysicsStep(float deltaTime) {
|
||||||
|
tu_time_t startTime = tu_clock_micros();
|
||||||
|
|
||||||
|
std::scoped_lock lock(globalPhysicsLock);
|
||||||
|
physicsWorld->update(std::min(deltaTime / 2, (1/60.f)));
|
||||||
|
|
||||||
|
// Update queued objects
|
||||||
|
queueLock.lock();
|
||||||
|
for (QueueItem item : bodyQueue) {
|
||||||
|
if (item.action == QueueItem::QUEUEITEM_ADD) {
|
||||||
|
simulatedBodies.push_back(item.part);
|
||||||
|
item.part->simulationTicket = --simulatedBodies.end();
|
||||||
|
} else if (item.part->simulationTicket.has_value()) {
|
||||||
|
simulatedBodies.erase(item.part->simulationTicket.value());
|
||||||
|
item.part->simulationTicket = std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
queueLock.unlock();
|
||||||
|
|
||||||
|
// TODO: Add list of tracked parts in workspace based on their ancestry using inWorkspace property of Instance
|
||||||
|
for (std::shared_ptr<Part> part : simulatedBodies) {
|
||||||
|
// If the part's body is dirty, update it now instead
|
||||||
|
if (part->rigidBodyDirty) {
|
||||||
|
updatePartPhysics(part);
|
||||||
|
part->rigidBodyDirty = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!part->rigidBody) continue;
|
||||||
|
|
||||||
|
// Sync properties
|
||||||
|
const rp::Transform& transform = part->rigidBody->getTransform();
|
||||||
|
part->cframe = CFrame(transform);
|
||||||
|
part->velocity = part->rigidBody->getLinearVelocity();
|
||||||
|
|
||||||
|
// part->rigidBody->enableGravity(true);
|
||||||
|
// RotateV/Motor joint
|
||||||
|
for (auto& joint : part->secondaryJoints) {
|
||||||
|
if (joint.expired() || !joint.lock()->IsA("RotateV")) continue;
|
||||||
|
|
||||||
|
std::shared_ptr<JointInstance> motor = joint.lock()->CastTo<JointInstance>().expect();
|
||||||
|
float rate = motor->part0.lock()->GetSurfaceParamB(-motor->c0.LookVector().Unit()) * 30;
|
||||||
|
// part->rigidBody->enableGravity(false);
|
||||||
|
part->rigidBody->setAngularVelocity(-(motor->part0.lock()->cframe * motor->c0).LookVector() * rate);
|
||||||
|
}
|
||||||
|
|
||||||
for (std::shared_ptr<BasePart> part : physicsWorld->getSimulatedBodies()) {
|
|
||||||
// Destroy fallen parts
|
// Destroy fallen parts
|
||||||
if (part->cframe.Position().Y() < this->fallenPartsDestroyHeight) {
|
if (part->cframe.Position().Y() < this->fallenPartsDestroyHeight) {
|
||||||
auto parent = part->GetParent();
|
auto parent = part->GetParent();
|
||||||
part->Destroy();
|
part->Destroy();
|
||||||
|
|
||||||
// If the parent of the part is a Model, destroy it too
|
// If the parent of the part is a Model, destroy it too
|
||||||
if (parent != nullptr && parent->IsA("Model"))
|
if (parent.has_value() && parent.value()->IsA("Model"))
|
||||||
parent->Destroy();
|
parent.value()->Destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
physTime = tu_clock_micros() - startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RaycastResult::RaycastResult(const rp::RaycastInfo& raycastInfo)
|
||||||
|
: worldPoint(raycastInfo.worldPoint)
|
||||||
|
, worldNormal(raycastInfo.worldNormal)
|
||||||
|
, hitFraction(raycastInfo.hitFraction)
|
||||||
|
, triangleIndex(raycastInfo.triangleIndex)
|
||||||
|
, body(raycastInfo.body)
|
||||||
|
, collider(raycastInfo.collider) {}
|
||||||
|
|
||||||
|
class NearestRayHit : public rp::RaycastCallback {
|
||||||
|
rp::Vector3 startPos;
|
||||||
|
std::optional<RaycastFilter> filter;
|
||||||
|
|
||||||
|
std::optional<RaycastResult> nearestHit;
|
||||||
|
float nearestHitDistance = -1;
|
||||||
|
|
||||||
|
// Order is not guaranteed, so we have to figure out the nearest object using a more sophisticated algorith,
|
||||||
|
rp::decimal notifyRaycastHit(const rp::RaycastInfo& raycastInfo) override {
|
||||||
|
// If the detected object is further away than the nearest object, continue.
|
||||||
|
int distance = (raycastInfo.worldPoint - startPos).length();
|
||||||
|
if (nearestHitDistance != -1 && distance >= nearestHitDistance)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!filter) {
|
||||||
|
nearestHit = raycastInfo;
|
||||||
|
nearestHitDistance = distance;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Part> part = partFromBody(raycastInfo.body);
|
||||||
|
FilterResult result = filter.value()(part);
|
||||||
|
if (result == FilterResult::BLOCK) {
|
||||||
|
nearestHit = std::nullopt;
|
||||||
|
nearestHitDistance = distance;
|
||||||
|
return 1;
|
||||||
|
} else if (result == FilterResult::TARGET) {
|
||||||
|
nearestHit = raycastInfo;
|
||||||
|
nearestHitDistance = distance;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
NearestRayHit(rp::Vector3 startPos, std::optional<RaycastFilter> filter = std::nullopt) : startPos(startPos), filter(filter) {}
|
||||||
|
std::optional<const RaycastResult> getNearestHit() { return nearestHit; };
|
||||||
|
};
|
||||||
|
|
||||||
|
std::optional<const RaycastResult> Workspace::CastRayNearest(glm::vec3 point, glm::vec3 rotation, float maxLength, std::optional<RaycastFilter> filter, unsigned short categoryMaskBits) {
|
||||||
|
// std::scoped_lock lock(globalPhysicsLock);
|
||||||
|
rp::Ray ray(glmToRp(point), glmToRp(glm::normalize(rotation)) * maxLength);
|
||||||
|
NearestRayHit rayHit(glmToRp(point), filter);
|
||||||
|
physicsWorld->raycast(ray, &rayHit, categoryMaskBits);
|
||||||
|
return rayHit.getNearestHit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Workspace::DestroyRigidBody(rp::RigidBody* rigidBody) {
|
||||||
|
std::scoped_lock lock(globalPhysicsLock);
|
||||||
|
physicsWorld->destroyRigidBody(rigidBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Workspace::DestroyJoint(rp::Joint* joint) {
|
||||||
|
std::scoped_lock lock(globalPhysicsLock);
|
||||||
|
physicsWorld->destroyJoint(joint);
|
||||||
|
}
|
||||||
|
|
||||||
|
rp::Joint* Workspace::CreateJoint(const rp::JointInfo& jointInfo) {
|
||||||
|
std::scoped_lock lock(globalPhysicsLock);
|
||||||
|
rp::Joint* joint = physicsWorld->createJoint(jointInfo);
|
||||||
|
|
||||||
|
return joint;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Workspace::AddBody(std::shared_ptr<Part> part) {
|
||||||
|
queueLock.lock();
|
||||||
|
bodyQueue.push_back({part, QueueItem::QUEUEITEM_ADD});
|
||||||
|
part->rigidBodyDirty = true;
|
||||||
|
queueLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Workspace::RemoveBody(std::shared_ptr<Part> part) {
|
||||||
|
queueLock.lock();
|
||||||
|
bodyQueue.push_back({part, QueueItem::QUEUEITEM_REMOVE});
|
||||||
|
queueLock.unlock();
|
||||||
}
|
}
|
|
@ -2,37 +2,77 @@
|
||||||
|
|
||||||
#include "objects/annotation.h"
|
#include "objects/annotation.h"
|
||||||
#include "objects/base/service.h"
|
#include "objects/base/service.h"
|
||||||
#include "physics/world.h"
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include <glm/ext/vector_float3.hpp>
|
#include <glm/ext/vector_float3.hpp>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <queue>
|
#include <reactphysics3d/body/RigidBody.h>
|
||||||
|
#include <reactphysics3d/engine/EventListener.h>
|
||||||
|
#include <reactphysics3d/engine/PhysicsCommon.h>
|
||||||
|
#include <reactphysics3d/engine/PhysicsWorld.h>
|
||||||
|
|
||||||
class BasePart;
|
namespace rp = reactphysics3d;
|
||||||
|
|
||||||
|
struct RaycastResult {
|
||||||
|
rp::Vector3 worldPoint;
|
||||||
|
rp::Vector3 worldNormal;
|
||||||
|
rp::decimal hitFraction;
|
||||||
|
int triangleIndex;
|
||||||
|
rp::Body* body;
|
||||||
|
rp::Collider* collider;
|
||||||
|
|
||||||
|
RaycastResult(const rp::RaycastInfo& raycastInfo);
|
||||||
|
};
|
||||||
|
|
||||||
|
enum FilterResult {
|
||||||
|
TARGET, // The object is captured
|
||||||
|
BLOCK, // The object blocks any objects behind it, but is not captured
|
||||||
|
PASS, // The object is transparent, ignore it
|
||||||
|
};
|
||||||
|
|
||||||
|
class Part;
|
||||||
class Snap;
|
class Snap;
|
||||||
class Weld;
|
class Weld;
|
||||||
class Rotate;
|
class Rotate;
|
||||||
class RotateV;
|
class RotateV;
|
||||||
|
|
||||||
struct ContactItem {
|
#ifndef __SIMULATION_TICKET
|
||||||
std::shared_ptr<BasePart> part0;
|
#define __SIMULATION_TICKET
|
||||||
std::shared_ptr<BasePart> part1;
|
typedef std::list<std::shared_ptr<Part>>::iterator SimulationTicket;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef std::function<FilterResult(std::shared_ptr<Part>)> RaycastFilter;
|
||||||
|
|
||||||
|
struct QueueItem {
|
||||||
|
std::shared_ptr<Part> part;
|
||||||
enum {
|
enum {
|
||||||
CONTACTITEM_TOUCHED,
|
QUEUEITEM_ADD,
|
||||||
CONTACTITEM_TOUCHENDED,
|
QUEUEITEM_REMOVE,
|
||||||
} action;
|
} action;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Workspace;
|
||||||
|
class PhysicsEventListener : public rp::EventListener {
|
||||||
|
friend Workspace;
|
||||||
|
Workspace* workspace;
|
||||||
|
|
||||||
|
PhysicsEventListener(Workspace*);
|
||||||
|
|
||||||
|
void onContact(const rp::CollisionCallback::CallbackData&) override;
|
||||||
|
void onTrigger(const rp::OverlapCallback::CallbackData&) override;
|
||||||
|
};
|
||||||
|
|
||||||
class DEF_INST_SERVICE_(explorer_icon="workspace") Workspace : public Service {
|
class DEF_INST_SERVICE_(explorer_icon="workspace") Workspace : public Service {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
|
|
||||||
std::queue<ContactItem> contactQueue;
|
std::list<std::shared_ptr<Part>> simulatedBodies;
|
||||||
std::mutex contactQueueLock;
|
std::list<QueueItem> bodyQueue;
|
||||||
|
rp::PhysicsWorld* physicsWorld;
|
||||||
|
static rp::PhysicsCommon* physicsCommon;
|
||||||
|
PhysicsEventListener physicsEventListener;
|
||||||
|
|
||||||
std::shared_ptr<PhysWorld> physicsWorld;
|
void updatePartPhysics(std::shared_ptr<Part> part);
|
||||||
friend PhysWorld;
|
|
||||||
protected:
|
protected:
|
||||||
void InitService() override;
|
void InitService() override;
|
||||||
void OnRun() override;
|
void OnRun() override;
|
||||||
|
@ -42,6 +82,7 @@ public:
|
||||||
Workspace();
|
Workspace();
|
||||||
~Workspace();
|
~Workspace();
|
||||||
|
|
||||||
|
std::mutex globalPhysicsLock;
|
||||||
std::recursive_mutex queueLock;
|
std::recursive_mutex queueLock;
|
||||||
|
|
||||||
DEF_PROP float fallenPartsDestroyHeight = -500;
|
DEF_PROP float fallenPartsDestroyHeight = -500;
|
||||||
|
@ -49,13 +90,14 @@ public:
|
||||||
// static inline std::shared_ptr<Workspace> New() { return std::make_shared<Workspace>(); };
|
// static inline std::shared_ptr<Workspace> New() { return std::make_shared<Workspace>(); };
|
||||||
static inline std::shared_ptr<Instance> Create() { return std::make_shared<Workspace>(); };
|
static inline std::shared_ptr<Instance> Create() { return std::make_shared<Workspace>(); };
|
||||||
|
|
||||||
inline void AddBody(std::shared_ptr<BasePart> part) { physicsWorld->addBody(part); }
|
void AddBody(std::shared_ptr<Part> part);
|
||||||
inline void RemoveBody(std::shared_ptr<BasePart> part) { physicsWorld->removeBody(part); }
|
void RemoveBody(std::shared_ptr<Part> part);
|
||||||
void SyncPartPhysics(std::shared_ptr<BasePart> part);
|
void DestroyRigidBody(rp::RigidBody* rigidBody);
|
||||||
|
void SyncPartPhysics(std::shared_ptr<Part> part);
|
||||||
|
|
||||||
inline PhysJoint CreateJoint(PhysJointInfo& info, std::shared_ptr<BasePart> part0, std::shared_ptr<BasePart> part1) { return physicsWorld->createJoint(info, part0, part1); }
|
rp::Joint* CreateJoint(const rp::JointInfo& jointInfo);
|
||||||
inline void DestroyJoint(PhysJoint joint) { physicsWorld->destroyJoint(joint); }
|
void DestroyJoint(rp::Joint* joint);
|
||||||
|
|
||||||
void PhysicsStep(float deltaTime);
|
void PhysicsStep(float deltaTime);
|
||||||
inline std::optional<const RaycastResult> CastRayNearest(glm::vec3 point, glm::vec3 rotation, float maxLength, std::optional<RaycastFilter> filter = std::nullopt, unsigned short categoryMaskBits = 0xFFFF) { return physicsWorld->castRay(point, rotation, maxLength, filter, categoryMaskBits); }
|
std::optional<const RaycastResult> CastRayNearest(glm::vec3 point, glm::vec3 rotation, float maxLength, std::optional<RaycastFilter> filter = std::nullopt, unsigned short categoryMaskBits = 0xFFFF);
|
||||||
};
|
};
|
|
@ -1,8 +1,13 @@
|
||||||
#include "panic.h"
|
#include "panic.h"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
|
#ifdef _NDEBUG
|
||||||
|
#define NDEBUG
|
||||||
|
#endif
|
||||||
|
|
||||||
bool trySafeAbort = false;
|
bool trySafeAbort = false;
|
||||||
void panic() {
|
void panic() {
|
||||||
// We've already been here, safe aborting has failed.
|
// We've already been here, safe aborting has failed.
|
||||||
|
|
|
@ -5,13 +5,13 @@
|
||||||
#include "datatypes/vector.h"
|
#include "datatypes/vector.h"
|
||||||
#include "math_helper.h"
|
#include "math_helper.h"
|
||||||
#include "objects/base/instance.h"
|
#include "objects/base/instance.h"
|
||||||
#include "objects/part/part.h"
|
#include "objects/part.h"
|
||||||
#include "objects/service/selection.h"
|
#include "objects/service/selection.h"
|
||||||
#include <glm/common.hpp>
|
#include <glm/common.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
PartAssembly::PartAssembly(std::vector<std::shared_ptr<BasePart>> parts, bool worldMode) : parts(parts) {
|
PartAssembly::PartAssembly(std::vector<std::shared_ptr<Part>> parts, bool worldMode) : parts(parts) {
|
||||||
if (parts.size() == 0) return;
|
if (parts.size() == 0) return;
|
||||||
if (parts.size() == 1 && !worldMode) {
|
if (parts.size() == 1 && !worldMode) {
|
||||||
_assemblyOrigin = parts[0]->cframe;
|
_assemblyOrigin = parts[0]->cframe;
|
||||||
|
@ -36,19 +36,19 @@ PartAssembly::PartAssembly(std::vector<std::shared_ptr<BasePart>> parts, bool wo
|
||||||
}
|
}
|
||||||
|
|
||||||
PartAssembly PartAssembly::FromSelection(std::vector<std::shared_ptr<Instance>> newSelection) {
|
PartAssembly PartAssembly::FromSelection(std::vector<std::shared_ptr<Instance>> newSelection) {
|
||||||
std::vector<std::shared_ptr<BasePart>> selection;
|
std::vector<std::shared_ptr<Part>> selection;
|
||||||
|
|
||||||
for (std::shared_ptr<Instance> obj : newSelection) {
|
for (std::shared_ptr<Instance> obj : newSelection) {
|
||||||
if (!obj->IsA<PVInstance>()) continue;
|
if (!obj->IsA<PVInstance>()) continue;
|
||||||
|
|
||||||
if (obj->IsA<BasePart>())
|
if (obj->IsA<Part>())
|
||||||
selection.push_back(obj->CastTo<BasePart>().expect());
|
selection.push_back(obj->CastTo<Part>().expect());
|
||||||
|
|
||||||
// Add object descendants
|
// Add object descendants
|
||||||
for (DescendantsIterator it = obj->GetDescendantsStart(); it != obj->GetDescendantsEnd(); it++) {
|
for (DescendantsIterator it = obj->GetDescendantsStart(); it != obj->GetDescendantsEnd(); it++) {
|
||||||
if (!(*it)->IsA<BasePart>()) continue;
|
if (!(*it)->IsA<Part>()) continue;
|
||||||
|
|
||||||
selection.push_back((*it)->CastTo<BasePart>().expect());
|
selection.push_back((*it)->CastTo<Part>().expect());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,16 +61,14 @@ PartAssembly PartAssembly::FromSelection(std::shared_ptr<Selection> selection) {
|
||||||
|
|
||||||
void PartAssembly::SetCollisionsEnabled(bool enabled) {
|
void PartAssembly::SetCollisionsEnabled(bool enabled) {
|
||||||
for (auto part : parts) {
|
for (auto part : parts) {
|
||||||
part->rigidBody.setCollisionsEnabled(enabled);
|
part->rigidBody->getCollider(0)->setIsWorldQueryCollider(enabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PartAssembly::SetOrigin(CFrame newOrigin) {
|
void PartAssembly::SetOrigin(CFrame newOrigin) {
|
||||||
for (auto part : parts) {
|
for (auto part : parts) {
|
||||||
part->cframe = newOrigin * (_assemblyOrigin.Inverse() * part->cframe);
|
part->cframe = newOrigin * (_assemblyOrigin.Inverse() * part->cframe);
|
||||||
part->velocity = 0; // Reset velocity
|
|
||||||
part->UpdateProperty("CFrame");
|
part->UpdateProperty("CFrame");
|
||||||
part->UpdateProperty("Velocity");
|
|
||||||
// sendPropertyUpdatedSignal(part, "CFrame", Variant(part->cframe));
|
// sendPropertyUpdatedSignal(part, "CFrame", Variant(part->cframe));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,22 +78,19 @@ void PartAssembly::SetOrigin(CFrame newOrigin) {
|
||||||
void PartAssembly::TransformBy(CFrame transform) {
|
void PartAssembly::TransformBy(CFrame transform) {
|
||||||
for (auto part : parts) {
|
for (auto part : parts) {
|
||||||
part->cframe = transform * part->cframe;
|
part->cframe = transform * part->cframe;
|
||||||
part->velocity = 0; // Reset velocity
|
|
||||||
part->UpdateProperty("CFrame");
|
part->UpdateProperty("CFrame");
|
||||||
part->UpdateProperty("Position");
|
part->UpdateProperty("Position");
|
||||||
part->UpdateProperty("Rotation");
|
part->UpdateProperty("Rotation");
|
||||||
part->UpdateProperty("Velocity");
|
|
||||||
sendPropertyUpdatedSignal(part, "CFrame", Variant(part->cframe));
|
sendPropertyUpdatedSignal(part, "CFrame", Variant(part->cframe));
|
||||||
sendPropertyUpdatedSignal(part, "Position", Variant(part->cframe));
|
sendPropertyUpdatedSignal(part, "Position", Variant(part->cframe));
|
||||||
sendPropertyUpdatedSignal(part, "Rotation", Variant(part->cframe));
|
sendPropertyUpdatedSignal(part, "Rotation", Variant(part->cframe));
|
||||||
sendPropertyUpdatedSignal(part, "Velocity", Variant(part->cframe));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_assemblyOrigin = transform * _assemblyOrigin;
|
_assemblyOrigin = transform * _assemblyOrigin;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PartAssembly::Scale(Vector3 newSize, bool scaleUp) {
|
void PartAssembly::Scale(Vector3 newSize, bool scaleUp) {
|
||||||
if (parts.size() == 1 && (!parts[0]->IsA<Part>() || parts[0]->CastTo<Part>().expect()->shape != PartType::Ball)) {
|
if (parts.size() == 1) {
|
||||||
parts[0]->size = newSize;
|
parts[0]->size = newSize;
|
||||||
parts[0]->UpdateProperty("Size");
|
parts[0]->UpdateProperty("Size");
|
||||||
sendPropertyUpdatedSignal(parts[0], "Size", Variant(parts[0]->size));
|
sendPropertyUpdatedSignal(parts[0], "Size", Variant(parts[0]->size));
|
||||||
|
@ -132,7 +127,6 @@ std::vector<PartTransformState> PartAssembly::GetCurrentTransforms() {
|
||||||
t.part = part;
|
t.part = part;
|
||||||
t.cframe = part->cframe;
|
t.cframe = part->cframe;
|
||||||
t.size = part->size;
|
t.size = part->size;
|
||||||
t.velocity = part->velocity;
|
|
||||||
transforms.push_back(t);
|
transforms.push_back(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,14 +4,13 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class BasePart;
|
class Part;
|
||||||
class Instance;
|
class Instance;
|
||||||
class Selection;
|
class Selection;
|
||||||
|
|
||||||
struct PartTransformState {
|
struct PartTransformState {
|
||||||
std::shared_ptr<BasePart> part;
|
std::shared_ptr<Part> part;
|
||||||
Vector3 size;
|
Vector3 size;
|
||||||
Vector3 velocity;
|
|
||||||
CFrame cframe;
|
CFrame cframe;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,9 +19,9 @@ class PartAssembly {
|
||||||
Vector3 _bounds;
|
Vector3 _bounds;
|
||||||
Vector3 _size;
|
Vector3 _size;
|
||||||
|
|
||||||
std::vector<std::shared_ptr<BasePart>> parts;
|
std::vector<std::shared_ptr<Part>> parts;
|
||||||
public:
|
public:
|
||||||
PartAssembly(std::vector<std::shared_ptr<BasePart>>, bool worldMode = false);
|
PartAssembly(std::vector<std::shared_ptr<Part>>, bool worldMode = false);
|
||||||
|
|
||||||
static PartAssembly FromSelection(std::vector<std::shared_ptr<Instance>> selection);
|
static PartAssembly FromSelection(std::vector<std::shared_ptr<Instance>> selection);
|
||||||
static PartAssembly FromSelection(std::shared_ptr<Selection> selection);
|
static PartAssembly FromSelection(std::shared_ptr<Selection> selection);
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include "datatypes/cframe.h"
|
|
||||||
#include "datatypes/vector.h"
|
|
||||||
#include <glm/ext/vector_float3.hpp>
|
|
||||||
#include <glm/ext.hpp>
|
|
||||||
|
|
||||||
#include <Jolt/Jolt.h>
|
|
||||||
|
|
||||||
template <typename T, typename F>
|
|
||||||
T convert(F vec) = delete;
|
|
||||||
|
|
||||||
// Vector3
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline Vector3 convert<Vector3>(JPH::Vec3 vec) {
|
|
||||||
return Vector3(vec.GetX(), vec.GetY(), vec.GetZ());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline JPH::Vec3 convert<JPH::Vec3>(Vector3 vec) {
|
|
||||||
return JPH::Vec3(vec.X(), vec.Y(), vec.Z());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline glm::vec3 convert<glm::vec3>(JPH::Vec3 vec) {
|
|
||||||
return glm::vec3(vec.GetX(), vec.GetY(), vec.GetZ());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline JPH::Vec3 convert<JPH::Vec3>(glm::vec3 vec) {
|
|
||||||
return JPH::Vec3(vec.x, vec.y, vec.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Quaternion
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline glm::quat convert<glm::quat>(JPH::Quat quat) {
|
|
||||||
return glm::quat(quat.GetW(), quat.GetX(), quat.GetY(), quat.GetZ());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline JPH::Quat convert<JPH::Quat>(glm::quat quat) {
|
|
||||||
return JPH::Quat(quat.x, quat.y, quat.z, quat.w);
|
|
||||||
}
|
|
39
core/src/physics/util.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#pragma once
|
||||||
|
#include <glm/ext/vector_float3.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <reactphysics3d/body/Body.h>
|
||||||
|
#include <reactphysics3d/mathematics/Matrix3x3.h>
|
||||||
|
#include <reactphysics3d/mathematics/Quaternion.h>
|
||||||
|
#include <reactphysics3d/mathematics/Vector3.h>
|
||||||
|
#include <reactphysics3d/mathematics/mathematics.h>
|
||||||
|
#include <glm/ext.hpp>
|
||||||
|
#include "objects/part.h"
|
||||||
|
|
||||||
|
namespace rp = reactphysics3d;
|
||||||
|
|
||||||
|
inline rp::Vector3 glmToRp(glm::vec3 vec) {
|
||||||
|
return rp::Vector3(vec.x, vec.y, vec.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline rp::Quaternion glmToRp(glm::quat quat) {
|
||||||
|
return rp::Quaternion(quat.w, rp::Vector3(quat.x, quat.y, quat.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline rp::Matrix3x3 glmToRp(glm::mat3 mat) {
|
||||||
|
// return (rp::Quaternion)glmToRp((glm::quat)mat);
|
||||||
|
// }
|
||||||
|
|
||||||
|
inline glm::vec3 rpToGlm(rp::Vector3 vec) {
|
||||||
|
return glm::vec3(vec.x, vec.y, vec.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline glm::quat rpToGlm(rp::Quaternion quat) {
|
||||||
|
return glm::quat(quat.w, quat.x, quat.y, quat.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make this std::optional
|
||||||
|
inline std::shared_ptr<Part> partFromBody(rp::Body* body) {
|
||||||
|
Part* raw = reinterpret_cast<Part*>(body->getUserData());
|
||||||
|
std::shared_ptr<Part> shared = std::dynamic_pointer_cast<Part>(raw->shared_from_this());
|
||||||
|
return shared;
|
||||||
|
}
|
|
@ -1,346 +0,0 @@
|
||||||
#include "world.h"
|
|
||||||
#include "datatypes/vector.h"
|
|
||||||
#include "enum/part.h"
|
|
||||||
#include "logger.h"
|
|
||||||
#include "objects/part/basepart.h"
|
|
||||||
#include "objects/part/part.h"
|
|
||||||
#include "objects/part/wedgepart.h"
|
|
||||||
#include "objects/service/workspace.h"
|
|
||||||
#include "physics/convert.h"
|
|
||||||
#include "timeutil.h"
|
|
||||||
|
|
||||||
#include <Jolt/Jolt.h>
|
|
||||||
#include <Jolt/Core/JobSystemThreadPool.h>
|
|
||||||
#include <Jolt/Core/TempAllocator.h>
|
|
||||||
#include <Jolt/Physics/Collision/BroadPhase/BroadPhaseLayer.h>
|
|
||||||
#include <Jolt/Physics/Collision/ObjectLayer.h>
|
|
||||||
#include <Jolt/Core/Factory.h>
|
|
||||||
#include <Jolt/Core/Memory.h>
|
|
||||||
#include <Jolt/Physics/Body/BodyCreationSettings.h>
|
|
||||||
#include <Jolt/Physics/Body/BodyInterface.h>
|
|
||||||
#include <Jolt/Physics/Body/MotionType.h>
|
|
||||||
#include <Jolt/Physics/Collision/RayCast.h>
|
|
||||||
#include <Jolt/Physics/Collision/Shape/BoxShape.h>
|
|
||||||
#include <Jolt/Physics/Collision/Shape/SphereShape.h>
|
|
||||||
#include <Jolt/Physics/Collision/Shape/CylinderShape.h>
|
|
||||||
#include <Jolt/Physics/Collision/Shape/ScaledShape.h>
|
|
||||||
#include <Jolt/Physics/Collision/Shape/ConvexHullShape.h>
|
|
||||||
#include <Jolt/Physics/Collision/Shape/RotatedTranslatedShape.h>
|
|
||||||
#include <Jolt/Physics/EActivation.h>
|
|
||||||
#include <Jolt/Physics/PhysicsSettings.h>
|
|
||||||
#include <Jolt/RegisterTypes.h>
|
|
||||||
#include <Jolt/Physics/Collision/CollisionCollectorImpl.h>
|
|
||||||
#include <Jolt/Physics/Collision/CastResult.h>
|
|
||||||
#include <Jolt/Physics/Collision/Shape/SubShapeID.h>
|
|
||||||
#include <Jolt/Physics/Body/BodyFilter.h>
|
|
||||||
#include <Jolt/Physics/Body/BodyLockInterface.h>
|
|
||||||
#include <Jolt/Physics/Collision/NarrowPhaseQuery.h>
|
|
||||||
#include <Jolt/Physics/Constraints/FixedConstraint.h>
|
|
||||||
#include <Jolt/Physics/Constraints/HingeConstraint.h>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
static JPH::TempAllocator* allocator;
|
|
||||||
static JPH::JobSystem* jobSystem;
|
|
||||||
|
|
||||||
namespace Layers
|
|
||||||
{
|
|
||||||
static constexpr JPH::ObjectLayer DYNAMIC = 0;
|
|
||||||
static constexpr JPH::ObjectLayer ANCHORED = 1;
|
|
||||||
static constexpr JPH::ObjectLayer NOCOLLIDE = 2;
|
|
||||||
// static constexpr JPH::ObjectLayer NUM_LAYERS = 3;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace BPLayers
|
|
||||||
{
|
|
||||||
static constexpr JPH::BroadPhaseLayer ANCHORED(0);
|
|
||||||
static constexpr JPH::BroadPhaseLayer DYNAMIC(1);
|
|
||||||
static constexpr JPH::BroadPhaseLayer NOCOLLIDE(2);
|
|
||||||
static constexpr uint NUM_LAYERS(3);
|
|
||||||
};
|
|
||||||
|
|
||||||
static JPH::Ref<JPH::Shape> wedgeShape;
|
|
||||||
|
|
||||||
void physicsInit() {
|
|
||||||
JPH::RegisterDefaultAllocator();
|
|
||||||
JPH::Factory::sInstance = new JPH::Factory();
|
|
||||||
JPH::RegisterTypes();
|
|
||||||
|
|
||||||
allocator = new JPH::TempAllocatorImpl(10 * 1024 * 1024);
|
|
||||||
jobSystem = new JPH::JobSystemThreadPool(JPH::cMaxPhysicsJobs, JPH::cMaxPhysicsBarriers, std::thread::hardware_concurrency() - 1);
|
|
||||||
|
|
||||||
// Create special shapes
|
|
||||||
JPH::Array<JPH::Vec3> wedgeVerts;
|
|
||||||
wedgeVerts.push_back({-1, -1, -1});
|
|
||||||
wedgeVerts.push_back({ 1, -1, -1});
|
|
||||||
wedgeVerts.push_back({-1, -1, 1});
|
|
||||||
wedgeVerts.push_back({ 1, -1, 1});
|
|
||||||
wedgeVerts.push_back({ 1, 1, 1});
|
|
||||||
wedgeVerts.push_back({-1, 1, 1});
|
|
||||||
// // Invisible bevel to avoid phasing
|
|
||||||
// wedgeVerts.push_back({1, 1, 0.9});
|
|
||||||
// wedgeVerts.push_back({0, 1, 0.9});
|
|
||||||
|
|
||||||
wedgeShape = JPH::ConvexHullShapeSettings(wedgeVerts).Create().Get();
|
|
||||||
}
|
|
||||||
|
|
||||||
void physicsDeinit() {
|
|
||||||
JPH::UnregisterTypes();
|
|
||||||
delete JPH::Factory::sInstance;
|
|
||||||
JPH::Factory::sInstance = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
PhysWorld::PhysWorld() {
|
|
||||||
worldImpl.Init(4096, 0, 4096, 4096, broadPhaseLayerInterface, objectBroadPhasefilter, objectLayerPairFilter);
|
|
||||||
worldImpl.SetGravity(JPH::Vec3(0, -196, 0));
|
|
||||||
JPH::PhysicsSettings settings = worldImpl.GetPhysicsSettings();
|
|
||||||
// settings.mPointVelocitySleepThreshold = 0.04f; // Fix parts not sleeping
|
|
||||||
// settings.mNumVelocitySteps *= 20;
|
|
||||||
// settings.mNumPositionSteps *= 20;
|
|
||||||
worldImpl.SetPhysicsSettings(settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
PhysWorld::~PhysWorld() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysWorld::addBody(std::shared_ptr<BasePart> part) {
|
|
||||||
syncBodyProperties(part);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysWorld::removeBody(std::shared_ptr<BasePart> part) {
|
|
||||||
JPH::BodyInterface& interface = worldImpl.GetBodyInterface();
|
|
||||||
|
|
||||||
// https://jrouwe.github.io/JoltPhysics/index.html#sleeping-bodies
|
|
||||||
// Wake sleeping bodies in its area before removing it
|
|
||||||
Vector3 aabbSize = part->GetAABB();
|
|
||||||
interface.ActivateBodiesInAABox(JPH::AABox(convert<JPH::Vec3>(part->position() - aabbSize), convert<JPH::Vec3>(part->position() + aabbSize)), {}, {});
|
|
||||||
|
|
||||||
interface.RemoveBody(part->rigidBody.bodyImpl->GetID());
|
|
||||||
interface.DestroyBody(part->rigidBody.bodyImpl->GetID());
|
|
||||||
part->rigidBody.bodyImpl = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
JPH::Shape* makeShape(std::shared_ptr<BasePart> basePart) {
|
|
||||||
if (std::shared_ptr<Part> part = std::dynamic_pointer_cast<Part>(basePart)) {
|
|
||||||
switch (part->shape) {
|
|
||||||
case PartType::Block:
|
|
||||||
return new JPH::BoxShape(convert<JPH::Vec3>(part->size / 2.f), JPH::cDefaultConvexRadius);
|
|
||||||
case PartType::Ball:
|
|
||||||
return new JPH::SphereShape(glm::min(part->size.X(), part->size.Y(), part->size.Z()) / 2.f);
|
|
||||||
case PartType::Cylinder:
|
|
||||||
return new JPH::RotatedTranslatedShape(JPH::Vec3(), JPH::Quat::sEulerAngles(JPH::Vec3(0, 0, JPH::JPH_PI * 0.5)), new JPH::CylinderShape(part->size.X() / 2.f, glm::min(part->size.Z(), part->size.Y()) / 2.f));
|
|
||||||
}
|
|
||||||
} else if (std::shared_ptr<WedgePart> part = std::dynamic_pointer_cast<WedgePart>(basePart)) {
|
|
||||||
return new JPH::ScaledShape(wedgeShape, convert<JPH::Vec3>(part->size / 2.f));
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysWorld::syncBodyProperties(std::shared_ptr<BasePart> part) {
|
|
||||||
JPH::BodyInterface& interface = worldImpl.GetBodyInterface();
|
|
||||||
|
|
||||||
JPH::EMotionType motionType = part->anchored ? JPH::EMotionType::Static : JPH::EMotionType::Dynamic;
|
|
||||||
JPH::EActivation activationMode = part->anchored ? JPH::EActivation::DontActivate : JPH::EActivation::Activate;
|
|
||||||
JPH::ObjectLayer objectLayer = !part->canCollide ? Layers::NOCOLLIDE : (part->anchored ? Layers::ANCHORED : Layers::DYNAMIC);
|
|
||||||
|
|
||||||
JPH::Body* body = part->rigidBody.bodyImpl;
|
|
||||||
|
|
||||||
// Generate a new rigidBody
|
|
||||||
if (body == nullptr) {
|
|
||||||
JPH::Shape* shape = makeShape(part);
|
|
||||||
JPH::BodyCreationSettings settings(shape, convert<JPH::Vec3>(part->position()), convert<JPH::Quat>((glm::quat)part->cframe.RotMatrix()), motionType, objectLayer);
|
|
||||||
settings.mAllowDynamicOrKinematic = true;
|
|
||||||
settings.mRestitution = 0.5;
|
|
||||||
|
|
||||||
body = interface.CreateBody(settings);
|
|
||||||
body->SetUserData((JPH::uint64)part.get());
|
|
||||||
part->rigidBody.bodyImpl = body;
|
|
||||||
|
|
||||||
interface.AddBody(body->GetID(), activationMode);
|
|
||||||
interface.SetLinearVelocity(body->GetID(), convert<JPH::Vec3>(part->velocity));
|
|
||||||
} else {
|
|
||||||
std::shared_ptr<Part> part2 = std::dynamic_pointer_cast<Part>(part);
|
|
||||||
bool shouldUpdateShape = (part2 != nullptr && part->rigidBody._lastShape != part2->shape) || part->rigidBody._lastSize == part->size;
|
|
||||||
|
|
||||||
if (shouldUpdateShape) {
|
|
||||||
// const JPH::Shape* oldShape = body->GetShape();
|
|
||||||
JPH::Shape* newShape = makeShape(part);
|
|
||||||
|
|
||||||
interface.SetShape(body->GetID(), newShape, true, activationMode);
|
|
||||||
// Seems like Jolt manages its memory for us, so we don't need the below
|
|
||||||
// delete oldShape;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface.SetObjectLayer(body->GetID(), objectLayer);
|
|
||||||
interface.SetMotionType(body->GetID(), motionType, activationMode);
|
|
||||||
interface.SetPositionRotationAndVelocity(body->GetID(), convert<JPH::Vec3>(part->position()), convert<JPH::Quat>((glm::quat)part->cframe.RotMatrix()), convert<JPH::Vec3>(part->velocity), /* Angular velocity is NYI: */ body->GetAngularVelocity());
|
|
||||||
}
|
|
||||||
|
|
||||||
part->rigidBody._lastSize = part->size;
|
|
||||||
if (std::shared_ptr<Part> part2 = std::dynamic_pointer_cast<Part>(part)) part->rigidBody._lastShape = part2->shape;
|
|
||||||
}
|
|
||||||
|
|
||||||
tu_time_t physTime;
|
|
||||||
void PhysWorld::step(float deltaTime) {
|
|
||||||
tu_time_t startTime = tu_clock_micros();
|
|
||||||
// Depending on the load, it may be necessary to call this with a differing collision step count
|
|
||||||
// 5 seems to be a good number supporting the high gravity
|
|
||||||
worldImpl.Update(deltaTime, 5, allocator, jobSystem);
|
|
||||||
|
|
||||||
JPH::BodyInterface& interface = worldImpl.GetBodyInterface();
|
|
||||||
JPH::BodyIDVector bodyIDs;
|
|
||||||
worldImpl.GetBodies(bodyIDs);
|
|
||||||
for (JPH::BodyID bodyID : bodyIDs) {
|
|
||||||
std::shared_ptr<BasePart> part = ((Instance*)interface.GetUserData(bodyID))->shared<BasePart>();
|
|
||||||
part->cframe = CFrame(convert<Vector3>(interface.GetPosition(bodyID)), convert<glm::quat>(interface.GetRotation(bodyID)));
|
|
||||||
}
|
|
||||||
|
|
||||||
physTime = tu_clock_micros() - startTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
PhysJoint PhysWorld::createJoint(PhysJointInfo& type, std::shared_ptr<BasePart> part0, std::shared_ptr<BasePart> part1) {
|
|
||||||
if (part0->rigidBody.bodyImpl == nullptr
|
|
||||||
|| part1->rigidBody.bodyImpl == nullptr
|
|
||||||
|| !part0->workspace()
|
|
||||||
|| !part1->workspace()
|
|
||||||
|| part0->workspace()->physicsWorld != shared_from_this()
|
|
||||||
|| part1->workspace()->physicsWorld != shared_from_this()
|
|
||||||
) { Logger::fatalError("Failed to create joint between two parts due to the call being invalid"); panic(); };
|
|
||||||
|
|
||||||
JPH::TwoBodyConstraint* constraint;
|
|
||||||
if (PhysFixedJointInfo* info = dynamic_cast<PhysFixedJointInfo*>(&type)) {
|
|
||||||
JPH::FixedConstraintSettings settings;
|
|
||||||
settings.mSpace = JPH::EConstraintSpace::LocalToBodyCOM;
|
|
||||||
settings.mPoint1 = convert<JPH::Vec3>(info->c0.Position());
|
|
||||||
settings.mAxisX1 = convert<JPH::Vec3>(info->c0.RightVector());
|
|
||||||
settings.mAxisY1 = convert<JPH::Vec3>(info->c0.UpVector());
|
|
||||||
settings.mPoint2 = convert<JPH::Vec3>(info->c1.Position());
|
|
||||||
settings.mAxisX2 = convert<JPH::Vec3>(info->c1.RightVector());
|
|
||||||
settings.mAxisY2 = convert<JPH::Vec3>(info->c1.UpVector());
|
|
||||||
constraint = settings.Create(*part0->rigidBody.bodyImpl, *part1->rigidBody.bodyImpl);
|
|
||||||
} else if (PhysRotatingJointInfo* info = dynamic_cast<PhysRotatingJointInfo*>(&type)) {
|
|
||||||
JPH::HingeConstraintSettings settings;
|
|
||||||
settings.mSpace = JPH::EConstraintSpace::LocalToBodyCOM;
|
|
||||||
settings.mPoint1 = convert<JPH::Vec3>(info->c0.Position());
|
|
||||||
settings.mNormalAxis1 = convert<JPH::Vec3>(info->c0.RightVector());
|
|
||||||
settings.mHingeAxis1 = convert<JPH::Vec3>(info->c0.LookVector());
|
|
||||||
settings.mPoint2 = convert<JPH::Vec3>(info->c1.Position());
|
|
||||||
settings.mNormalAxis2 = convert<JPH::Vec3>(info->c1.RightVector());
|
|
||||||
settings.mHingeAxis2 = convert<JPH::Vec3>(info->c1.LookVector());
|
|
||||||
// settings.mMotorSettings = JPH::MotorSettings(1.0f, 1.0f);
|
|
||||||
constraint = settings.Create(*part0->rigidBody.bodyImpl, *part1->rigidBody.bodyImpl);
|
|
||||||
if (info->motorized) {
|
|
||||||
static_cast<JPH::HingeConstraint*>(constraint)->SetMotorState(JPH::EMotorState::Velocity);
|
|
||||||
static_cast<JPH::HingeConstraint*>(constraint)->SetTargetAngularVelocity(-info->initialVelocity);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
panic();
|
|
||||||
}
|
|
||||||
|
|
||||||
worldImpl.AddConstraint(constraint);
|
|
||||||
return { constraint };
|
|
||||||
}
|
|
||||||
|
|
||||||
// WATCH OUT! This should only be called for HingeConstraints.
|
|
||||||
// Can't use dynamic_cast because TwoBodyConstraint is not virtual
|
|
||||||
void PhysJoint::setAngularVelocity(float velocity) {
|
|
||||||
JPH::HingeConstraint* constraint = static_cast<JPH::HingeConstraint*>(jointImpl);
|
|
||||||
if (!constraint) return;
|
|
||||||
constraint->SetTargetAngularVelocity(-velocity);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PhysWorld::destroyJoint(PhysJoint joint) {
|
|
||||||
worldImpl.RemoveConstraint(joint.jointImpl);
|
|
||||||
}
|
|
||||||
|
|
||||||
class PhysRayCastBodyFilter : public JPH::BodyFilter {
|
|
||||||
bool ShouldCollideLocked(const JPH::Body &inBody) const override {
|
|
||||||
std::shared_ptr<BasePart> part = ((Instance*)inBody.GetUserData())->shared<BasePart>();
|
|
||||||
|
|
||||||
// Ignore specifically "hidden" parts from raycast
|
|
||||||
// TODO: Replace this with a better system... Please.
|
|
||||||
if (!part->rigidBody.isCollisionsEnabled()) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::optional<const RaycastResult> PhysWorld::castRay(Vector3 point, Vector3 rotation, float maxLength, std::optional<RaycastFilter> filter, unsigned short categoryMaskBits) {
|
|
||||||
if (filter != std::nullopt) { Logger::fatalError("The filter property of PhysWorld::castRay is not yet implemented"); panic(); };
|
|
||||||
|
|
||||||
const JPH::BodyLockInterface& lockInterface = worldImpl.GetBodyLockInterfaceNoLock();
|
|
||||||
const JPH::BodyInterface& interface = worldImpl.GetBodyInterface();
|
|
||||||
const JPH::NarrowPhaseQuery& query = worldImpl.GetNarrowPhaseQuery();
|
|
||||||
|
|
||||||
// First we cast a ray to find a matching part
|
|
||||||
Vector3 end = point + rotation.Unit() * maxLength;
|
|
||||||
JPH::RRayCast ray { convert<JPH::Vec3>(point), convert<JPH::Vec3>(end) };
|
|
||||||
JPH::RayCastResult result;
|
|
||||||
PhysRayCastBodyFilter bodyFilter;
|
|
||||||
bool hitFound = query.CastRay(ray, result, {}, {}, bodyFilter);
|
|
||||||
|
|
||||||
// No matches found, return empty
|
|
||||||
if (!hitFound) return std::nullopt;
|
|
||||||
|
|
||||||
// Next we cast a ray to find the hit surface and its world position and normal
|
|
||||||
JPH::BodyID hitBodyId = result.mBodyID;
|
|
||||||
std::shared_ptr<BasePart> part = ((Instance*)interface.GetUserData(hitBodyId))->shared<BasePart>();
|
|
||||||
const JPH::Shape* shape = interface.GetShape(hitBodyId);
|
|
||||||
|
|
||||||
// Find the hit position and hence the surface normal of the shape at that specific point
|
|
||||||
Vector3 hitPosition = point + rotation.Unit() * (maxLength * result.mFraction);
|
|
||||||
JPH::Vec3 surfaceNormal = shape->GetSurfaceNormal(result.mSubShapeID2, convert<JPH::Vec3>(part->cframe.Inverse() * hitPosition));
|
|
||||||
Vector3 worldNormal = part->cframe.Rotation() * convert<Vector3>(surfaceNormal);
|
|
||||||
|
|
||||||
return RaycastResult {
|
|
||||||
.worldPoint = hitPosition,
|
|
||||||
.worldNormal = worldNormal,
|
|
||||||
.body = lockInterface.TryGetBody(hitBodyId),
|
|
||||||
.hitPart = part,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
uint BroadPhaseLayerInterface::GetNumBroadPhaseLayers() const {
|
|
||||||
return BPLayers::NUM_LAYERS;
|
|
||||||
}
|
|
||||||
|
|
||||||
JPH::BroadPhaseLayer BroadPhaseLayerInterface::GetBroadPhaseLayer(JPH::ObjectLayer inLayer) const {
|
|
||||||
switch (inLayer) {
|
|
||||||
case Layers::DYNAMIC: return BPLayers::DYNAMIC;
|
|
||||||
case Layers::ANCHORED: return BPLayers::ANCHORED;
|
|
||||||
case Layers::NOCOLLIDE: return BPLayers::NOCOLLIDE;
|
|
||||||
default: panic();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char * BroadPhaseLayerInterface::GetBroadPhaseLayerName(JPH::BroadPhaseLayer inLayer) const {
|
|
||||||
using T = JPH::BroadPhaseLayer::Type;
|
|
||||||
switch ((T)inLayer) {
|
|
||||||
case (T)BPLayers::DYNAMIC: return "DYNAMIC";
|
|
||||||
case (T)BPLayers::ANCHORED: return "ANCHORED";
|
|
||||||
case (T)BPLayers::NOCOLLIDE: return "NOCOLLIDE";
|
|
||||||
default: panic();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ObjectBroadPhaseFilter::ShouldCollide(JPH::ObjectLayer inLayer1, JPH::BroadPhaseLayer inLayer2) const {
|
|
||||||
using T = JPH::BroadPhaseLayer::Type;
|
|
||||||
switch ((T)inLayer2) {
|
|
||||||
case (T)BPLayers::DYNAMIC: return true;
|
|
||||||
case (T)BPLayers::ANCHORED: return true;
|
|
||||||
case (T)BPLayers::NOCOLLIDE: return false;
|
|
||||||
default: panic();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ObjectLayerPairFilter::ShouldCollide(JPH::ObjectLayer inLayer1, JPH::ObjectLayer inLayer2) const {
|
|
||||||
switch (inLayer1) {
|
|
||||||
case Layers::DYNAMIC:
|
|
||||||
return true;
|
|
||||||
case Layers::ANCHORED:
|
|
||||||
return inLayer2 == Layers::DYNAMIC;
|
|
||||||
case Layers::NOCOLLIDE:
|
|
||||||
return false;
|
|
||||||
default:
|
|
||||||
panic();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,126 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "datatypes/cframe.h"
|
|
||||||
#include "datatypes/vector.h"
|
|
||||||
#include "enum/part.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include <functional>
|
|
||||||
#include <list>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include <Jolt/Jolt.h>
|
|
||||||
#include <Jolt/Physics/Body/Body.h>
|
|
||||||
#include <Jolt/Physics/PhysicsSystem.h>
|
|
||||||
#include <Jolt/Physics/Constraints/TwoBodyConstraint.h>
|
|
||||||
|
|
||||||
class BasePart;
|
|
||||||
class PhysWorld;
|
|
||||||
|
|
||||||
struct PhysJointInfo { virtual ~PhysJointInfo() = default; protected: PhysJointInfo() = default; };
|
|
||||||
|
|
||||||
struct PhysFixedJointInfo : PhysJointInfo {
|
|
||||||
CFrame c0;
|
|
||||||
CFrame c1;
|
|
||||||
|
|
||||||
inline PhysFixedJointInfo(CFrame c0, CFrame c1) : c0(c0), c1(c1) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PhysRotatingJointInfo : PhysJointInfo {
|
|
||||||
CFrame c0;
|
|
||||||
CFrame c1;
|
|
||||||
bool motorized;
|
|
||||||
float initialVelocity;
|
|
||||||
|
|
||||||
inline PhysRotatingJointInfo(CFrame c0, CFrame c1) : c0(c0), c1(c1), motorized(false), initialVelocity(0.f){}
|
|
||||||
inline PhysRotatingJointInfo(CFrame c0, CFrame c1, float initialVelocity) : c0(c0), c1(c1), motorized(true), initialVelocity(initialVelocity) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class PhysWorld;
|
|
||||||
struct PhysJoint {
|
|
||||||
public:
|
|
||||||
JPH::TwoBodyConstraint* jointImpl;
|
|
||||||
|
|
||||||
void setAngularVelocity(float velocity);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RaycastResult;
|
|
||||||
class PhysRigidBody {
|
|
||||||
JPH::Body* bodyImpl = nullptr;
|
|
||||||
inline PhysRigidBody(JPH::Body* rigidBody) : bodyImpl(rigidBody) {}
|
|
||||||
Vector3 _lastSize;
|
|
||||||
PartType _lastShape;
|
|
||||||
bool collisionsEnabled = true;
|
|
||||||
|
|
||||||
friend PhysWorld;
|
|
||||||
friend RaycastResult;
|
|
||||||
public:
|
|
||||||
inline PhysRigidBody() {}
|
|
||||||
|
|
||||||
inline void setActive(bool active) { if (!bodyImpl) return; }
|
|
||||||
inline void setCollisionsEnabled(bool enabled) { collisionsEnabled = enabled; }
|
|
||||||
inline bool isCollisionsEnabled() { return collisionsEnabled; }
|
|
||||||
void updateCollider(std::shared_ptr<BasePart>);
|
|
||||||
};
|
|
||||||
|
|
||||||
// // Provides internal implementation-specific values from the raycast result
|
|
||||||
// struct RaycastResultInternal {
|
|
||||||
// rp::decimal hitFraction;
|
|
||||||
// rp::Collider* collider;
|
|
||||||
// };
|
|
||||||
|
|
||||||
struct RaycastResult {
|
|
||||||
Vector3 worldPoint;
|
|
||||||
Vector3 worldNormal;
|
|
||||||
PhysRigidBody body;
|
|
||||||
nullable std::shared_ptr<BasePart> hitPart;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum FilterResult {
|
|
||||||
TARGET, // The object is captured
|
|
||||||
BLOCK, // The object blocks any objects behind it, but is not captured
|
|
||||||
PASS, // The object is transparent, ignore it
|
|
||||||
};
|
|
||||||
|
|
||||||
class BasePart;
|
|
||||||
typedef std::function<FilterResult(std::shared_ptr<BasePart>)> RaycastFilter;
|
|
||||||
|
|
||||||
class BroadPhaseLayerInterface : public JPH::BroadPhaseLayerInterface {
|
|
||||||
uint GetNumBroadPhaseLayers() const override;
|
|
||||||
JPH::BroadPhaseLayer GetBroadPhaseLayer(JPH::ObjectLayer inLayer) const override;
|
|
||||||
const char * GetBroadPhaseLayerName(JPH::BroadPhaseLayer inLayer) const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ObjectBroadPhaseFilter : public JPH::ObjectVsBroadPhaseLayerFilter {
|
|
||||||
bool ShouldCollide(JPH::ObjectLayer inLayer1, JPH::BroadPhaseLayer inLayer2) const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ObjectLayerPairFilter : public JPH::ObjectLayerPairFilter {
|
|
||||||
bool ShouldCollide(JPH::ObjectLayer inLayer1, JPH::ObjectLayer inLayer2) const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PhysWorld : public std::enable_shared_from_this<PhysWorld> {
|
|
||||||
BroadPhaseLayerInterface broadPhaseLayerInterface;
|
|
||||||
ObjectBroadPhaseFilter objectBroadPhasefilter;
|
|
||||||
ObjectLayerPairFilter objectLayerPairFilter;
|
|
||||||
JPH::PhysicsSystem worldImpl;
|
|
||||||
std::list<std::shared_ptr<BasePart>> simulatedBodies;
|
|
||||||
|
|
||||||
public:
|
|
||||||
PhysWorld();
|
|
||||||
~PhysWorld();
|
|
||||||
|
|
||||||
void step(float deltaTime);
|
|
||||||
|
|
||||||
void addBody(std::shared_ptr<BasePart>);
|
|
||||||
void removeBody(std::shared_ptr<BasePart>);
|
|
||||||
|
|
||||||
PhysJoint createJoint(PhysJointInfo& type, std::shared_ptr<BasePart> part0, std::shared_ptr<BasePart> part1);
|
|
||||||
void destroyJoint(PhysJoint joint);
|
|
||||||
|
|
||||||
inline const std::list<std::shared_ptr<BasePart>>& getSimulatedBodies() { return simulatedBodies; }
|
|
||||||
void syncBodyProperties(std::shared_ptr<BasePart>);
|
|
||||||
std::optional<const RaycastResult> castRay(Vector3 point, Vector3 rotation, float maxLength, std::optional<RaycastFilter> filter, unsigned short categoryMaskBits);
|
|
||||||
};
|
|
||||||
|
|
||||||
void physicsInit();
|
|
||||||
void physicsDeinit();
|
|
|
@ -1,7 +1,8 @@
|
||||||
#include "rendering/shader.h"
|
#include "rendering/shader.h"
|
||||||
#include "rendering/texture.h"
|
#include "rendering/texture.h"
|
||||||
#include "timeutil.h"
|
#include "timeutil.h"
|
||||||
#include <glad/gl.h>
|
#include <GL/glew.h>
|
||||||
|
#include <GL/gl.h>
|
||||||
#include <glm/ext/vector_float4.hpp>
|
#include <glm/ext/vector_float4.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -10,8 +11,6 @@ extern Texture* debugFontTexture;
|
||||||
extern Shader* debugFontShader;
|
extern Shader* debugFontShader;
|
||||||
extern Shader* identityShader;
|
extern Shader* identityShader;
|
||||||
|
|
||||||
void drawRect(int x, int y, int width, int height, glm::vec4 color);
|
|
||||||
|
|
||||||
void drawChar(char c, int x, int y, float scale=1.f) {
|
void drawChar(char c, int x, int y, float scale=1.f) {
|
||||||
debugFontShader->use();
|
debugFontShader->use();
|
||||||
debugFontTexture->activate(1);
|
debugFontTexture->activate(1);
|
||||||
|
@ -42,6 +41,22 @@ void drawString(std::string str, int x, int y, float scale=1.f) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void drawRect(int x, int y, int w, int h, glm::vec4 color) {
|
||||||
|
identityShader->use();
|
||||||
|
identityShader->set("aColor", color);
|
||||||
|
|
||||||
|
float x0 = 2*float(x)/viewportWidth-1, y0 = 2*float(y)/viewportHeight-1, x1 = 2*float(x + w)/viewportWidth-1, y1 = 2*float(y + h)/viewportHeight-1;
|
||||||
|
float tmp;
|
||||||
|
tmp = -y0, y0 = -y1, y1 = tmp;
|
||||||
|
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
glVertex3f(x0, y0, 0);
|
||||||
|
glVertex3f(x1, y0, 0);
|
||||||
|
glVertex3f(x1, y1, 0);
|
||||||
|
glVertex3f(x0, y1, 0);
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
static tu_time_t lastTime;
|
static tu_time_t lastTime;
|
||||||
extern tu_time_t renderTime;
|
extern tu_time_t renderTime;
|
||||||
extern tu_time_t physTime;
|
extern tu_time_t physTime;
|
||||||
|
|