[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/workflows/msvcBuild.yml",
    "content": "name: MSVC\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n\njobs:\n  buildMSVC:\n\n    runs-on: windows-latest\n\n    steps:\n    - uses: actions/checkout@v2\n    - name: setup\n      run: install\\setup.bat\n    - name: make\n      run: cmake --build build --parallel\n\n"
  },
  {
    "path": ".github/workflows/ubuntuBuild.yml",
    "content": "name: Ubuntu\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n\njobs:\n  buildUbuntu:\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v2\n    - name: setup\n      run: sh install/setupUbuntu.sh\n    - name: make\n      run: cmake --build build --parallel\n\n"
  },
  {
    "path": ".gitignore",
    "content": "\n# Files possibly generated by Physics3D\nres/.properties\nimgui.ini\nres/imgui.ini\n*.parts\n*.nativeParts\n*.world\n*.obj\n*.bobj\n\n# Visual Studio\n**.vcxproj.filters\n**.vcxproj.user\n**.aps\n*.db\n*.opendb\n*.TMP\n.vs/\nDebug/\nRelease/\nx64/\nx86/\nlib/\nipch/\n\n# Visual studio code\n.vscode/\n\n# CLion\n.idea/\ncmake-build-debug/\n\n# Other build systems\ninclude/\nvcpkg/\nbuild/\nbuild2/\nbuild_debug/\n\n\n*.log\n\nSHADERed/\n\nres/xcf/\n\n*.ruleset\n\nHexinator.lnk\n\nPhysics3D.sln.DotSettings.user\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.10)\n\nproject(Physics3D-application VERSION 1.0)\n\nmessage(STATUS \"Build type: ${CMAKE_BUILD_TYPE}\")\nmessage(STATUS \"Building with: ${CMAKE_CXX_COMPILER_ID}\")\n\nset(CMAKE_CXX_STANDARD 20)\nset(CMAKE_CXX_STANDARD_REQUIRED True)\n\nif (CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n\tset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} /arch:AVX2\")\n\n\tset(CMAKE_CXX_FLAGS_RELEASE \"${CMAKE_CXX_FLAGS_RELEASE} /O2 /Oi /ot /GL\")\nelse()\n\tset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -march=native -mtune=native\")\n\n\tset(CMAKE_CXX_FLAGS_DEBUG \"${CMAKE_CXX_FLAGS_DEBUG} -g  -fsanitize=address\")\n\n\tset(OpenGL_GL_PREFERENCE \"GLVND\")\n\n\t#running benchmarks showed this to be a pessimization\n\t#set(CMAKE_INTERPROCEDURAL_OPTIMIZATION True)\n\t#surprisingly, also a pessimization\n\t#set(CMAKE_CXX_FLAGS  \"${CMAKE_CXX_FLAGS} -ffast-math\")\nendif()\n\nfind_package(glfw3 3.2 REQUIRED)\nfind_package(OpenGL REQUIRED)\nfind_package(GLEW REQUIRED)\nfind_package(Freetype REQUIRED)\nfind_package(Threads REQUIRED)\n\ninclude_directories(PRIVATE \"${GLFW_DIR}/include\")\ninclude_directories(PRIVATE \"${GLEW_DIR}/include\")\ninclude_directories(PRIVATE \"${FREETYPE_INCLUDE_DIRS}\")\ninclude_directories(PRIVATE \"include\")\n\n\nadd_library(util STATIC \n  util/terminalColor.cpp\n  util/log.cpp\n  util/properties.cpp\n  util/stringUtil.cpp\n  util/fileUtils.cpp\n  util/valueCycle.cpp\n  util/systemVariables.cpp\n\n  util/resource/resource.cpp\n  util/resource/resourceLoader.cpp\n  util/resource/resourceManager.cpp\n)\n\nif (CMAKE_CXX_COMPILER_ID STREQUAL GNU)\n\ttarget_link_libraries(util stdc++fs)\nendif()\n\n# Adds the Physics3D library\nadd_subdirectory(Physics3D)\n\nadd_executable(benchmarks\n  benchmarks/benchmark.cpp\n  benchmarks/basicWorld.cpp\n  benchmarks/complexObjectBenchmark.cpp\n  benchmarks/getBoundsPerformance.cpp\n  benchmarks/manyCubesBenchmark.cpp\n  benchmarks/worldBenchmark.cpp\n  benchmarks/rotationBenchmark.cpp\n  benchmarks/ecsBenchmark.cpp\n  benchmarks/threadResponseTime.cpp\n)\n\nadd_library(imguiInclude STATIC\n  include/imgui/imgui.cpp\n  include/imgui/imgui_demo.cpp\n  include/imgui/imgui_draw.cpp\n  include/imgui/imgui_impl_glfw.cpp\n  include/imgui/imgui_impl_opengl3.cpp\n  include/imgui/imgui_widgets.cpp\n)\n\nadd_library(graphics STATIC\n  graphics/glfwUtils.cpp\n  graphics/bindable.cpp\n  graphics/core.cpp\n  graphics/font.cpp\n  graphics/renderer.cpp\n  graphics/texture.cpp\n  graphics/extendedTriangleMesh.cpp\n  graphics/meshRegistry.cpp\n\n  graphics/buffers/bufferLayout.cpp\n  graphics/buffers/frameBuffer.cpp\n  graphics/buffers/indexBuffer.cpp\n  graphics/buffers/renderBuffer.cpp\n  graphics/buffers/vertexArray.cpp\n  graphics/buffers/vertexBuffer.cpp\n\n  graphics/debug/guiDebug.cpp\n  graphics/debug/profilerUI.cpp\n  graphics/debug/visualDebug.cpp\n\n  graphics/gui/gui.cpp\n  graphics/gui/guiUtils.cpp\n  graphics/gui/imgui/imguiStyle.cpp\n\n  graphics/mesh/abstractMesh.cpp\n  graphics/mesh/arrayMesh.cpp\n  graphics/mesh/indexedMesh.cpp\n  graphics/mesh/pointMesh.cpp\n  graphics/mesh/vectorMesh.cpp\n\n  graphics/path/path.cpp\n  graphics/path/path3D.cpp\n\n  graphics/resource/fontResource.cpp\n  graphics/resource/shaderResource.cpp\n  graphics/resource/textureResource.cpp\n\n  graphics/shader/shader.cpp\n  graphics/shader/lexer.cpp\n  graphics/shader/parser.cpp\n  graphics/shader/shaders.cpp\n  graphics/shader/propertiesParser.cpp\n)\n\nadd_library(engine STATIC\n  engine/core.cpp\n\n  engine/input/inputHandler.cpp\n  engine/input/keyboard.cpp\n  engine/input/modifiers.cpp\n  engine/input/mouse.cpp\n\n  engine/io/export.cpp\n  engine/io/import.cpp\n\n  engine/layer/layerStack.cpp\n\n  engine/tool/toolManager.cpp\n\n  engine/options/keyboardOptions.cpp\n\n  engine/resource/meshResource.cpp\n)\n\nadd_executable(tests \n  tests/testsMain.cpp\n\n  tests/estimateMotion.cpp\n  tests/testValues.cpp\n  tests/generators.cpp\n\n  tests/mathTests.cpp\n  tests/rotationTests.cpp\n  tests/motionTests.cpp\n  tests/geometryTests.cpp\n  tests/estimationTests.cpp\n  tests/constraintTests.cpp\n  tests/jointTests.cpp\n  tests/boundsTree2Tests.cpp\n  tests/guiTests.cpp\n  tests/indexedShapeTests.cpp\n  tests/physicalStructureTests.cpp\n  tests/physicsTests.cpp\n  tests/inertiaTests.cpp\n  tests/testFrameworkConsistencyTests.cpp\n  tests/ecsTests.cpp\n  tests/lexerTests.cpp\n)\n\nadd_executable(application\n  application/core.cpp\n  application/application.cpp\n  application/eventHandler.cpp\n  application/extendedPart.cpp\n  application/resources.cpp\n  application/worldBuilder.cpp\n  application/builtinWorlds.cpp\n  application/worlds.cpp\n\n  application/input/standardInputHandler.cpp\n  application/input/playerController.cpp\n\n  application/io/saveDialog.cpp\n  application/io/serialization.cpp\n\n  application/layer/constraintLayer.cpp\n  application/layer/debugLayer.cpp\n  application/layer/debugOverlay.cpp\n  application/layer/guiLayer.cpp\n  application/layer/modelLayer.cpp\n  application/layer/pickerLayer.cpp\n  application/layer/postprocessLayer.cpp\n  application/layer/skyboxLayer.cpp\n  application/layer/testLayer.cpp\n  application/layer/cameraLayer.cpp\n  application/layer/shadowLayer.cpp\n  application/layer/imguiLayer.cpp\n\n  application/picker/ray.cpp\n  application/picker/selection.cpp\n  application/picker/tools/selectionTool.cpp\n  application/picker/tools/translationTool.cpp\n  application/picker/tools/rotationTool.cpp\n  application/picker/tools/scaleTool.cpp\n  application/picker/tools/regionSelectionTool.cpp\n  application/picker/tools/attachmentTool.cpp\n  application/picker/tools/fixedConstraintTool.cpp\n  application/picker/tools/motorConstraintTool.cpp\n  application/picker/tools/pistonConstraintTool.cpp\n  application/picker/tools/elasticLinkTool.cpp\n  application/picker/tools/magneticLinkTool.cpp\n  application/picker/tools/springLinkTool.cpp\n  application/picker/tools/alignmentLinkTool.cpp\n  application/picker/tools/pathTool.cpp\n  \n  application/shader/shaders.cpp\n  application/shader/basicShader.cpp\n  application/shader/shaderBase.cpp\n\n  application/view/camera.cpp\n  application/view/frames.cpp\n  application/view/screen.cpp\n  application/view/debugFrame.cpp\n  application/view/layerFrame.cpp\n  application/view/ecsFrame.cpp\n  application/view/propertiesFrame.cpp\n  application/view/resourceFrame.cpp\n  application/view/environmentFrame.cpp\n  application/view/toolbarFrame.cpp\n)\n\ntarget_include_directories(tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})\ntarget_include_directories(benchmarks PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})\ntarget_include_directories(graphics PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})\ntarget_include_directories(engine PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})\ntarget_include_directories(application PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})\ntarget_include_directories(graphics PRIVATE \"${CMAKE_CURRENT_SOURCE_DIR}/graphics\")\ntarget_include_directories(engine PRIVATE \"${CMAKE_CURRENT_SOURCE_DIR}/engine\")\ntarget_include_directories(application PRIVATE \"${CMAKE_CURRENT_SOURCE_DIR}/application\")\n\ntarget_link_libraries(tests util)\ntarget_link_libraries(tests Physics3D)\ntarget_link_libraries(tests graphics)\ntarget_link_libraries(tests engine)\ntarget_link_libraries(tests Threads::Threads)\n\ntarget_link_libraries(benchmarks util)\ntarget_link_libraries(benchmarks Physics3D)\ntarget_link_libraries(benchmarks Threads::Threads)\n\ntarget_link_libraries(graphics imguiInclude)\ntarget_link_libraries(graphics Physics3D)\n\ntarget_link_libraries(engine graphics)\n\ntarget_link_libraries(application util)\ntarget_link_libraries(application Physics3D)\ntarget_link_libraries(application graphics)\ntarget_link_libraries(application engine)\n\n#target_link_libraries(application ${GLFW_LIBRARIES})\ntarget_link_libraries(application glfw)\n#target_link_libraries(application ${OPENGL_LIBRARIES})\ntarget_link_libraries(application OpenGL::GL)\n#target_link_libraries(application ${GLEW_LIBRARIES})\ntarget_link_libraries(application GLEW::GLEW)\ntarget_link_libraries(application ${FREETYPE_LIBRARIES})\ntarget_link_libraries(application Threads::Threads)\n\n# install(TARGETS benchmarks DESTINATION bin)\n\n"
  },
  {
    "path": "LICENSE.md",
    "content": "MIT License\n\nCopyright (c) 2018 ThePhysicsGuys\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Physics3D/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.10)\n\nproject(Physics3D VERSION 0.9)\n\n\nset(CMAKE_CXX_STANDARD 23)\nset(CMAKE_CXX_STANDARD_REQUIRED True)\n\nif (CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n\t# set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} /arch:AVX2\")\n\n\tset(CMAKE_CXX_FLAGS_RELEASE \"${CMAKE_CXX_FLAGS_RELEASE} /O2 /Oi /ot /GL\")\nelse()\n\tset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -march=native -mtune=native -fno-math-errno\")\n\n\tset(CMAKE_CXX_FLAGS_RELEASE \"${CMAKE_CXX_FLAGS_RELEASE} -Ofast\")\n\n\t#running benchmarks showed this to be a pessimization\n\t#set(CMAKE_INTERPROCEDURAL_OPTIMIZATION True)\n\t#surprisingly, also a pessimization\n\t#set(CMAKE_CXX_FLAGS  \"${CMAKE_CXX_FLAGS} -ffast-math\")\nendif()\n\n\nadd_library(Physics3D STATIC \n  part.cpp\n  physical.cpp\n  rigidBody.cpp\n  layer.cpp\n  world.cpp\n  worldPhysics.cpp\n  inertia.cpp\n\n  math/linalg/eigen.cpp\n  math/linalg/trigonometry.cpp\n\n  geometry/computationBuffer.cpp\n  geometry/convexShapeBuilder.cpp\n  geometry/genericIntersection.cpp\n  geometry/indexedShape.cpp\n  geometry/intersection.cpp\n  geometry/triangleMesh.cpp\n  geometry/triangleMeshSSE.cpp\n  geometry/triangleMeshSSE4.cpp\n  geometry/triangleMeshAVX.cpp\n  geometry/polyhedron.cpp\n  geometry/shape.cpp\n  geometry/shapeBuilder.cpp\n  geometry/shapeClass.cpp\n  geometry/shapeCreation.cpp\n  geometry/builtinShapeClasses.cpp\n  geometry/shapeLibrary.cpp\n\n  datastructures/aligned_alloc.cpp\n\n  boundstree/boundsTree.cpp\n  boundstree/boundsTreeAVX.cpp\n  boundstree/filters/visibilityFilter.cpp\n  \n  hardconstraints/fixedConstraint.cpp\n  hardconstraints/hardConstraint.cpp\n  hardconstraints/hardPhysicalConnection.cpp\n  hardconstraints/motorConstraint.cpp\n  hardconstraints/controller/sineWaveController.cpp\n  \n  constraints/constraint.cpp\n  constraints/constraintGroup.cpp\n  constraints/ballConstraint.cpp\n  constraints/hingeConstraint.cpp\n  constraints/barConstraint.cpp\n  \n  softlinks/softLink.cpp\n  softlinks/springLink.cpp\n  softlinks/elasticLink.cpp\n  softlinks/magneticLink.cpp\n  softlinks/alignmentLink.cpp\n  \n  externalforces/directionalGravity.cpp\n  externalforces/externalForce.cpp\n  externalforces/magnetForce.cpp\n  \n  threading/upgradeableMutex.cpp\n  threading/physicsThread.cpp\n  \n  misc/debug.cpp\n  misc/cpuid.cpp\n  misc/validityHelper.cpp\n  misc/physicsProfiler.cpp\n  \n  misc/serialization/serialization.cpp\n  misc/serialization/serializeBasicTypes.cpp\n)\n\nif (CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n  set_source_files_properties(geometry/triangleMeshSSE.cpp PROPERTIES COMPILE_FLAGS /arch:SSE2)\n  set_source_files_properties(geometry/triangleMeshSSE4.cpp PROPERTIES COMPILE_FLAGS /arch:SSE2)\n  set_source_files_properties(geometry/triangleMeshAVX.cpp PROPERTIES COMPILE_FLAGS /arch:AVX2)\nelse()\n  set_source_files_properties(geometry/triangleMeshSSE.cpp PROPERTIES COMPILE_FLAGS -msse2) # Up to SSE2\n  set_source_files_properties(geometry/triangleMeshSSE4.cpp PROPERTIES COMPILE_FLAGS -msse4.1) # Up to SSE4_1\n  set_source_files_properties(geometry/triangleMeshAVX.cpp PROPERTIES COMPILE_FLAGS -mfma) # Includes AVX, AVX2 and FMA\nendif()\n\n"
  },
  {
    "path": "Physics3D/Physics3D.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <VCProjectVersion>15.0</VCProjectVersion>\n    <ProjectGuid>{DC20CBAC-AB67-4A0C-BBE2-65DC81DEF289}</ProjectGuid>\n    <RootNamespace>physics</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n    <ProjectName>Physics3D</ProjectName>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>DynamicLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <TargetName>$(ProjectName)</TargetName>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <TargetName>$(ProjectName)</TargetName>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n      <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n      <PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <Link>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n      <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>\n      <PreprocessorDefinitions>_MBCS;NDEBUG;CATCH_INTERSECTION_ERRORS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"inertia.cpp\" />\n    <ClCompile Include=\"part.cpp\" />\n    <ClCompile Include=\"physical.cpp\" />\n    <ClCompile Include=\"rigidBody.cpp\" />\n    <ClCompile Include=\"layer.cpp\" />\n    <ClCompile Include=\"world.cpp\" />\n    <ClCompile Include=\"worldPhysics.cpp\" />\n    <ClCompile Include=\"math\\linalg\\eigen.cpp\" />\n    <ClCompile Include=\"math\\linalg\\trigonometry.cpp\" />\n    <ClCompile Include=\"geometry\\computationBuffer.cpp\" />\n    <ClCompile Include=\"geometry\\convexShapeBuilder.cpp\" />\n    <ClCompile Include=\"geometry\\indexedShape.cpp\" />\n    <ClCompile Include=\"geometry\\genericIntersection.cpp\" />\n    <ClCompile Include=\"geometry\\intersection.cpp\" />\n    <ClCompile Include=\"geometry\\polyhedron.cpp\" />\n    <ClCompile Include=\"geometry\\shape.cpp\" />\n    <ClCompile Include=\"geometry\\shapeBuilder.cpp\" />\n    <ClCompile Include=\"geometry\\shapeClass.cpp\" />\n    <ClCompile Include=\"geometry\\builtinShapeClasses.cpp\" />\n    <ClCompile Include=\"geometry\\shapeCreation.cpp\" />\n    <ClCompile Include=\"geometry\\triangleMesh.cpp\" />\n    <ClCompile Include=\"geometry\\shapeLibrary.cpp\" />\n    <ClCompile Include=\"geometry\\triangleMeshAVX.cpp\">\n      <EnableEnhancedInstructionSet Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">AdvancedVectorExtensions2</EnableEnhancedInstructionSet>\n      <EnableEnhancedInstructionSet Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">AdvancedVectorExtensions2</EnableEnhancedInstructionSet>\n    </ClCompile>\n    <ClCompile Include=\"geometry\\triangleMeshSSE.cpp\">\n      <EnableEnhancedInstructionSet Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">StreamingSIMDExtensions2</EnableEnhancedInstructionSet>\n      <EnableEnhancedInstructionSet Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">StreamingSIMDExtensions2</EnableEnhancedInstructionSet>\n    </ClCompile>\n    <ClCompile Include=\"geometry\\triangleMeshSSE4.cpp\">\n      <EnableEnhancedInstructionSet Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">StreamingSIMDExtensions2</EnableEnhancedInstructionSet>\n      <EnableEnhancedInstructionSet Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">StreamingSIMDExtensions2</EnableEnhancedInstructionSet>\n    </ClCompile>\n    <ClCompile Include=\"datastructures\\aligned_alloc.cpp\" />\n    <ClCompile Include=\"boundstree\\boundsTree.cpp\" />\n    <ClCompile Include=\"boundstree\\filters\\visibilityFilter.cpp\" />\n    <ClCompile Include=\"softlinks\\alignmentLink.cpp\" />\n    <ClCompile Include=\"softlinks\\elasticLink.cpp\" />\n    <ClCompile Include=\"softlinks\\magneticLink.cpp\" />\n    <ClCompile Include=\"softlinks\\softLink.cpp\" />\n    <ClCompile Include=\"softlinks\\springLink.cpp\" />\n    <ClCompile Include=\"constraints\\constraint.cpp\" />\n    <ClCompile Include=\"constraints\\ballConstraint.cpp\" />\n    <ClCompile Include=\"constraints\\hingeConstraint.cpp\" />\n    <ClCompile Include=\"constraints\\barConstraint.cpp\" />\n    <ClCompile Include=\"constraints\\constraintGroup.cpp\" />\n    <ClCompile Include=\"hardconstraints\\hardConstraint.cpp\" />\n    <ClCompile Include=\"hardconstraints\\hardPhysicalConnection.cpp\" />\n    <ClCompile Include=\"hardconstraints\\fixedConstraint.cpp\" />\n    <ClCompile Include=\"hardconstraints\\motorConstraint.cpp\" />\n    <ClCompile Include=\"hardconstraints\\controller\\sineWaveController.cpp\" />\n    <ClCompile Include=\"externalforces\\externalForce.cpp\" />\n    <ClCompile Include=\"externalforces\\directionalGravity.cpp\" />\n    <ClCompile Include=\"externalforces\\magnetForce.cpp\" />\n    <ClCompile Include=\"threading\\upgradeableMutex.cpp\" />\n    <ClCompile Include=\"threading\\physicsThread.cpp\" />\n    <ClCompile Include=\"misc\\cpuid.cpp\" />\n    <ClCompile Include=\"misc\\physicsProfiler.cpp\" />\n    <ClCompile Include=\"misc\\validityHelper.cpp\" />\n    <ClCompile Include=\"misc\\debug.cpp\" />\n    <ClCompile Include=\"misc\\serialization\\serializeBasicTypes.cpp\" />\n    <ClCompile Include=\"misc\\serialization\\serialization.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"layer.h\" />\n    <ClInclude Include=\"inertia.h\" />\n    <ClInclude Include=\"motion.h\" />\n    <ClInclude Include=\"part.h\" />\n    <ClInclude Include=\"physical.h\" />\n    <ClInclude Include=\"relativeMotion.h\" />\n    <ClInclude Include=\"rigidBody.h\" />\n    <ClInclude Include=\"worldPhysics.h\" />\n    <ClInclude Include=\"world.h\" />\n    <ClInclude Include=\"worldIteration.h\" />\n    <ClInclude Include=\"colissionBuffer.h\" />\n    <ClInclude Include=\"math\\boundingBox.h\" />\n    <ClInclude Include=\"math\\bounds.h\" />\n    <ClInclude Include=\"math\\cframe.h\" />\n    <ClInclude Include=\"math\\constants.h\" />\n    <ClInclude Include=\"math\\fix.h\" />\n    <ClInclude Include=\"math\\globalCFrame.h\" />\n    <ClInclude Include=\"math\\globalTransform.h\" />\n    <ClInclude Include=\"math\\mathUtil.h\" />\n    <ClInclude Include=\"math\\position.h\" />\n    <ClInclude Include=\"math\\taylorExpansion.h\" />\n    <ClInclude Include=\"math\\predefinedTaylorExpansions.h\" />\n    <ClInclude Include=\"math\\rotation.h\" />\n    <ClInclude Include=\"math\\transform.h\" />\n    <ClInclude Include=\"math\\utils.h\" />\n    <ClInclude Include=\"math\\ray.h\" />\n    <ClInclude Include=\"math\\linalg\\commonMatrices.h\" />\n    <ClInclude Include=\"math\\linalg\\eigen.h\" />\n    <ClInclude Include=\"math\\linalg\\largeMatrix.h\" />\n    <ClInclude Include=\"math\\linalg\\largeMatrixAlgorithms.h\" />\n    <ClInclude Include=\"math\\linalg\\vec.h\" />\n    <ClInclude Include=\"math\\linalg\\mat.h\" />\n    <ClInclude Include=\"math\\linalg\\quat.h\" />\n    <ClInclude Include=\"math\\linalg\\trigonometry.h\" />\n    <ClInclude Include=\"geometry\\scalableInertialMatrix.h\" />\n    <ClInclude Include=\"geometry\\computationBuffer.h\" />\n    <ClInclude Include=\"geometry\\convexShapeBuilder.h\" />\n    <ClInclude Include=\"geometry\\genericCollidable.h\" />\n    <ClInclude Include=\"geometry\\indexedShape.h\" />\n    <ClInclude Include=\"geometry\\genericIntersection.h\" />\n    <ClInclude Include=\"geometry\\shapeCreation.h\" />\n    <ClInclude Include=\"geometry\\triangleMesh.h\" />\n    <ClInclude Include=\"geometry\\triangleMeshCommon.h\" />\n    <ClInclude Include=\"geometry\\intersection.h\" />\n    <ClInclude Include=\"geometry\\builtinShapeClasses.h\" />\n    <ClInclude Include=\"geometry\\polyhedron.h\" />\n    <ClInclude Include=\"geometry\\shape.h\" />\n    <ClInclude Include=\"geometry\\shapeBuilder.h\" />\n    <ClInclude Include=\"geometry\\shapeClass.h\" />\n    <ClInclude Include=\"geometry\\shapeLibrary.h\" />\n    <ClInclude Include=\"datastructures\\alignedPtr.h\" />\n    <ClInclude Include=\"datastructures\\buffers.h\" />\n    <ClInclude Include=\"datastructures\\iteratorEnd.h\" />\n    <ClInclude Include=\"datastructures\\iteratorFactory.h\" />\n    <ClInclude Include=\"datastructures\\monotonicTree.h\" />\n    <ClInclude Include=\"datastructures\\compactPtrDataPair.h\" />\n    <ClInclude Include=\"datastructures\\sharedArray.h\" />\n    <ClInclude Include=\"datastructures\\uniqueArrayPtr.h\" />\n    <ClInclude Include=\"datastructures\\unmanagedArray.h\" />\n    <ClInclude Include=\"datastructures\\unorderedVector.h\" />\n    <ClInclude Include=\"datastructures\\smartPointers.h\" />\n    <ClInclude Include=\"datastructures\\aligned_alloc.h\" />\n    <ClInclude Include=\"datastructures\\parallelArray.h\" />\n    <ClInclude Include=\"boundstree\\boundsTree.h\" />\n    <ClInclude Include=\"boundstree\\filters\\outOfBoundsFilter.h\" />\n    <ClInclude Include=\"boundstree\\filters\\rayIntersectsBoundsFilter.h\" />\n    <ClInclude Include=\"boundstree\\filters\\visibilityFilter.h\" />\n    <ClInclude Include=\"softlinks\\softLink.h\" />\n    <ClInclude Include=\"softlinks\\springLink.h\" />\n    <ClInclude Include=\"softlinks\\alignmentLink.h\" />\n    <ClInclude Include=\"softlinks\\elasticLink.h\" />\n    <ClInclude Include=\"softlinks\\magneticLink.h\" />\n    <ClInclude Include=\"constraints\\constraint.h\" />\n    <ClInclude Include=\"constraints\\constraintImpl.h\" />\n    <ClInclude Include=\"constraints\\ballConstraint.h\" />\n    <ClInclude Include=\"constraints\\hingeConstraint.h\" />\n    <ClInclude Include=\"constraints\\barConstraint.h\" />\n    <ClInclude Include=\"constraints\\constraintGroup.h\" />\n    <ClInclude Include=\"hardconstraints\\hardConstraint.h\" />\n    <ClInclude Include=\"hardconstraints\\constraintTemplates.h\" />\n    <ClInclude Include=\"hardconstraints\\fixedConstraint.h\" />\n    <ClInclude Include=\"hardconstraints\\hardPhysicalConnection.h\" />\n    <ClInclude Include=\"hardconstraints\\motorConstraint.h\" />\n    <ClInclude Include=\"hardconstraints\\sinusoidalPistonConstraint.h\" />\n    <ClInclude Include=\"hardconstraints\\controller\\constController.h\" />\n    <ClInclude Include=\"hardconstraints\\controller\\sineWaveController.h\" />\n    <ClInclude Include=\"externalforces\\externalForce.h\" />\n    <ClInclude Include=\"externalforces\\directionalGravity.h\" />\n    <ClInclude Include=\"externalforces\\magnetForce.h\" />\n    <ClInclude Include=\"threading\\sharedLockGuard.h\" />\n    <ClInclude Include=\"threading\\threadPool.h\" />\n    <ClInclude Include=\"threading\\upgradeableMutex.h\" />\n    <ClInclude Include=\"threading\\physicsThread.h\" />\n    <ClInclude Include=\"misc\\debug.h\" />\n    <ClInclude Include=\"misc\\unreachable.h\" />\n    <ClInclude Include=\"misc\\toString.h\" />\n    <ClInclude Include=\"misc\\validityHelper.h\" />\n    <ClInclude Include=\"misc\\catchable_assert.h\" />\n    <ClInclude Include=\"misc\\cpuid.h\" />\n    <ClInclude Include=\"misc\\physicsProfiler.h\" />\n    <ClInclude Include=\"misc\\profiling.h\" />\n    <ClInclude Include=\"misc\\serialization\\dynamicSerialize.h\" />\n    <ClInclude Include=\"misc\\serialization\\serializeBasicTypes.h\" />\n    <ClInclude Include=\"misc\\serialization\\sharedObjectSerializer.h\" />\n    <ClInclude Include=\"misc\\serialization\\serialization.h\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "Physics3D/boundstree/boundsTree.cpp",
    "content": "#include \"boundsTree.h\"\n\n\n#include \"../datastructures/aligned_alloc.h\"\n\nnamespace P3D {\n// naive implementation, to be optimized\nBoundsTemplate<float> TrunkSIMDHelperFallback::getTotalBounds(const TreeTrunk& trunk, int upTo) {\n\tassert(upTo >= 1 && upTo <= BRANCH_FACTOR);\n\tBoundsTemplate<float> totalBounds = trunk.getBoundsOfSubNode(0);\n\tfor(int i = 1; i < upTo; i++) {\n\t\ttotalBounds = unionOfBounds(totalBounds, trunk.getBoundsOfSubNode(i));\n\t}\n\treturn totalBounds;\n}\n// naive implementation, to be optimized\nBoundsTemplate<float> TrunkSIMDHelperFallback::getTotalBoundsWithout(const TreeTrunk& trunk, int upTo, int without) {\n\tassert(upTo >= 2 && upTo <= BRANCH_FACTOR); // size must be at least 2, can't compute otherwise\n\tassert(without >= 0 && without < BRANCH_FACTOR);\n\tif(without == 0) {\n\t\tBoundsTemplate<float> totalBounds = trunk.getBoundsOfSubNode(1);\n\t\tfor(int i = 2; i < upTo; i++) {\n\t\t\ttotalBounds = unionOfBounds(totalBounds, trunk.getBoundsOfSubNode(i));\n\t\t}\n\t\treturn totalBounds;\n\t} else {\n\t\tBoundsTemplate<float> totalBounds = trunk.getBoundsOfSubNode(0);\n\t\tfor(int i = 1; i < upTo; i++) {\n\t\t\tif(i == without) continue;\n\t\t\ttotalBounds = unionOfBounds(totalBounds, trunk.getBoundsOfSubNode(i));\n\t\t}\n\t\treturn totalBounds;\n\t}\n}\n\nBoundsArray<BRANCH_FACTOR> TrunkSIMDHelperFallback::getAllTotalBoundsWithout(const TreeTrunk& trunk, int upTo) {\n\tassert(upTo >= 2 && upTo <= BRANCH_FACTOR); // size must be at least 2, can't compute otherwise\n\tBoundsArray<BRANCH_FACTOR> result;\n\t{\n\t\tBoundsTemplate<float> totalBounds0 = trunk.getBoundsOfSubNode(1);\n\t\tfor(int i = 2; i < upTo; i++) {\n\t\t\ttotalBounds0 = unionOfBounds(totalBounds0, trunk.getBoundsOfSubNode(i));\n\t\t}\n\t\tresult.setBounds(0, totalBounds0);\n\t}\n\tfor(int without = 1; without < upTo; without++) {\n\t\tBoundsTemplate<float> totalBounds = trunk.getBoundsOfSubNode(0);\n\t\tfor(int i = 2; i < upTo; i++) {\n\t\t\tif(i == without) continue;\n\t\t\ttotalBounds = unionOfBounds(totalBounds, trunk.getBoundsOfSubNode(i));\n\t\t}\n\t\tresult.setBounds(without, totalBounds);\n\t}\n\n\treturn result;\n}\n\nstd::array<bool, BRANCH_FACTOR> TrunkSIMDHelperFallback::getAllContainsBounds(const TreeTrunk& trunk, const BoundsTemplate<float>& boundsToContain) {\n\tstd::array<bool, BRANCH_FACTOR> contained;\n\tfor(int i = 0; i < BRANCH_FACTOR; i++) {\n\t\tBoundsTemplate<float> subNodeBounds = trunk.getBoundsOfSubNode(i);\n\t\tcontained[i] = subNodeBounds.contains(boundsToContain);\n\t}\n\treturn contained;\n}\n\nstd::array<float, BRANCH_FACTOR> TrunkSIMDHelperFallback::computeAllCosts(const TreeTrunk& trunk) {\n\tstd::array<float, BRANCH_FACTOR> costs;\n\tfor(int i = 0; i < BRANCH_FACTOR; i++) {\n\t\tBoundsTemplate<float> subNodeBounds = trunk.getBoundsOfSubNode(i);\n\t\tcosts[i] = computeCost(subNodeBounds);\n\t}\n\treturn costs;\n}\n\nstd::array<float, BRANCH_FACTOR> TrunkSIMDHelperFallback::computeAllCombinationCosts(const BoundsArray<BRANCH_FACTOR>& boundsArr, const BoundsTemplate<float>& boundsExtention) {\n\tstd::array<float, BRANCH_FACTOR> costs;\n\tfor(int i = 0; i < BRANCH_FACTOR; i++) {\n\t\tBoundsTemplate<float> subNodeBounds = boundsArr.getBounds(i);\n\t\tcosts[i] = computeCost(unionOfBounds(boundsExtention, subNodeBounds));\n\t}\n\treturn costs;\n}\n\nstd::pair<int, int> TrunkSIMDHelperFallback::computeFurthestObjects(const BoundsArray<BRANCH_FACTOR * 2>& boundsArray, int size) {\n\tstd::pair<int, int> furthestObjects{0, 1};\n\tfloat biggestCost = -std::numeric_limits<float>::infinity();\n\tfor(int i = 0; i < size - 1; i++) {\n\t\tBoundsTemplate<float> iBounds = boundsArray.getBounds(i);\n\t\tfor(int j = i + 1; j < size; j++) {\n\t\t\tBoundsTemplate<float> jBounds = boundsArray.getBounds(j);\n\n\t\t\tfloat cost = computeCost(unionOfBounds(iBounds, jBounds));\n\t\t\tif(cost > biggestCost) {\n\t\t\t\tbiggestCost = cost;\n\t\t\t\tfurthestObjects.first = i;\n\t\t\t\tfurthestObjects.second = j;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn furthestObjects;\n}\n\nint TrunkSIMDHelperFallback::getLowestCombinationCost(const TreeTrunk& trunk, const BoundsTemplate<float>& boundsExtention, int nodeSize) {\n\tstd::array<float, BRANCH_FACTOR> costs = TrunkSIMDHelperFallback::computeAllCombinationCosts(trunk.subNodeBounds, boundsExtention);\n\tfloat bestCost = costs[0];\n\tint bestIndex = 0;\n\tfor(int i = 1; i < nodeSize; i++) {\n\t\tif(costs[i] < bestCost) {\n\t\t\tbestIndex = i;\n\t\t\tbestCost = costs[i];\n\t\t}\n\t}\n\treturn bestIndex;\n}\n\nstd::array<bool, BRANCH_FACTOR> TrunkSIMDHelperFallback::computeOverlapsWith(const TreeTrunk& trunk, int trunkSize, const BoundsTemplate<float>& bounds) {\n\tstd::array<bool, BRANCH_FACTOR> result;\n\n\tfor(int i = 0; i < trunkSize; i++) {\n\t\tresult[i] = intersects(trunk.getBoundsOfSubNode(i), bounds);\n\t}\n\n\treturn result;\n}\n\nOverlapMatrix TrunkSIMDHelperFallback::computeBoundsOverlapMatrix(const TreeTrunk& trunkA, int trunkASize, const TreeTrunk& trunkB, int trunkBSize) {\n\tOverlapMatrix result;\n\tfor(int a = 0; a < trunkASize; a++) {\n\t\tBoundsTemplate<float> aBounds = trunkA.getBoundsOfSubNode(a);\n\t\tfor(int b = 0; b < trunkBSize; b++) {\n\t\t\tBoundsTemplate<float> bBounds = trunkB.getBoundsOfSubNode(b);\n\t\t\tresult[a][b] = intersects(aBounds, bBounds);\n\t\t}\n\t}\n\treturn result;\n}\n\nOverlapMatrix TrunkSIMDHelperFallback::computeInternalBoundsOverlapMatrix(const TreeTrunk& trunk, int trunkSize) {\n\tOverlapMatrix result;\n\tfor(int a = 0; a < trunkSize; a++) {\n\t\tBoundsTemplate<float> aBounds = trunk.getBoundsOfSubNode(a);\n\t\tfor(int b = a+1; b < trunkSize; b++) {\n\t\t\tBoundsTemplate<float> bBounds = trunk.getBoundsOfSubNode(b);\n\t\t\tresult[a][b] = intersects(aBounds, bBounds);\n\t\t}\n\t}\n\treturn result;\n}\n\nstd::array<float, BRANCH_FACTOR> TrunkSIMDHelperFallback::computeAllExtentionCosts(const TreeTrunk& trunk, int trunkSize, const BoundsTemplate<float>& extraBounds) {\n\tstd::array<float, BRANCH_FACTOR> resultingCosts;\n\tfor(int i = 0; i < trunkSize; i++) {\n\t\tresultingCosts[i] = computeAdditionCost(trunk.getBoundsOfSubNode(i), extraBounds);\n\t}\n\treturn resultingCosts;\n}\n\nint TrunkSIMDHelperFallback::transferNodes(TreeTrunk& srcTrunk, int srcTrunkStart, int srcTrunkEnd, TreeTrunk& destTrunk, int destTrunkSize) {\n\tfor(int i = srcTrunkStart; i < srcTrunkEnd; i++) {\n\t\tdestTrunk.setSubNode(destTrunkSize, std::move(srcTrunk.subNodes[i]), srcTrunk.getBoundsOfSubNode(i));\n\t\tdestTrunkSize++;\n\t}\n\treturn destTrunkSize;\n}\n\nBoundsArray<BRANCH_FACTOR * 2> TrunkSIMDHelperFallback::combineBoundsArrays(const TreeTrunk& trunkA, int trunkASize, const TreeTrunk& trunkB, int trunkBSize) {\n\tBoundsArray<BRANCH_FACTOR * 2> result;\n\tfor(int i = 0; i < trunkASize; i++) {\n\t\tresult.setBounds(i, trunkA.getBoundsOfSubNode(i));\n\t}\n\tfor(int i = 0; i < trunkBSize; i++) {\n\t\tresult.setBounds(trunkASize + i, trunkB.getBoundsOfSubNode(i));\n\t}\n\treturn result;\n}\n\n// returns true if modified\nbool TrunkSIMDHelperFallback::exchangeNodesBetween(TreeTrunk& trunkA, int& trunkASize, TreeTrunk& trunkB, int& trunkBSize) {\n\tint totalSize = trunkASize + trunkBSize;\n\t// if this is not the case, we could've just merged the nodes, this is handled in another function\n\t// if totalSize was BRANCH_FACTOR + 1 we could've moved all but one node from one trunk to the other, also handled elsewhere\n\tassert(totalSize >= BRANCH_FACTOR + 2); \n\tBoundsArray<BRANCH_FACTOR * 2> allBounds = TrunkSIMDHelperFallback::combineBoundsArrays(trunkA, trunkASize, trunkB, trunkBSize);\n\tstd::pair<int, int> furthestObjects = TrunkSIMDHelperFallback::computeFurthestObjects(allBounds, totalSize);\n\n\tBoundsTemplate<float> aBounds = allBounds.getBounds(furthestObjects.first);\n\tBoundsTemplate<float> bBounds = allBounds.getBounds(furthestObjects.second);\n\n\tint aResultSize = 0; \n\tint bResultSize = 0; \n\tint aResult[BRANCH_FACTOR * 2];\n\tint bResult[BRANCH_FACTOR * 2];\n\n\t// positive if costA < costB\n\tfloat allDeltaCosts[BRANCH_FACTOR * 2];\n\tfor(int i = 0; i < totalSize; i++) {\n\t\tBoundsTemplate<float> bounds = allBounds.getBounds(i);\n\t\tfloat costA = computeCost(unionOfBounds(aBounds, bounds));\n\t\tfloat costB = computeCost(unionOfBounds(bBounds, bounds));\n\n\t\tallDeltaCosts[i] = costB - costA;\n\t}\n\n\tfor(int i = 0; i < totalSize; i++) {\n\t\tif(allDeltaCosts[i] >= 0.0) {\n\t\t\taResult[aResultSize++] = i;\n\t\t} else {\n\t\t\tbResult[bResultSize++] = i;\n\t\t}\n\t}\n\n\tif(aResultSize > BRANCH_FACTOR) {\n\t\t// move least costly elements from a to b (least costly cost is closest to 0)\n\t\tdo {\n\t\t\tint worstIndex = 0; \n\t\t\tfloat worstCost = allDeltaCosts[aResult[0]];\n\t\t\tfor(int i = 1; i < aResultSize; i++) {\n\t\t\t\tfloat cost = allDeltaCosts[aResult[i]];\n\t\t\t\tif(cost < worstCost) {\n\t\t\t\t\tworstIndex = i;\n\t\t\t\t\tworstCost = cost;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbResult[bResultSize++] = aResult[worstIndex];\n\t\t\taResult[worstIndex] = aResult[--aResultSize];\n\t\t} while(aResultSize > BRANCH_FACTOR);\n\t} else if(bResultSize > BRANCH_FACTOR) {\n\t\t// move least costly elements from b to a (least costly cost is closest to 0)\n\t\tdo {\n\t\t\tint worstIndex = 0;\n\t\t\tfloat worstCost = allDeltaCosts[bResult[0]];\n\t\t\tfor(int i = 1; i < bResultSize; i++) {\n\t\t\t\tfloat cost = allDeltaCosts[bResult[i]];\n\t\t\t\tif(cost > worstCost) { // these costs are all negative\n\t\t\t\t\tworstIndex = i;\n\t\t\t\t\tworstCost = cost;\n\t\t\t\t}\n\t\t\t}\n\t\t\taResult[aResultSize++] = bResult[worstIndex];\n\t\t\tbResult[worstIndex] = bResult[--bResultSize];\n\t\t} while(bResultSize > BRANCH_FACTOR);\n\t}\n\n\tassert(aResultSize + bResultSize == totalSize);\n\tassert(aResultSize <= BRANCH_FACTOR && bResultSize <= BRANCH_FACTOR);\n\tassert(aResultSize >= 2 && bResultSize >= 2); // Guaranteed by totalSize >= BRANCH_FACTOR + 2 && aResultSize <= BRANCH_FACTOR && bResultSize <= BRANCH_FACTOR\n\n\t// checks to see if a change needs to be made\n\tbool a0ComesFromA = aResult[0] < trunkASize; \n\tbool b0ComesFromA = bResult[0] < trunkASize;\n\tif(a0ComesFromA != b0ComesFromA) {// they differ in origin\n\t\tfor(int i = 1; i < aResultSize; i++) {\n\t\t\tbool comesFromA = aResult[i] < trunkASize;\n\t\t\tif(comesFromA != a0ComesFromA) {\n\t\t\t\tgoto wasChanged;\n\t\t\t}\n\t\t}\n\t\tfor(int i = 1; i < bResultSize; i++) {\n\t\t\tbool comesFromA = bResult[i] < trunkASize;\n\t\t\tif(comesFromA != b0ComesFromA) {\n\t\t\t\tgoto wasChanged;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\twasChanged:;\n\n\tTreeNodeRef allSubNodes[BRANCH_FACTOR * 2];\n\tfor(int i = 0; i < trunkASize; i++) {\n\t\tallSubNodes[i] = std::move(trunkA.subNodes[i]);\n\t}\n\tfor(int i = 0; i < trunkBSize; i++) {\n\t\tallSubNodes[i+trunkASize] = std::move(trunkB.subNodes[i]);\n\t}\n\n\tfor(int i = 0; i < aResultSize; i++) {\n\t\tint from = aResult[i];\n\t\ttrunkA.setSubNode(i, std::move(allSubNodes[from]), allBounds.getBounds(from));\n\t}\n\tfor(int i = 0; i < bResultSize; i++) {\n\t\tint from = bResult[i];\n\t\ttrunkB.setSubNode(i, std::move(allSubNodes[from]), allBounds.getBounds(from));\n\t}\n\n\ttrunkASize = aResultSize;\n\ttrunkBSize = bResultSize;\n\treturn true;\n}\n\n// returns the new size of this node, to be applied to the caller\nint addRecursive(TrunkAllocator& allocator, TreeTrunk& curTrunk, int curTrunkSize, TreeNodeRef&& newNode, const BoundsTemplate<float>& bounds) {\n\tassert(curTrunkSize >= 0 && curTrunkSize <= BRANCH_FACTOR);\n\tif(curTrunkSize == BRANCH_FACTOR) {\n\t\tint chosenNode = TrunkSIMDHelperFallback::getLowestCombinationCost(curTrunk, bounds, curTrunkSize);\n\n\t\tTreeNodeRef& chosen = curTrunk.subNodes[chosenNode];\n\t\tBoundsTemplate<float> oldSubNodeBounds = curTrunk.getBoundsOfSubNode(chosenNode);\n\n\t\t// can be inserted into the trunkNode\n\t\tif(chosen.isTrunkNode() && !chosen.isGroupHead()) {\n\t\t\tint newSize = addRecursive(allocator, chosen.asTrunk(), chosen.getTrunkSize(), std::move(newNode), bounds);\n\t\t\tchosen.setTrunkSize(newSize);\n\t\t} else {\n\t\t\tTreeTrunk* newTrunk = allocator.allocTrunk();\n\t\t\tnewTrunk->setSubNode(0, std::move(chosen), oldSubNodeBounds);\n\t\t\tnewTrunk->setSubNode(1, std::move(newNode), bounds);\n\n\t\t\tchosen = TreeNodeRef(newTrunk, 2, false);\n\t\t}\n\t\tcurTrunk.setBoundsOfSubNode(chosenNode, unionOfBounds(oldSubNodeBounds, bounds));\n\t\treturn BRANCH_FACTOR;\n\t} else {\n\t\tcurTrunk.setSubNode(curTrunkSize, std::move(newNode), bounds);\n\t\treturn curTrunkSize + 1;\n\t}\n}\n\nbool containsObjectRecursive(const TreeTrunk& trunk, int trunkSize, const void* object, const BoundsTemplate<float>& bounds) {\n\tassert(trunkSize >= 0 && trunkSize <= BRANCH_FACTOR);\n\tstd::array<bool, BRANCH_FACTOR> couldContain = TrunkSIMDHelperFallback::getAllContainsBounds(trunk, bounds);\n\tfor(int i = 0; i < trunkSize; i++) {\n\t\tif(!couldContain[i]) continue; \n\n\t\tconst TreeNodeRef& subNode = trunk.subNodes[i];\n\t\tif(subNode.isTrunkNode()) {\n\t\t\tif(containsObjectRecursive(subNode.asTrunk(), subNode.getTrunkSize(), object, bounds)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} else {\n\t\t\tif(subNode.asObject() == object) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n}\n\n// returns new trunkSize if removed, -1 if not removed\nint removeRecursive(TrunkAllocator& allocator, TreeTrunk& curTrunk, int curTrunkSize, const void* objectToRemove, const BoundsTemplate<float>& bounds) {\n\tassert(curTrunkSize >= 0 && curTrunkSize <= BRANCH_FACTOR);\n\tstd::array<bool, BRANCH_FACTOR> couldContain = TrunkSIMDHelperFallback::getAllContainsBounds(curTrunk, bounds);\n\tfor(int i = 0; i < curTrunkSize; i++) {\n\t\tif(!couldContain[i]) continue;\n\n\t\tTreeNodeRef& subNode = curTrunk.subNodes[i];\n\t\tif(subNode.isTrunkNode()) {\n\t\t\tTreeTrunk& subNodeTrunk = subNode.asTrunk();\n\t\t\tassert(subNode.getTrunkSize() >= 2);\n\t\t\tint newSubNodeTrunkSize = removeRecursive(allocator, subNodeTrunk, subNode.getTrunkSize(), objectToRemove, bounds);\n\t\t\tassert(newSubNodeTrunkSize >= 1 || newSubNodeTrunkSize == -1);\n\t\t\tif(newSubNodeTrunkSize != -1) {\n\t\t\t\tif(newSubNodeTrunkSize == 1) {\n\t\t\t\t\t// remove reduntant trunk\n\t\t\t\t\tbool wasGroupHead = subNode.isGroupHead();\n\t\t\t\t\tsubNode = std::move(subNodeTrunk.subNodes[0]);\n\t\t\t\t\tcurTrunk.setBoundsOfSubNode(i, subNodeTrunk.getBoundsOfSubNode(0));\n\t\t\t\t\tif(wasGroupHead && subNode.isTrunkNode()) {\n\t\t\t\t\t\tsubNode.makeGroupHead(); // in the rare case that it removes Z in a node that is a group like this: GH[TN[X,Y],Z]. Without this the grouping would be lost\n\t\t\t\t\t}\n\t\t\t\t\tallocator.freeTrunk(&subNodeTrunk);\n\t\t\t\t} else {\n\t\t\t\t\tcurTrunk.setBoundsOfSubNode(i, TrunkSIMDHelperFallback::getTotalBounds(subNodeTrunk, newSubNodeTrunkSize));\n\t\t\t\t\tsubNode.setTrunkSize(newSubNodeTrunkSize);\n\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\treturn curTrunkSize;\n\t\t\t}\n\t\t} else {\n\t\t\tif(subNode.asObject() == objectToRemove) {\n\t\t\t\tcurTrunk.moveSubNode(curTrunkSize - 1, i);\n\t\t\t\treturn curTrunkSize - 1;\n\t\t\t}\n\t\t}\n\t}\n\treturn -1;\n}\n\nstruct TreeGrab {\n\tint resultingGroupSize;\n\tTreeNodeRef nodeRef;\n\tBoundsTemplate<float> nodeBounds;\n\n\tTreeGrab() : resultingGroupSize(-1) {}\n\tTreeGrab(int resultingGroupSize, TreeNodeRef&& nodeRef, const BoundsTemplate<float>& nodeBounds) :\n\t\tresultingGroupSize(resultingGroupSize),\n\t\tnodeRef(std::move(nodeRef)),\n\t\tnodeBounds(nodeBounds) {}\n};\n\n// returns new trunkSize if removed, -1 if not removed\nstatic TreeGrab grabGroupRecursive(TrunkAllocator& allocator, TreeTrunk& curTrunk, int curTrunkSize, const void* groupRepresentative, const BoundsTemplate<float>& representativeBounds) {\n\tassert(curTrunkSize >= 0 && curTrunkSize <= BRANCH_FACTOR);\n\tstd::array<bool, BRANCH_FACTOR> couldContain = TrunkSIMDHelperFallback::getAllContainsBounds(curTrunk, representativeBounds);\n\tfor(int i = 0; i < curTrunkSize; i++) {\n\t\tif(!couldContain[i]) continue;\n\n\t\tTreeNodeRef& subNode = curTrunk.subNodes[i];\n\t\tif(subNode.isTrunkNode()) {\n\t\t\tTreeTrunk& subNodeTrunk = subNode.asTrunk();\n\t\t\tsize_t trunkSize = subNode.getTrunkSize();\n\t\t\tassert(trunkSize >= 2);\n\n\t\t\tif(subNode.isGroupHead()) {\n\t\t\t\tif(containsObjectRecursive(subNodeTrunk, trunkSize, groupRepresentative, representativeBounds)) {\n\t\t\t\t\t// found group, now remove it\n\t\t\t\t\tTreeNodeRef subNodeCopy = std::move(subNode);\n\t\t\t\t\tcurTrunk.moveSubNode(curTrunkSize - 1, i);\n\t\t\t\t\treturn TreeGrab(curTrunkSize - 1, std::move(subNodeCopy), curTrunk.getBoundsOfSubNode(i));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// try \n\t\t\t\tTreeGrab recursiveResult = grabGroupRecursive(allocator, subNodeTrunk, subNode.getTrunkSize(), groupRepresentative, representativeBounds);\n\t\t\t\tint newSubNodeTrunkSize = recursiveResult.resultingGroupSize;\n\t\t\t\tassert(newSubNodeTrunkSize >= 1 || newSubNodeTrunkSize == -1);\n\t\t\t\tif(newSubNodeTrunkSize != -1) {\n\t\t\t\t\tif(newSubNodeTrunkSize == 1) {\n\t\t\t\t\t\t// remove reduntant trunk\n\t\t\t\t\t\tcurTrunk.setSubNode(i, std::move(subNodeTrunk.subNodes[0]), subNodeTrunk.getBoundsOfSubNode(0));\n\t\t\t\t\t\tallocator.freeTrunk(&subNodeTrunk);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcurTrunk.setBoundsOfSubNode(i, TrunkSIMDHelperFallback::getTotalBounds(subNodeTrunk, newSubNodeTrunkSize));\n\t\t\t\t\t\tsubNode.setTrunkSize(newSubNodeTrunkSize);\n\t\t\t\t\t}\n\n\t\t\t\t\trecursiveResult.resultingGroupSize = curTrunkSize;\n\t\t\t\t\treturn recursiveResult;\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else {\n\t\t\tif(subNode.asObject() == groupRepresentative) {\n\t\t\t\tTreeNodeRef subNodeCopy = std::move(subNode);\n\t\t\t\tBoundsTemplate<float> subNodeBounds = curTrunk.getBoundsOfSubNode(i);\n\t\t\t\tcurTrunk.moveSubNode(curTrunkSize - 1, i);\n\t\t\t\treturn TreeGrab(curTrunkSize - 1, std::move(subNodeCopy), subNodeBounds);\n\t\t\t}\n\t\t}\n\t}\n\treturn TreeGrab();\n}\n\nconst TreeNodeRef* getGroupRecursive(const TreeTrunk& curTrunk, int curTrunkSize, const void* groupRepresentative, const BoundsTemplate<float>& representativeBounds) {\n\tassert(curTrunkSize >= 0 && curTrunkSize <= BRANCH_FACTOR);\n\tstd::array<bool, BRANCH_FACTOR> couldContain = TrunkSIMDHelperFallback::getAllContainsBounds(curTrunk, representativeBounds);\n\tfor(int i = 0; i < curTrunkSize; i++) {\n\t\tif(!couldContain[i]) continue;\n\n\t\tconst TreeNodeRef& subNode = curTrunk.subNodes[i];\n\t\tif(subNode.isTrunkNode()) {\n\t\t\tconst TreeTrunk& subNodeTrunk = subNode.asTrunk();\n\t\t\tsize_t subTrunkSize = subNode.getTrunkSize();\n\t\t\tassert(subTrunkSize >= 2);\n\n\t\t\tif(subNode.isGroupHead()) {\n\t\t\t\tif(containsObjectRecursive(subNodeTrunk, subTrunkSize, groupRepresentative, representativeBounds)) {\n\t\t\t\t\treturn &subNode;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst TreeNodeRef* recursiveFound = getGroupRecursive(subNodeTrunk, subTrunkSize, groupRepresentative, representativeBounds);\n\t\t\t\tif(recursiveFound != nullptr) {\n\t\t\t\t\treturn recursiveFound;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tif(subNode.asObject() == groupRepresentative) {\n\t\t\t\treturn &subNode;\n\t\t\t}\n\t\t}\n\t}\n\treturn nullptr;\n}\n\n// also frees starting trunk\nstatic void freeTrunksRecursive(TrunkAllocator& alloc, TreeTrunk& curTrunk, int curTrunkSize) {\n\tfor(int i = 0; i < curTrunkSize; i++) {\n\t\tTreeNodeRef& subNode = curTrunk.subNodes[i];\n\t\tif(subNode.isTrunkNode()) {\n\t\t\tTreeTrunk& subTrunk = subNode.asTrunk();\n\t\t\tfreeTrunksRecursive(alloc, subTrunk, subNode.getTrunkSize());\n\t\t}\n\t}\n\talloc.freeTrunk(&curTrunk);\n}\n\n// expects a function of the form void(void* object, const BoundsTemplate<float>& bounds)\ntemplate<typename Func>\nstatic void forEachRecurseWithBounds(const TreeTrunk& curTrunk, int curTrunkSize, const Func& func) {\n\tfor(int i = 0; i < curTrunkSize; i++) {\n\t\tconst TreeNodeRef& subNode = curTrunk.subNodes[i];\n\t\tif(subNode.isTrunkNode()) {\n\t\t\tforEachRecurseWithBounds(subNode.asTrunk(), subNode.getTrunkSize(), func);\n\t\t} else {\n\t\t\tfunc(subNode.asObject(), curTrunk.getBoundsOfSubNode(i));\n\t\t}\n\t}\n}\n\n// returns true if the group that is inserted into is found\n// deletes all trunknodes of the destroyed group with the provided allocator\nstatic bool insertGroupIntoGroup(TrunkAllocator& sourceAlloc, TrunkAllocator& destinationAlloc, TreeTrunk& baseTrunk, int baseTrunkSize, const void* groupToAddToRep, const BoundsTemplate<float>& groupToAddToRepBounds, TreeNodeRef&& groupToDestroy, const BoundsTemplate<float>& groupToDestroyBounds) {\n\tbool groupWasFound = modifyGroupRecursive(destinationAlloc, baseTrunk, baseTrunkSize, groupToAddToRep, groupToAddToRepBounds, [&sourceAlloc, &destinationAlloc, &groupToDestroy, &groupToDestroyBounds](TreeNodeRef& group, const BoundsTemplate<float>& groupBounds) {\n\t\tTreeTrunk* trunk;\n\t\tint trunkSize;\n\t\tif(group.isLeafNode()) {\n\t\t\ttrunk = destinationAlloc.allocTrunk();\n\t\t\ttrunk->setSubNode(0, std::move(group), groupBounds);\n\t\t\ttrunkSize = 1;\n\t\t} else {\n\t\t\ttrunk = &group.asTrunk();\n\t\t\ttrunkSize = group.getTrunkSize();\n\t\t}\n\n\t\tif(groupToDestroy.isTrunkNode()) {\n\t\t\tforEachRecurseWithBounds(groupToDestroy.asTrunk(), groupToDestroy.getTrunkSize(), [&](void* object, const BoundsTemplate<float>& bounds) {\n\t\t\t\ttrunkSize = addRecursive(destinationAlloc, *trunk, trunkSize, TreeNodeRef(object), bounds);\n\t\t\t});\n\t\t} else {\n\t\t\ttrunkSize = addRecursive(destinationAlloc, *trunk, trunkSize, TreeNodeRef(groupToDestroy.asObject()), groupToDestroyBounds);\n\t\t}\n\n\t\tgroup = TreeNodeRef(trunk, trunkSize, true);\n\n\t\tif(groupToDestroy.isTrunkNode()) {\n\t\t\tTreeTrunk& destroyTrunk = groupToDestroy.asTrunk();\n\t\t\tfreeTrunksRecursive(sourceAlloc, destroyTrunk, groupToDestroy.getTrunkSize());\n\t\t}\n\n\t\treturn TrunkSIMDHelperFallback::getTotalBounds(*trunk, trunkSize);\n\t});\n\treturn groupWasFound;\n}\n\n\nTrunkAllocator::TrunkAllocator() : allocationCount(0) {}\nTrunkAllocator::~TrunkAllocator() {\n\tassert(this->allocationCount == 0);\n}\nTrunkAllocator::TrunkAllocator(TrunkAllocator&& other) noexcept : allocationCount(other.allocationCount) {\n\tother.allocationCount = 0;\n}\nTrunkAllocator& TrunkAllocator::operator=(TrunkAllocator&& other) noexcept {\n\tstd::swap(this->allocationCount, other.allocationCount);\n\treturn *this;\n}\n\nTreeTrunk* TrunkAllocator::allocTrunk() {\n\tthis->allocationCount++;\n\tstd::cout << \"allocTrunk \" << this->allocationCount << std::endl;\n\treturn static_cast<TreeTrunk*>(aligned_malloc(sizeof(TreeTrunk), alignof(TreeTrunk)));\n}\nvoid TrunkAllocator::freeTrunk(TreeTrunk* trunk) {\n\tthis->allocationCount--;\n\tstd::cout << \"freeTrunk \" << this->allocationCount << std::endl;\n\taligned_free(trunk);\n}\nvoid TrunkAllocator::freeAllTrunks(TreeTrunk& baseTrunk, int baseTrunkSize) {\n\tfor(int i = 0; i < baseTrunkSize; i++) {\n\t\tTreeNodeRef& subNode = baseTrunk.subNodes[i];\n\t\tif(subNode.isTrunkNode()) {\n\t\t\tfreeTrunksRecursive(*this, subNode.asTrunk(), subNode.getTrunkSize());\n\t\t}\n\t}\n}\n\nBoundsTreePrototype::BoundsTreePrototype() : baseTrunk(), baseTrunkSize(0) {}\nBoundsTreePrototype::~BoundsTreePrototype() {\n\tthis->clear();\n}\nvoid BoundsTreePrototype::addGroupTrunk(TreeTrunk* newTrunk, int newTrunkSize) {\n\tthis->baseTrunkSize = addRecursive(allocator, baseTrunk, baseTrunkSize, TreeNodeRef(newTrunk, newTrunkSize, true), TrunkSIMDHelperFallback::getTotalBounds(*newTrunk, newTrunkSize));\n}\nvoid BoundsTreePrototype::add(void* newObject, const BoundsTemplate<float>& bounds) {\n\tthis->baseTrunkSize = addRecursive(allocator, baseTrunk, baseTrunkSize, TreeNodeRef(newObject), bounds);\n}\nvoid BoundsTreePrototype::addToGroup(void* newObject, const BoundsTemplate<float>& newObjectBounds, const void* groupRepresentative, const BoundsTemplate<float>& groupRepBounds) {\n\tbool foundGroup = modifyGroupRecursive(allocator, baseTrunk, baseTrunkSize, groupRepresentative, groupRepBounds, [this, newObject, &newObjectBounds](TreeNodeRef& groupNode, const BoundsTemplate<float>& groupNodeBounds) {\n\t\tassert(groupNode.isGroupHeadOrLeaf());\n\t\tif(groupNode.isTrunkNode()) {\n\t\t\tTreeTrunk& groupTrunk = groupNode.asTrunk();\n\t\t\tint resultingSize = addRecursive(allocator, groupTrunk, groupNode.getTrunkSize(), TreeNodeRef(newObject), newObjectBounds);\n\t\t\tgroupNode.setTrunkSize(resultingSize);\n\t\t\treturn TrunkSIMDHelperFallback::getTotalBounds(groupTrunk, resultingSize);\n\t\t} else {\n\t\t\tTreeTrunk* newTrunkNode = allocator.allocTrunk();\n\t\t\tnewTrunkNode->setSubNode(0, std::move(groupNode), groupNodeBounds);\n\t\t\tnewTrunkNode->setSubNode(1, TreeNodeRef(newObject), newObjectBounds);\n\t\t\tgroupNode = TreeNodeRef(newTrunkNode, 2, true);\n\t\t\treturn TrunkSIMDHelperFallback::getTotalBounds(*newTrunkNode, 2);\n\t\t}\n\t});\n\tif(!foundGroup) {\n\t\tthrow \"Group not found!\";\n\t}\n}\nvoid BoundsTreePrototype::mergeGroups(const void* groupRepA, const BoundsTemplate<float>& repABounds, const void* groupRepB, const BoundsTemplate<float>& repBBounds) {\n\tTreeGrab grabbed = grabGroupRecursive(this->allocator, this->baseTrunk, this->baseTrunkSize, groupRepA, repABounds);\n\tif(grabbed.resultingGroupSize == -1) {\n\t\tthrow \"groupRepA not found!\";\n\t}\n\tthis->baseTrunkSize = grabbed.resultingGroupSize;\n\n\tbool groupBWasFound = insertGroupIntoGroup(this->allocator, this->allocator, this->baseTrunk, this->baseTrunkSize, groupRepB, repBBounds, std::move(grabbed.nodeRef), grabbed.nodeBounds);\n\n\tif(!groupBWasFound) {\n\t\tthrow \"groupRepB not found!\";\n\t}\n}\n\nvoid BoundsTreePrototype::transferGroupTo(const void* groupRep, const BoundsTemplate<float>& groupRepBounds, BoundsTreePrototype& destinationTree) {\n\tTreeGrab grabbed = grabGroupRecursive(this->allocator, this->baseTrunk, this->baseTrunkSize, groupRep, groupRepBounds);\n\tif(grabbed.resultingGroupSize == -1) {\n\t\tthrow \"groupRep not found!\";\n\t}\n\tthis->baseTrunkSize = grabbed.resultingGroupSize;\n\n\tbool groupBWasFound = addRecursive(destinationTree.allocator, destinationTree.baseTrunk, destinationTree.baseTrunkSize, std::move(grabbed.nodeRef), grabbed.nodeBounds);\n\tassert(groupBWasFound);\n}\nvoid BoundsTreePrototype::remove(const void* objectToRemove, const BoundsTemplate<float>& bounds) {\n\tint resultingBaseSize = removeRecursive(allocator, baseTrunk, baseTrunkSize, objectToRemove, bounds);\n\tif(resultingBaseSize != -1) {\n\t\tthis->baseTrunkSize = resultingBaseSize;\n\t} else {\n\t\tthrow \"Object not found!\";\n\t}\n}\nbool BoundsTreePrototype::contains(const void* object, const BoundsTemplate<float>& bounds) const {\n\treturn containsObjectRecursive(baseTrunk, baseTrunkSize, object, bounds);\n}\n\nbool BoundsTreePrototype::groupContains(const void* object, const BoundsTemplate<float>& bounds, const void* groupRep, const BoundsTemplate<float>& groupRepBounds) const {\n\tconst TreeNodeRef* groupFound = getGroupRecursive(this->baseTrunk, this->baseTrunkSize, groupRep, groupRepBounds);\n\tif(!groupFound) {\n\t\tthrow \"Group not found!\";\n\t}\n\tif(groupFound->isTrunkNode()) {\n\t\treturn containsObjectRecursive(groupFound->asTrunk(), groupFound->getTrunkSize(), object, bounds);\n\t} else {\n\t\treturn groupFound->asObject() == object;\n\t}\n}\n\nstatic bool updateObjectBoundsRecurive(TreeTrunk& curTrunk, int curTrunkSize, const void* object, const BoundsTemplate<float>& originalBounds, const BoundsTemplate<float>& newBounds) {\n\tassert(curTrunkSize >= 0 && curTrunkSize <= BRANCH_FACTOR);\n\tstd::array<bool, BRANCH_FACTOR> couldContain = TrunkSIMDHelperFallback::getAllContainsBounds(curTrunk, originalBounds);\n\tfor(int i = 0; i < curTrunkSize; i++) {\n\t\tif(!couldContain[i]) continue;\n\n\t\tTreeNodeRef& subNode = curTrunk.subNodes[i];\n\t\tif(subNode.isTrunkNode()) {\n\t\t\tTreeTrunk& subTrunk = subNode.asTrunk();\n\t\t\tint subTrunkSize = subNode.getTrunkSize();\n\t\t\tif(updateObjectBoundsRecurive(subTrunk, subTrunkSize, object, originalBounds, newBounds)) {\n\t\t\t\tcurTrunk.setBoundsOfSubNode(i, TrunkSIMDHelperFallback::getTotalBounds(subTrunk, subTrunkSize));\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} else {\n\t\t\tif(subNode.asObject() == object) {\n\t\t\t\tcurTrunk.setBoundsOfSubNode(i, newBounds);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n}\n\nvoid BoundsTreePrototype::updateObjectBounds(const void* object, const BoundsTemplate<float>& originalBounds, const BoundsTemplate<float>& newBounds) {\n\tbool wasFound = updateObjectBoundsRecurive(this->baseTrunk, this->baseTrunkSize, object, originalBounds, newBounds);\n\tif(!wasFound) throw \"Object was not found!\";\n}\n\nstatic bool findAndReplaceObjectRecursive(TreeTrunk& curTrunk, int curTrunkSize, const void* oldObject, void* newObject, const BoundsTemplate<float>& bounds) {\n\tassert(curTrunkSize >= 0 && curTrunkSize <= BRANCH_FACTOR);\n\tstd::array<bool, BRANCH_FACTOR> couldContain = TrunkSIMDHelperFallback::getAllContainsBounds(curTrunk, bounds);\n\tfor(int i = 0; i < curTrunkSize; i++) {\n\t\tif(!couldContain[i]) continue;\n\n\t\tTreeNodeRef& subNode = curTrunk.subNodes[i];\n\t\tif(subNode.isTrunkNode()) {\n\t\t\tTreeTrunk& subTrunk = subNode.asTrunk();\n\t\t\tint subTrunkSize = subNode.getTrunkSize();\n\t\t\tif(findAndReplaceObjectRecursive(subTrunk, subTrunkSize, oldObject, newObject, bounds)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} else {\n\t\t\tif(subNode.asObject() == oldObject) {\n\t\t\t\tsubNode.setObject(newObject);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n}\nvoid BoundsTreePrototype::findAndReplaceObject(const void* oldObject, void* newObject, const BoundsTemplate<float>& bounds) {\n\tbool found = findAndReplaceObjectRecursive(this->baseTrunk, this->baseTrunkSize, oldObject, newObject, bounds);\n\tif(!found) throw \"Object to rename not found!\";\n}\n\nstatic bool disbandGroupRecursive(TreeTrunk& curTrunk, int curTrunkSize, const void* groupRep, const BoundsTemplate<float>& groupRepBounds) {\n\tassert(curTrunkSize >= 0 && curTrunkSize <= BRANCH_FACTOR);\n\tstd::array<bool, BRANCH_FACTOR> couldContain = TrunkSIMDHelperFallback::getAllContainsBounds(curTrunk, groupRepBounds);\n\tfor(int i = 0; i < curTrunkSize; i++) {\n\t\tif(!couldContain[i]) continue;\n\n\t\tTreeNodeRef& subNode = curTrunk.subNodes[i];\n\t\tif(subNode.isTrunkNode()) {\n\t\t\tTreeTrunk& subTrunk = subNode.asTrunk();\n\t\t\tint subTrunkSize = subNode.getTrunkSize();\n\t\t\tif(subNode.isGroupHead()) {\n\t\t\t\tif(containsObjectRecursive(subTrunk, subTrunkSize, groupRep, groupRepBounds)) {\n\t\t\t\t\tsubNode.removeGroupHead();\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif(disbandGroupRecursive(subTrunk, subTrunkSize, groupRep, groupRepBounds)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tif(subNode.asObject() == groupRep) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n}\n\nvoid BoundsTreePrototype::disbandGroup(const void* groupRep, const BoundsTemplate<float>& groupRepBounds) {\n\tdisbandGroupRecursive(this->baseTrunk, this->baseTrunkSize, groupRep, groupRepBounds);\n}\n\nstatic size_t getSizeRecursive(const TreeTrunk& curTrunk, int curTrunkSize) {\n\tsize_t total = 0;\n\tfor(int i = 0; i < curTrunkSize; i++) {\n\t\tconst TreeNodeRef& subNode = curTrunk.subNodes[i];\n\t\tif(subNode.isTrunkNode()) {\n\t\t\ttotal += getSizeRecursive(subNode.asTrunk(), subNode.getTrunkSize());\n\t\t} else {\n\t\t\ttotal++;\n\t\t}\n\t}\n\treturn total;\n}\n\nsize_t BoundsTreePrototype::size() const {\n\treturn getSizeRecursive(baseTrunk, baseTrunkSize);\n}\nsize_t BoundsTreePrototype::groupSize(const void* groupRep, const BoundsTemplate<float>& groupRepBounds) const {\n\tconst TreeNodeRef* groupFound = getGroupRecursive(this->baseTrunk, this->baseTrunkSize, groupRep, groupRepBounds);\n\tif(!groupFound) {\n\t\tthrow \"Group not found!\";\n\t}\n\tif(groupFound->isTrunkNode()) {\n\t\treturn getSizeRecursive(groupFound->asTrunk(), groupFound->getTrunkSize());\n\t} else {\n\t\treturn 1;\n\t}\n}\n\nvoid BoundsTreePrototype::clear() {\n\tthis->allocator.freeAllTrunks(this->baseTrunk, this->baseTrunkSize);\n\tthis->baseTrunkSize = 0;\n}\n\n// means that this trunk and it's subtrunks cannot be improved\nstatic bool isLeafTrunk(TreeTrunk& trunk, int trunkSize) {\n\tfor(int subNodeI = 0; subNodeI < trunkSize; subNodeI++) {\n\t\tTreeNodeRef& subNode = trunk.subNodes[subNodeI];\n\t\tif(!subNode.isGroupHeadOrLeaf()) return false;\n\t}\n\treturn true;\n}\n\nstatic void improveTrunkHorizontal(TrunkAllocator& alloc, TreeTrunk& trunk) {\n\tconstexpr int trunkSize = BRANCH_FACTOR; // required by the interface, allows for small SIMD optimizations\n\n\tassert(!isLeafTrunk(trunk, trunkSize));\n\n\t// indexed overlaps[i][j] with j >= i+1\n\tOverlapMatrix overlaps = TrunkSIMDHelperFallback::computeInternalBoundsOverlapMatrix(trunk, trunkSize);\n\n\tfor(int subNodeAI = 0; subNodeAI < trunkSize-1; subNodeAI++) {\n\t\tTreeNodeRef& subNodeA = trunk.subNodes[subNodeAI];\n\n\t\tif(subNodeA.isGroupHeadOrLeaf()) continue; // no breaking up groups\n\n\t\tTreeTrunk& subTrunkA = subNodeA.asTrunk();\n\t\tint subTrunkSizeA = subNodeA.getTrunkSize();\n\n\t\tfor(int subNodeBI = subNodeAI+1; subNodeBI < trunkSize - 1; subNodeBI++) {\n\t\t\tTreeNodeRef& subNodeB = trunk.subNodes[subNodeBI];\n\n\t\t\tif(subNodeB.isGroupHeadOrLeaf()) continue; // no breaking up groups\n\n\t\t\tTreeTrunk& subTrunkB = subNodeB.asTrunk();\n\t\t\tint subTrunkSizeB = subNodeB.getTrunkSize();\n\n\t\t\tif(!overlaps[subNodeAI][subNodeBI]) continue;\n\n\t\t\tif(subTrunkSizeA + subTrunkSizeB >= BRANCH_FACTOR + 2) {\n\t\t\t\t// if true, this updates subTrunkSizeA and subTrunkSizeB\n\t\t\t\tif(TrunkSIMDHelperFallback::exchangeNodesBetween(subTrunkA, subTrunkSizeA, subTrunkB, subTrunkSizeB)) {\n\t\t\t\t\t// update treenoderefs\n\t\t\t\t\tsubNodeA.setTrunkSize(subTrunkSizeA);\n\t\t\t\t\tsubNodeB.setTrunkSize(subTrunkSizeB);\n\n\t\t\t\t\ttrunk.setBoundsOfSubNode(subNodeAI, TrunkSIMDHelperFallback::getTotalBounds(subTrunkA, subTrunkSizeA));\n\t\t\t\t\ttrunk.setBoundsOfSubNode(subNodeBI, TrunkSIMDHelperFallback::getTotalBounds(subTrunkB, subTrunkSizeB));\n\t\t\t\t\t// just return, changing trunkNodes invalidated overlaps matrix, more improvements can be done in future calls\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// can just merge out a Trunk\n\t\t\t\t// move all but first element from B to A\n\t\t\t\tsubTrunkSizeA = TrunkSIMDHelperFallback::transferNodes(subTrunkB, 1, subTrunkSizeB, subTrunkA, subTrunkSizeA);\n\t\t\t\tsubNodeA.setTrunkSize(subTrunkSizeA);\n\t\t\t\ttrunk.setBoundsOfSubNode(subNodeAI, TrunkSIMDHelperFallback::getTotalBounds(subTrunkA, subTrunkSizeA));\n\t\t\t\ttrunk.setSubNode(subNodeBI, std::move(subTrunkB.subNodes[0]), subTrunkB.getBoundsOfSubNode(0));\n\t\t\t\talloc.freeTrunk(&subTrunkB);\n\n\t\t\t\t// just return, changing trunkNodes invalidated overlaps matrix, more improvements can be done in future calls\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n}\n\ninline static void swapNodesBetweenTrunks(TreeTrunk& trunkA, int indexInTrunkA, TreeTrunk& trunkB, int indexInTrunkB) {\n\tBoundsTemplate<float> boundsA = trunkA.getBoundsOfSubNode(indexInTrunkA);\n\tBoundsTemplate<float> boundsB = trunkB.getBoundsOfSubNode(indexInTrunkB);\n\n\ttrunkA.setBoundsOfSubNode(indexInTrunkA, boundsB);\n\ttrunkB.setBoundsOfSubNode(indexInTrunkB, boundsA);\n\n\tstd::swap(trunkA.subNodes[indexInTrunkA], trunkB.subNodes[indexInTrunkB]);\n}\n\nstatic void improveTrunkVertical(TreeTrunk& trunk) {\n\tconstexpr int trunkSize = BRANCH_FACTOR; // required by the interface, allows for small SIMD optimizations\n\n\tif(isLeafTrunk(trunk, trunkSize)) return; // no improvement possible\n\n\tstd::array<float, BRANCH_FACTOR> allExistingSizes = TrunkSIMDHelperFallback::computeAllCosts(trunk);\n\n\tint smallestSubNodeI = 0;\n\tfloat smallestSubNodeSize = allExistingSizes[0];\n\n\tfor(int i = 1; i < trunkSize; i++) {\n\t\tif(allExistingSizes[i] < smallestSubNodeSize) {\n\t\t\tsmallestSubNodeSize = allExistingSizes[i];\n\t\t\tsmallestSubNodeI = i;\n\t\t}\n\t}\n\n\tint largestItemSubTrunkI = -1;\n\tint largestItemI = -1;\n\tfloat largestItemInSubTrunkISize = smallestSubNodeSize; // try to beat this, if we can't then there's no swap\n\n\tfor(int subTrunkI = 0; subTrunkI < trunkSize; subTrunkI++) {\n\t\tif(subTrunkI == smallestSubNodeI) continue; // the smallest node cannot contain a node larger than itself, also, trying to swap these would store this node in itself, leading to memory leak and objects disappearing\n\t\tTreeNodeRef& subNode = trunk.subNodes[subTrunkI];\n\n\t\t// find a node, and try to swap it with an element from a group\n\t\tif(subNode.isGroupHeadOrLeaf()) continue;\n\n\t\tTreeTrunk& subTrunk = subNode.asTrunk();\n\t\tint subTrunkSize = subNode.getTrunkSize();\n\n\t\tstd::array<float, BRANCH_FACTOR> subTrunkSizes = TrunkSIMDHelperFallback::computeAllCosts(subTrunk);\n\t\t\n\t\tfor(int i = 0; i < subTrunkSize; i++) {\n\t\t\tif(subTrunkSizes[i] > largestItemInSubTrunkISize) {\n\t\t\t\tlargestItemInSubTrunkISize = subTrunkSizes[i];\n\t\t\t\tlargestItemSubTrunkI = subTrunkI;\n\t\t\t\tlargestItemI = i;\n\t\t\t}\n\t\t}\n\t}\n\n\tif(largestItemI != -1) {\n\t\t// an improvement can be made by swapping\n\t\tTreeTrunk& chosenSubTrunk = trunk.subNodes[largestItemSubTrunkI].asTrunk();\n\t\tint chosenSubTrunkSize = trunk.subNodes[largestItemSubTrunkI].getTrunkSize();\n\t\tswapNodesBetweenTrunks(trunk, smallestSubNodeI, chosenSubTrunk, largestItemI);\n\t\ttrunk.setBoundsOfSubNode(largestItemSubTrunkI, TrunkSIMDHelperFallback::getTotalBounds(chosenSubTrunk, chosenSubTrunkSize));\n\t}\n}\n\nstatic int moveElementsOutOfGroup(TrunkAllocator& alloc, TreeTrunk& trunk, int trunkSize) {\n\tassert(!isLeafTrunk(trunk, trunkSize));\n\tif(trunkSize >= BRANCH_FACTOR) return trunkSize;\n\tint freeSlots = BRANCH_FACTOR - trunkSize;\n\n\tfor(int subNodeI = 0; subNodeI < trunkSize; subNodeI++) {\n\t\tTreeNodeRef& subNode = trunk.subNodes[subNodeI];\n\n\t\t// find a node, and try to swap it with an element from a group\n\t\tif(!subNode.isGroupHeadOrLeaf()) { // no breaking up groups\n\t\t\tTreeTrunk& subTrunk = subNode.asTrunk();\n\t\t\tint subTrunkSize = subNode.getTrunkSize();\n\n\t\t\tif(subTrunkSize <= freeSlots + 1) {\n\t\t\t\t// whole trunk is consumed, can use an extra slot since \n\n\t\t\t\ttrunk.setSubNode(subNodeI, std::move(subTrunk.subNodes[0]), subTrunk.getBoundsOfSubNode(0));\n\n\t\t\t\ttrunkSize = TrunkSIMDHelperFallback::transferNodes(subTrunk, 1, subTrunkSize, trunk, trunkSize);\n\t\t\t\talloc.freeTrunk(&subTrunk);\n\n\t\t\t\tif(trunkSize >= BRANCH_FACTOR) return trunkSize;\n\t\t\t\tfreeSlots = BRANCH_FACTOR - trunkSize;\n\t\t\t} else {\n\t\t\t\t// not consuming the whole trunk add what we can\n\t\t\t\tint resultingSubTrunkSize = subTrunkSize - freeSlots;\n\t\t\t\tint resultingSize = TrunkSIMDHelperFallback::transferNodes(subTrunk, resultingSubTrunkSize, subTrunkSize, trunk, trunkSize);\n\t\t\t\tsubNode.setTrunkSize(resultingSubTrunkSize);\n\t\t\t\ttrunk.setBoundsOfSubNode(subNodeI, TrunkSIMDHelperFallback::getTotalBounds(subTrunk, resultingSubTrunkSize));\n\t\t\t\tassert(resultingSize == BRANCH_FACTOR);\n\t\t\t\treturn resultingSize;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn trunkSize;\n}\n\nstatic int improveStructureRecursive(TrunkAllocator& alloc, TreeTrunk& trunk, int trunkSize) {\n\tbool givenTrunkIsLeafTrunk = true;\n\tfor(int i = 0; i < trunkSize; i++) {\n\t\tTreeNodeRef& subNode = trunk.subNodes[i];\n\t\tif(subNode.isTrunkNode()) {\n\t\t\tTreeTrunk& subTrunk = subNode.asTrunk();\n\t\t\tint subTrunkSize = subNode.getTrunkSize();\n\n\t\t\tsubTrunkSize = improveStructureRecursive(alloc, subTrunk, subTrunkSize);\n\n\t\t\tsubNode.setTrunkSize(subTrunkSize);\n\n\t\t\tif(!subNode.isGroupHead()) givenTrunkIsLeafTrunk = false;\n\t\t}\n\t}\n\tif(givenTrunkIsLeafTrunk) return trunkSize;\n\n\ttrunkSize = moveElementsOutOfGroup(alloc, trunk, trunkSize);\n\n\tif(trunkSize != BRANCH_FACTOR) return trunkSize;\n\tif(isLeafTrunk(trunk, trunkSize)) return trunkSize;\n\n\timproveTrunkVertical(trunk); // trunkSize == BRANCH_FACTOR\n\timproveTrunkHorizontal(alloc, trunk); // trunkSize == BRANCH_FACTOR\n\n\treturn trunkSize;\n}\nvoid BoundsTreePrototype::improveStructure() {\n\timproveStructureRecursive(this->allocator, this->baseTrunk, this->baseTrunkSize);\n}\nvoid BoundsTreePrototype::maxImproveStructure() {\n\tfor(int i = 0; i < 5; i++) {\n\t\tthis->improveStructure();\n\t}\n}\n\n};\n"
  },
  {
    "path": "Physics3D/boundstree/boundsTree.h",
    "content": "#pragma once\n\n#include \"../math/fix.h\"\n#include \"../math/position.h\"\n#include \"../math/bounds.h\"\n#include \"../datastructures/iteratorEnd.h\"\n#include \"../datastructures/iteratorFactory.h\"\n\n#include <cstdint>\n#include <utility>\n#include <cassert>\n#include <limits>\n#include <array>\n#include <optional>\n#include <iostream>\n#include <stack>\n\nnamespace P3D {\nconstexpr int BRANCH_FACTOR = 8;\nstatic_assert((BRANCH_FACTOR & (BRANCH_FACTOR - 1)) == 0, \"Branch factor must be power of 2\");\n\nstruct TreeTrunk;\n\ninline float computeCost(const BoundsTemplate<float>& bounds) {\n\tVec3f d = bounds.getDiagonal();\n\treturn d.x + d.y + d.z;\n}\n\ninline float computeAdditionCost(const BoundsTemplate<float>& oldBounds, const BoundsTemplate<float>& extraBounds) {\n\treturn computeCost(unionOfBounds(oldBounds, extraBounds)) - computeCost(oldBounds);\n}\n\nclass TreeNodeRef {\n\tfriend struct TreeTrunk;\n\n\tstatic constexpr std::uintptr_t SIZE_DATA_MASK = BRANCH_FACTOR - 1;\n\tstatic constexpr std::uintptr_t GROUP_HEAD_MASK = BRANCH_FACTOR;\n\tstatic constexpr std::uintptr_t PTR_MASK = ~(SIZE_DATA_MASK | GROUP_HEAD_MASK);\n\tstatic constexpr std::uintptr_t INVALID_REF = 0xADADADADADADADAD;\n\n\n\t/* encoding:\n\t\t0b...pppppgsss\n\n\t\t(this is if BRANCH_FACTOR == 8)\n\t\tLast 3 bits specify type: \n\t\t0b000: leaf node -> ptr points to object\n\t\telse : trunk node -> ptr points to TreeTrunk\n\t\t\tg bit specifies 'isGroupHead'\n\t\t\ts bits specify size of this trunk node - 1. 0b111 is a trunknode of size 8\n\t*/\n\tstd::uintptr_t ptr;\n\n\tinline int getSizeData() const {\n\t\treturn static_cast<int>(ptr & SIZE_DATA_MASK);\n\t}\n\npublic:\n#ifndef NDEBUG\n\tTreeNodeRef() noexcept : ptr(INVALID_REF) {}\n#else\n\tTreeNodeRef() = default;\n#endif\n\tinline explicit TreeNodeRef(TreeTrunk* trunk, int trunkSize, bool isGroupHead) noexcept;\n\tinline explicit TreeNodeRef(void* ptr) noexcept : ptr(reinterpret_cast<std::uintptr_t>(ptr)) {\n\t\tassert((this->ptr & SIZE_DATA_MASK) == 0);\n\t}\n\n\tTreeNodeRef(const TreeNodeRef&) = delete;\n\tTreeNodeRef& operator=(const TreeNodeRef&) = delete;\n#ifndef NDEBUG\n\tTreeNodeRef(TreeNodeRef&& other) noexcept : ptr(other.ptr) { other.ptr = INVALID_REF; }\n\tTreeNodeRef& operator=(TreeNodeRef&& other) noexcept { this->ptr = other.ptr; other.ptr = INVALID_REF; return *this; }\n#else\n\tTreeNodeRef(TreeNodeRef&& other) = default;\n\tTreeNodeRef& operator=(TreeNodeRef&& other) = default;\n#endif\n\n\tinline bool isLeafNode() const {\n\t\tassert(this->ptr != INVALID_REF);\n\t\treturn getSizeData() == 0;\n\t}\n\tinline bool isTrunkNode() const {\n\t\tassert(this->ptr != INVALID_REF);\n\t\treturn getSizeData() != 0;\n\t}\n\tinline int getTrunkSize() const {\n\t\tassert(isTrunkNode());\n\t\treturn getSizeData() + 1;\n\t}\n\tinline void setTrunkSize(int newSize) {\n\t\tassert(isTrunkNode());\n\t\tassert(newSize >= 2 && newSize <= BRANCH_FACTOR);\n\t\tthis->ptr = (this->ptr & ~SIZE_DATA_MASK) | (newSize - 1);\n\t}\n\tinline void setObject(void* newObject) {\n\t\tassert(isLeafNode());\n\t\tthis->ptr = reinterpret_cast<std::uintptr_t>(newObject);\n\t\tassert((this->ptr & SIZE_DATA_MASK) == 0);\n\t}\n\tinline void makeGroupHead() {\n\t\tassert(isTrunkNode());\n\t\tthis->ptr |= GROUP_HEAD_MASK;\n\t}\n\tinline void removeGroupHead() {\n\t\tassert(isTrunkNode());\n\t\tthis->ptr &= ~GROUP_HEAD_MASK;\n\t}\n\tinline bool isGroupHead() const {\n\t\tassert(isTrunkNode());\n\t\treturn (ptr & GROUP_HEAD_MASK) != 0;\n\t}\n\tinline bool isGroupHeadOrLeaf() const {\n\t\tif(isTrunkNode()) {\n\t\t\treturn (ptr & GROUP_HEAD_MASK) != 0;\n\t\t} else {\n\t\t\treturn true;\n\t\t}\n\t}\n\tinline const TreeTrunk& asTrunk() const;\n\tinline TreeTrunk& asTrunk();\n\tinline void* asObject() const;\n\n\t// expects a function of the form BoundsTemplate<float>(const CastTo&)\n\ttemplate<typename CastTo, typename GetObjectBoundsFunc>\n\tinline BoundsTemplate<float> recalculateBoundsRecursive(const GetObjectBoundsFunc& getObjBounds);\n};\n\nstruct TrunkSIMDHelperFallback;\n\ntemplate<size_t Size>\nstruct alignas(64) BoundsArray {\n\tfloat xMin[Size];\n\tfloat yMin[Size];\n\tfloat zMin[Size];\n\tfloat xMax[Size];\n\tfloat yMax[Size];\n\tfloat zMax[Size];\n\n\tinline BoundsTemplate<float> getBounds(int index) const {\n\t\tassert(index >= 0 && index < Size);\n\t\tBoundsTemplate<float> result;\n\t\tresult.min.x = xMin[index];\n\t\tresult.min.y = yMin[index];\n\t\tresult.min.z = zMin[index];\n\t\tresult.max.x = xMax[index];\n\t\tresult.max.y = yMax[index];\n\t\tresult.max.z = zMax[index];\n\t\treturn result;\n\t}\n\tinline void setBounds(int index, const BoundsTemplate<float>& newBounds) {\n\t\tassert(index >= 0 && index < Size);\n\t\txMin[index] = newBounds.min.x;\n\t\tyMin[index] = newBounds.min.y;\n\t\tzMin[index] = newBounds.min.z;\n\t\txMax[index] = newBounds.max.x;\n\t\tyMax[index] = newBounds.max.y;\n\t\tzMax[index] = newBounds.max.z;\n\t}\n\tinline void move(int from, int to) {\n\t\tassert(from >= 0 && from < Size);\n\t\tassert(to >= 0 && to < Size);\n\t\txMin[to] = xMin[from];\n\t\tyMin[to] = yMin[from];\n\t\tzMin[to] = zMin[from];\n\t\txMax[to] = xMax[from];\n\t\tyMax[to] = yMax[from];\n\t\tzMax[to] = zMax[from];\n\t}\n};\n\nstruct alignas(64) TreeTrunk {\n\tBoundsArray<BRANCH_FACTOR> subNodeBounds;\n\tTreeNodeRef subNodes[BRANCH_FACTOR];\n\n\tinline BoundsTemplate<float> getBoundsOfSubNode(int subNode) const {\n\t\treturn this->subNodeBounds.getBounds(subNode);\n\t}\n\n\tinline void setBoundsOfSubNode(int subNode, const BoundsTemplate<float>& newBounds) {\n\t\tthis->subNodeBounds.setBounds(subNode, newBounds);\n\t}\n\n\tinline void moveSubNode(int from, int to) {\n\t\tthis->subNodeBounds.move(from, to);\n\t\tthis->subNodes[to] = std::move(this->subNodes[from]);\n\t}\n\n\tinline void setSubNode(int subNode, TreeNodeRef&& newNode, const BoundsTemplate<float>& newBounds) {\n\t\tthis->subNodeBounds.setBounds(subNode, newBounds);\n\t\tsubNodes[subNode] = std::move(newNode);\n\t}\n};\n\nTreeNodeRef::TreeNodeRef(TreeTrunk* trunk, int trunkSize, bool isGroupHead) noexcept : ptr(reinterpret_cast<std::uintptr_t>(trunk) | (static_cast<std::uintptr_t>(trunkSize) - 1) | (isGroupHead ? BRANCH_FACTOR : 0)) {\n\tassert(trunkSize >= 2 && trunkSize <= BRANCH_FACTOR); // trunkSize must be between 2-BRANCH_FACTOR\n\tassert((reinterpret_cast<std::uintptr_t>(trunk) & (BRANCH_FACTOR * sizeof(int64_t) - 1)) == 0); // check trunk is aligned correctly\n}\nconst TreeTrunk& TreeNodeRef::asTrunk() const {\n\tassert(this->ptr != INVALID_REF);\n\tassert(isTrunkNode());\n\treturn *reinterpret_cast<TreeTrunk*>(ptr & PTR_MASK);\n}\nTreeTrunk& TreeNodeRef::asTrunk() {\n\tassert(this->ptr != INVALID_REF);\n\tassert(isTrunkNode());\n\treturn *reinterpret_cast<TreeTrunk*>(ptr & PTR_MASK);\n}\nvoid* TreeNodeRef::asObject() const {\n\tassert(this->ptr != INVALID_REF);\n\tassert(isLeafNode());\n\treturn reinterpret_cast<TreeTrunk*>(ptr & ~SIZE_DATA_MASK);\n}\n\nstruct OverlapMatrix {\n\tbool overlapData[BRANCH_FACTOR*BRANCH_FACTOR]{};\n\n\tinline bool* operator[](size_t idx) {return overlapData+BRANCH_FACTOR*idx;}\n\tinline const bool* operator[](size_t idx) const {return overlapData+BRANCH_FACTOR*idx;}\n};\n\nstruct TrunkSIMDHelperFallback {\n\tstatic BoundsTemplate<float> getTotalBounds(const TreeTrunk& trunk, int upTo);\n\tstatic BoundsTemplate<float> getTotalBoundsWithout(const TreeTrunk& trunk, int upTo, int without);\n\t// returns a list of bounds, every index contains the total bounds without that subNode\n\tstatic BoundsArray<BRANCH_FACTOR> getAllTotalBoundsWithout(const TreeTrunk& trunk, int upTo);\n\tstatic std::array<bool, BRANCH_FACTOR> getAllContainsBounds(const TreeTrunk& trunk, const BoundsTemplate<float>& boundsToContain);\n\tstatic std::array<float, BRANCH_FACTOR> computeAllCosts(const TreeTrunk& trunk);\n\tstatic std::array<float, BRANCH_FACTOR> computeAllCombinationCosts(const BoundsArray<BRANCH_FACTOR>& boundsArr, const BoundsTemplate<float>& boundsExtention);\n\tstatic std::pair<int, int> computeFurthestObjects(const BoundsArray<BRANCH_FACTOR * 2>& boundsArray, int size);\n\tstatic int getLowestCombinationCost(const TreeTrunk& trunk, const BoundsTemplate<float>& boundsExtention, int nodeSize);\n\tstatic std::array<bool, BRANCH_FACTOR> computeOverlapsWith(const TreeTrunk& trunk, int trunkSize, const BoundsTemplate<float>& bounds);\n\t// indexed result[a][b]\n\tstatic OverlapMatrix computeBoundsOverlapMatrix(const TreeTrunk& trunkA, int trunkASize, const TreeTrunk& trunkB, int trunkBSize);\n\tstatic OverlapMatrix computeBoundsOverlapMatrixAVX(const TreeTrunk& trunkA, int trunkASize, const TreeTrunk& trunkB, int trunkBSize);\n\tstatic OverlapMatrix computeBoundsOverlapMatrixSSE(const TreeTrunk& trunkA, int trunkASize, const TreeTrunk& trunkB, int trunkBSize);\n\t// indexed result[i][j] with j >= i+1\n\tstatic OverlapMatrix computeInternalBoundsOverlapMatrix(const TreeTrunk& trunk, int trunkSize);\n\n\tstatic std::array<float, BRANCH_FACTOR> computeAllExtentionCosts(const TreeTrunk& trunk, int trunkSize, const BoundsTemplate<float>& extraBounds);\n\n\t// returns resulting destTrunk size\n\tstatic int transferNodes(TreeTrunk& srcTrunk, int srcTrunkStart, int srcTrunkEnd, TreeTrunk& destTrunk, int destTrunkSize);\n\t\n\tstatic BoundsArray<BRANCH_FACTOR * 2> combineBoundsArrays(const TreeTrunk& trunkA, int trunkASize, const TreeTrunk& trunkB, int trunkBSize);\n\n\t// returns true if modified\n\tstatic bool exchangeNodesBetween(TreeTrunk& trunkA, int& trunkASize, TreeTrunk& trunkB, int& trunkBSize);\n};\n\ntemplate<typename CastTo, typename GetObjectBoundsFunc>\ninline BoundsTemplate<float> TreeNodeRef::recalculateBoundsRecursive(const GetObjectBoundsFunc& getObjBounds) {\n\tint sizeData = getSizeData();\n\tif(sizeData == 0) { // is leaf node\n\t\treturn getObjBounds(*reinterpret_cast<const CastTo*>(this->asObject()));\n\t} else {\n\t\tint trunkSize = sizeData + 1;\n\n\t\tTreeTrunk* trunk = this->asTrunk();\n\n\t\tfor(int i = 0; i < trunkSize; i++) {\n\t\t\ttrunk->setBoundsOfSubNode(i, trunk->subNodes[i].recalculateBoundsRecursive(getObjBounds));\n\t\t}\n\n\t\treturn TrunkSIMDHelperFallback::getTotalBounds(*trunk, trunkSize);\n\t}\n}\n\nclass TrunkAllocator {\n\tsize_t allocationCount;\npublic:\n\tTrunkAllocator();\n\t~TrunkAllocator();\n\tTrunkAllocator(const TrunkAllocator&) = delete;\n\tTrunkAllocator& operator=(const TrunkAllocator&) = delete;\n\tTrunkAllocator(TrunkAllocator&& other) noexcept;\n\tTrunkAllocator& operator=(TrunkAllocator&& other) noexcept;\n\tTreeTrunk* allocTrunk();\n\tvoid freeTrunk(TreeTrunk* trunk);\n\tvoid freeAllTrunks(TreeTrunk& baseTrunk, int baseTrunkSize);\n};\n\nint addRecursive(TrunkAllocator& allocator, TreeTrunk& curTrunk, int curTrunkSize, TreeNodeRef&& newNode, const BoundsTemplate<float>& bounds);\nint removeRecursive(TrunkAllocator& allocator, TreeTrunk& curTrunk, int curTrunkSize, const void* objectToRemove, const BoundsTemplate<float>& bounds);\nbool containsObjectRecursive(const TreeTrunk& trunk, int trunkSize, const void* object, const BoundsTemplate<float>& bounds);\nconst TreeNodeRef* getGroupRecursive(const TreeTrunk& curTrunk, int curTrunkSize, const void* groupRepresentative, const BoundsTemplate<float>& representativeBounds);\n\n/*\n \tExpects a function of the form BoundsTemplate<float>(TreeNodeRef& groupNode, const BoundsTemplate<float>& groupNodeBounds)\n\tShould return the new bounds of the node. \n\tThe input group and resulting group should be in the normal form of a group:\n\t\tif Trunk node => isGroupHead is enabled, no trunk node below has isGroupHead\n\t\tor Leaf node\n*/\ntemplate<typename Func>\ninline bool modifyGroupRecursive(TrunkAllocator& allocator, TreeTrunk& curTrunk, int curTrunkSize, const void* groupRepresentative, const BoundsTemplate<float>& groupRepresentativeBounds, const Func& modification) {\n\tassert(curTrunkSize >= 0 && curTrunkSize <= BRANCH_FACTOR);\n\tstd::array<bool, BRANCH_FACTOR> couldContain = TrunkSIMDHelperFallback::getAllContainsBounds(curTrunk, groupRepresentativeBounds);\n\tfor(int i = 0; i < curTrunkSize; i++) {\n\t\tif(!couldContain[i]) continue;\n\n\t\tTreeNodeRef& subNode = curTrunk.subNodes[i];\n\t\tif(subNode.isTrunkNode()) {\n\t\t\tTreeTrunk& subTrunk = subNode.asTrunk();\n\t\t\tint subTrunkSize = subNode.getTrunkSize();\n\t\t\tif(subNode.isGroupHead()) {\n\t\t\t\tif(containsObjectRecursive(subTrunk, subTrunkSize, groupRepresentative, groupRepresentativeBounds)) {\n\t\t\t\t\tBoundsTemplate<float> newTrunkBounds = modification(subNode, curTrunk.getBoundsOfSubNode(i));\n\t\t\t\t\tassert(subNode.isGroupHeadOrLeaf());\n\t\t\t\t\tcurTrunk.setBoundsOfSubNode(i, newTrunkBounds);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif(modifyGroupRecursive(allocator, subTrunk, subTrunkSize, groupRepresentative, groupRepresentativeBounds, modification)) {\n\t\t\t\t\tcurTrunk.setBoundsOfSubNode(i, TrunkSIMDHelperFallback::getTotalBounds(subTrunk, subTrunkSize));\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tif(subNode.asObject() == groupRepresentative) {\n\t\t\t\tBoundsTemplate<float> newTrunkBounds = modification(subNode, curTrunk.getBoundsOfSubNode(i));\n\t\t\t\tassert(subNode.isGroupHeadOrLeaf());\n\t\t\t\tcurTrunk.setBoundsOfSubNode(i, newTrunkBounds);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n}\n/*\n\tExpects a function of the form std::optional<BoundsTemplate<float>>(TreeNodeRef& groupNode, const BoundsTemplate<float>& groupNodeBounds)\n\tShould return the new bounds of the node.\n\tThe input group and resulting group should be in the normal form of a group:\n\t\tif Trunk node => isGroupHead is enabled, no trunk node below has isGroupHead\n\t\tor Leaf node\n*/\ntemplate<typename Func>\ninline int contractGroupRecursive(TrunkAllocator& allocator, TreeTrunk& curTrunk, int curTrunkSize, const void* groupRepresentative, const BoundsTemplate<float>& groupRepresentativeBounds, const Func& modification) {\n\tassert(curTrunkSize >= 0 && curTrunkSize <= BRANCH_FACTOR);\n\tstd::array<bool, BRANCH_FACTOR> couldContain = TrunkSIMDHelperFallback::getAllContainsBounds(curTrunk, groupRepresentativeBounds);\n\tfor(int i = 0; i < curTrunkSize; i++) {\n\t\tif(!couldContain[i]) continue;\n\n\t\tTreeNodeRef& subNode = curTrunk.subNodes[i];\n\t\tif(subNode.isTrunkNode()) {\n\t\t\tTreeTrunk& subTrunk = subNode.asTrunk();\n\t\t\tint subTrunkSize = subNode.getTrunkSize();\n\t\t\tif(subNode.isGroupHead()) {\n\t\t\t\tif(containsObjectRecursive(subTrunk, subTrunkSize, groupRepresentative, groupRepresentativeBounds)) {\n\t\t\t\t\tstd::optional<BoundsTemplate<float>> newTrunkBounds = modification(subNode, curTrunk.getBoundsOfSubNode(i));\n\t\t\t\t\tif(newTrunkBounds.has_value()) {\n\t\t\t\t\t\tassert(subNode.isGroupHeadOrLeaf());\n\t\t\t\t\t\tcurTrunk.setBoundsOfSubNode(i, newTrunkBounds.value());\n\t\t\t\t\t\treturn curTrunkSize;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcurTrunk.moveSubNode(curTrunkSize - 1, i);\n\t\t\t\t\t\treturn curTrunkSize - 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tint newSubSize = contractGroupRecursive(allocator, subTrunk, subTrunkSize, groupRepresentative, groupRepresentativeBounds, modification);\n\t\t\t\tif(newSubSize != -1) {\n\t\t\t\t\tassert(newSubSize >= 1);\n\t\t\t\t\tif(newSubSize == 1) {\n\t\t\t\t\t\tcurTrunk.setSubNode(i, std::move(subTrunk.subNodes[0]), subTrunk.getBoundsOfSubNode(0));\n\t\t\t\t\t\tallocator.freeTrunk(&subTrunk);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsubNode.setTrunkSize(newSubSize);\n\t\t\t\t\t\tcurTrunk.setBoundsOfSubNode(i, TrunkSIMDHelperFallback::getTotalBounds(subTrunk, newSubSize));\n\t\t\t\t\t}\n\t\t\t\t\treturn curTrunkSize;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tif(subNode.asObject() == groupRepresentative) {\n\t\t\t\tstd::optional<BoundsTemplate<float>> newTrunkBounds = modification(subNode, curTrunk.getBoundsOfSubNode(i));\n\t\t\t\tif(newTrunkBounds.has_value()) {\n\t\t\t\t\tassert(subNode.isGroupHeadOrLeaf());\n\t\t\t\t\tcurTrunk.setBoundsOfSubNode(i, newTrunkBounds.value());\n\t\t\t\t\treturn curTrunkSize;\n\t\t\t\t} else {\n\t\t\t\t\tcurTrunk.moveSubNode(curTrunkSize - 1, i);\n\t\t\t\t\treturn curTrunkSize - 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn -1;\n}\n\n// expects a function of the form void(Boundable& object)\ntemplate<typename Boundable, typename Func>\ninline void forEachRecurse(const TreeTrunk& curTrunk, int curTrunkSize, const Func& func) {\n\tfor(int i = 0; i < curTrunkSize; i++) {\n\t\tconst TreeNodeRef& subNode = curTrunk.subNodes[i];\n\t\tif(subNode.isTrunkNode()) {\n\t\t\tforEachRecurse<Boundable, Func>(subNode.asTrunk(), subNode.getTrunkSize(), func);\n\t\t} else {\n\t\t\tfunc(*static_cast<Boundable*>(subNode.asObject()));\n\t\t}\n\t}\n}\n\n// expects a filter of the form std::array<bool, BRANCH_FACTOR>(const TreeTrunk& trunk, int trunkSize)\n// expects a function of the form void(Boundable& object)\ntemplate<typename Boundable, typename Filter, typename Func>\ninline void forEachFilteredRecurse(const TreeTrunk& curTrunk, int curTrunkSize, const Filter& filter, const Func& func) {\n\tstd::array<bool, BRANCH_FACTOR> passes = filter(curTrunk, curTrunkSize);\n\tfor(int i = 0; i < curTrunkSize; i++) {\n\t\tif(passes[i]) {\n\t\t\tconst TreeNodeRef& subNode = curTrunk.subNodes[i];\n\t\t\tif(subNode.isTrunkNode()) {\n\t\t\t\tforEachFilteredRecurse<Boundable, Filter, Func>(subNode.asTrunk(), subNode.getTrunkSize(), filter, func);\n\t\t\t} else {\n\t\t\t\tfunc(*static_cast<Boundable*>(subNode.asObject()));\n\t\t\t}\n\t\t}\n\t}\n}\n\n// expects a function of the form void(Boundable*, Boundable*)\n// Calls the given function for each pair of leaf nodes from the two trunks \ntemplate<typename Boundable, typename SIMDHelper, typename Func>\nvoid forEachColissionWithRecursive(Boundable* obj, const BoundsTemplate<float>& objBounds, const TreeTrunk& trunk, int trunkSize, const Func& func) {\n\tstd::array<bool, BRANCH_FACTOR> collidesWith = SIMDHelper::computeOverlapsWith(trunk, trunkSize, objBounds);\n\n\tfor(int i = 0; i < trunkSize; i++) {\n\t\tif(!collidesWith[i]) continue;\n\n\t\tconst TreeNodeRef& subNode = trunk.subNodes[i];\n\n\t\tif(subNode.isTrunkNode()) {\n\t\t\tforEachColissionWithRecursive<Boundable, SIMDHelper, Func>(obj, objBounds, subNode.asTrunk(), subNode.getTrunkSize(), func);\n\t\t} else {\n\t\t\tfunc(obj, static_cast<Boundable*>(subNode.asObject()));\n\t\t}\n\t}\n}\n\n// expects a function of the form void(Boundable*, Boundable*)\n// Calls the given function for each pair of leaf nodes from the two trunks \ntemplate<typename Boundable, typename SIMDHelper, typename Func>\nvoid forEachColissionWithRecursive(const TreeTrunk& trunk, int trunkSize, Boundable* obj, const BoundsTemplate<float>& objBounds, const Func& func) {\n\tstd::array<bool, BRANCH_FACTOR> collidesWith = SIMDHelper::computeOverlapsWith(trunk, trunkSize, objBounds);\n\n\tfor(int i = 0; i < trunkSize; i++) {\n\t\tif(!collidesWith[i]) continue;\n\n\t\tconst TreeNodeRef& subNode = trunk.subNodes[i];\n\n\t\tif(subNode.isTrunkNode()) {\n\t\t\tforEachColissionWithRecursive<Boundable, SIMDHelper, Func>(subNode.asTrunk(), subNode.getTrunkSize(), obj, objBounds, func);\n\t\t} else {\n\t\t\tfunc(static_cast<Boundable*>(subNode.asObject()), obj);\n\t\t}\n\t}\n}\n\n// expects a function of the form void(Boundable*, Boundable*)\n// Calls the given function for each pair of leaf nodes from the two trunks \ntemplate<typename Boundable, typename SIMDHelper, typename Func>\nvoid forEachColissionBetweenRecursive(const TreeTrunk& trunkA, int trunkASize, const TreeTrunk& trunkB, int trunkBSize, const Func& func) {\n\tOverlapMatrix overlapBetween = SIMDHelper::computeBoundsOverlapMatrix(trunkA, trunkASize, trunkB, trunkBSize);\n\n\tfor(int a = 0; a < trunkASize; a++) {\n\t\tconst TreeNodeRef& aNode = trunkA.subNodes[a];\n\t\tbool aIsTrunk = aNode.isTrunkNode();\n\t\tfor(int b = 0; b < trunkBSize; b++) {\n\t\t\tif(!overlapBetween[a][b]) continue;\n\n\t\t\tconst TreeNodeRef& bNode = trunkB.subNodes[b];\n\t\t\tbool bIsTrunk = bNode.isTrunkNode();\n\t\t\t\n\t\t\tif(aIsTrunk) {\n\t\t\t\tif(bIsTrunk) {\n\t\t\t\t\t// both trunk nodes\n\t\t\t\t\t// split both\n\t\t\t\t\tforEachColissionBetweenRecursive<Boundable, SIMDHelper, Func>(aNode.asTrunk(), aNode.getTrunkSize(), bNode.asTrunk(), bNode.getTrunkSize(), func);\n\t\t\t\t} else {\n\t\t\t\t\t// a is trunk, b is not\n\t\t\t\t\t// split a\n\t\t\t\t\tforEachColissionWithRecursive<Boundable, SIMDHelper, Func>(aNode.asTrunk(), aNode.getTrunkSize(), static_cast<Boundable*>(bNode.asObject()), trunkB.getBoundsOfSubNode(b), func);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif(bIsTrunk) {\n\t\t\t\t\t// b is trunk, a is not\n\t\t\t\t\t// split b\n\t\t\t\t\tforEachColissionWithRecursive<Boundable, SIMDHelper, Func>(static_cast<Boundable*>(aNode.asObject()), trunkA.getBoundsOfSubNode(a), bNode.asTrunk(), bNode.getTrunkSize(), func);\n\t\t\t\t} else {\n\t\t\t\t\t// both leaf nodes\n\t\t\t\t\tfunc(static_cast<Boundable*>(aNode.asObject()), static_cast<Boundable*>(bNode.asObject()));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n// expects a function of the form void(Boundable*, Boundable*)\n// Calls the given function for each pair of leaf nodes that are not in the same group and have overlapping bounds\ntemplate<typename Boundable, typename SIMDHelper, typename Func>\nvoid forEachColissionInternalRecursive(const TreeTrunk& curTrunk, int curTrunkSize, const Func& func) {\n\tOverlapMatrix internalOverlap = SIMDHelper::computeInternalBoundsOverlapMatrix(curTrunk, curTrunkSize);\n\n\tfor(int a = 0; a < curTrunkSize; a++) {\n\t\tconst TreeNodeRef& aNode = curTrunk.subNodes[a];\n\t\tbool aIsTrunk = aNode.isTrunkNode();\n\t\tfor(int b = a+1; b < curTrunkSize; b++) {\n\t\t\tif(!internalOverlap[a][b]) continue;\n\n\t\t\tconst TreeNodeRef& bNode = curTrunk.subNodes[b];\n\t\t\tbool bIsTrunk = bNode.isTrunkNode();\n\n\t\t\tif(aIsTrunk) {\n\t\t\t\tif(bIsTrunk) {\n\t\t\t\t\t// both trunk nodes\n\t\t\t\t\t// split both\n\t\t\t\t\tforEachColissionBetweenRecursive<Boundable, SIMDHelper, Func>(aNode.asTrunk(), aNode.getTrunkSize(), bNode.asTrunk(), bNode.getTrunkSize(), func);\n\t\t\t\t} else {\n\t\t\t\t\t// a is trunk, b is not\n\t\t\t\t\t// split a\n\t\t\t\t\tforEachColissionWithRecursive<Boundable, SIMDHelper, Func>(aNode.asTrunk(), aNode.getTrunkSize(), static_cast<Boundable*>(bNode.asObject()), curTrunk.getBoundsOfSubNode(b), func);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif(bIsTrunk) {\n\t\t\t\t\t// b is trunk, a is not\n\t\t\t\t\t// split b\n\t\t\t\t\tforEachColissionWithRecursive<Boundable, SIMDHelper, Func>(static_cast<Boundable*>(aNode.asObject()), curTrunk.getBoundsOfSubNode(a), bNode.asTrunk(), bNode.getTrunkSize(), func);\n\t\t\t\t} else {\n\t\t\t\t\t// both leaf nodes\n\t\t\t\t\tfunc(static_cast<Boundable*>(aNode.asObject()), static_cast<Boundable*>(bNode.asObject()));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfor(int i = 0; i < curTrunkSize; i++) {\n\t\tconst TreeNodeRef& subNode = curTrunk.subNodes[i];\n\n\t\tif(subNode.isTrunkNode() && !subNode.isGroupHead()) {\n\t\t\tforEachColissionInternalRecursive<Boundable, SIMDHelper, Func>(subNode.asTrunk(), subNode.getTrunkSize(), func);\n\t\t}\n\t}\n}\n\nclass BoundsTreeIteratorPrototype {\n\tstruct StackElement {\n\t\tconst TreeTrunk* trunk;\n\t\tint trunkSize;\n\t\tint curIndex;\n\t};\n\n\tstd::stack<StackElement> trunkStack;\n\npublic:\n\tBoundsTreeIteratorPrototype() = default;\n\tBoundsTreeIteratorPrototype(const TreeTrunk& baseTrunk, int baseTrunkSize) : trunkStack() {\n\t\tif(baseTrunkSize == 0) return;\n\t\ttrunkStack.push(StackElement{&baseTrunk, baseTrunkSize, 0});\n\t\twhile(trunkStack.top().trunk->subNodes[0].isTrunkNode()) {\n\t\t\tconst TreeNodeRef& nextNode = trunkStack.top().trunk->subNodes[0];\n\t\t\ttrunkStack.push(StackElement{&nextNode.asTrunk(), nextNode.getTrunkSize(), 0});\n\t\t}\n\t}\n\n\tvoid* operator*() const {\n\t\tconst StackElement& top = trunkStack.top();\n\t\treturn top.trunk->subNodes[top.curIndex].asObject();\n\t}\n\n\tBoundsTreeIteratorPrototype& operator++() {\n\t\tStackElement& top = trunkStack.top();\n\t\ttop.curIndex++;\n\t\tif(top.curIndex < top.trunkSize) {\n\t\t\tconst TreeNodeRef& nextNode = trunkStack.top().trunk->subNodes[top.curIndex];\n\t\t\tif(nextNode.isTrunkNode()) {\n\t\t\t\t// rise until hitting non trunk node\n\t\t\t\ttrunkStack.push(StackElement{&nextNode.asTrunk(), nextNode.getTrunkSize(), 0});\n\t\t\t\twhile(trunkStack.top().trunk->subNodes[0].isTrunkNode()) {\n\t\t\t\t\tconst TreeNodeRef& nextNode = trunkStack.top().trunk->subNodes[0];\n\t\t\t\t\ttrunkStack.push(StackElement{&nextNode.asTrunk(), nextNode.getTrunkSize(), 0});\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// drop down until next available\n\t\t\tdo {\n\t\t\t\ttrunkStack.pop();\n\t\t\t\tif(trunkStack.size() == 0) break; // iteration done\n\t\t\t\tStackElement& top = trunkStack.top();\n\t\t\t\ttop.curIndex++;\n\t\t\t\tassert(top.curIndex <= top.trunkSize);\n\t\t\t} while(top.curIndex == top.trunkSize); // keep popping\n\t\t}\n\t\treturn *this;\n\t}\n\n\tbool operator!=(IteratorEnd) const {\n\t\treturn trunkStack.size() != 0;\n\t}\n};\n\ntemplate<typename Filter>\nclass FilteredTreeIteratorPrototype {\n\tstruct StackElement {\n\t\tconst TreeTrunk* trunk;\n\t\tint trunkSize;\n\t\tint curIndex;\n\t\tstd::array<bool, BRANCH_FACTOR> filterResults;\n\t};\n\n\tFilter filter;\n\tstd::stack<StackElement> trunkStack;\n\npublic:\n\tFilteredTreeIteratorPrototype() = default;\n\n\tvoid delveDown() {\n\t\twhile(true) {\n\t\t\tagain:\n\t\t\tStackElement& top = trunkStack.top();\n\t\t\tfor(; top.curIndex < top.trunkSize; top.curIndex++) {\n\t\t\t\tif(top.filterResults[top.curIndex]) {\n\t\t\t\t\tconst TreeNodeRef& subNode = top.trunk->subNodes[top.curIndex];\n\t\t\t\t\tif(!subNode.isTrunkNode()) break;\n\t\t\t\t\tStackElement newElem{&subNode.asTrunk(), subNode.getTrunkSize(), 0};\n\t\t\t\t\tnewElem.filterResults = this->filter(*newElem.trunk, newElem.trunkSize);\n\t\t\t\t\ttrunkStack.push(newElem);\n\t\t\t\t\tgoto again;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// no available node found, go back up a level\n\t\t\ttrunkStack.pop();\n\t\t\tif(trunkStack.empty()) return; // end of iteration\n\t\t\tStackElement& newTop = trunkStack.top();\n\t\t\tnewTop.curIndex++;\n\t\t}\n\t}\n\n\tFilteredTreeIteratorPrototype(const TreeTrunk& baseTrunk, int baseTrunkSize, const Filter& filter) : trunkStack(), filter(filter) {\n\t\tif(baseTrunkSize == 0) return;\n\t\tStackElement newElement{&baseTrunk, baseTrunkSize};\n\t\tnewElement.filterResults = this->filter(baseTrunk, baseTrunkSize);\n\t\tfor(int i = 0; i < baseTrunkSize; i++){\n\t\t\tif(newElement.filterResults[i]) {\n\t\t\t\tnewElement.curIndex = i;\n\t\t\t\ttrunkStack.push(newElement);\n\t\t\t\tgoto found;\n\t\t\t}\n\t\t}\n\t\treturn; // none of the nodes are suitable\n\t\tfound:;\n\t\tthis->delveDown();\n\t}\n\n\tvoid* operator*() const {\n\t\tconst StackElement& top = trunkStack.top();\n\t\treturn top.trunk->subNodes[top.curIndex].asObject();\n\t}\n\n\tFilteredTreeIteratorPrototype& operator++() {\n\t\tStackElement& top = trunkStack.top();\n\t\ttop.curIndex++;\n\t\tthis->delveDown();\n\t\treturn *this;\n\t}\n\n\tbool operator!=(IteratorEnd) const {\n\t\treturn trunkStack.size() != 0;\n\t}\n};\n\nclass BoundsTreePrototype {\n\tTreeTrunk baseTrunk;\n\tint baseTrunkSize;\n\tTrunkAllocator allocator;\n\n\ttemplate<typename Boundable>\n\tfriend class BoundsTree;\n\npublic:\n\tBoundsTreePrototype();\n\t~BoundsTreePrototype();\n\n\tinline BoundsTreePrototype(BoundsTreePrototype&& other) noexcept : baseTrunk(std::move(other.baseTrunk)), baseTrunkSize(other.baseTrunkSize), allocator(std::move(other.allocator)) {\n\t\tother.baseTrunkSize = 0;\n\t}\n\tinline BoundsTreePrototype& operator=(BoundsTreePrototype&& other) noexcept {\n\t\tthis->baseTrunk = std::move(other.baseTrunk);\n\t\tthis->baseTrunkSize = other.baseTrunkSize;\n\t\tthis->allocator = std::move(other.allocator);\n\n\t\tother.baseTrunkSize = 0;\n\n\t\treturn *this;\n\t}\n\n\tvoid add(void* newObject, const BoundsTemplate<float>& bounds);\n\tvoid remove(const void* objectToRemove, const BoundsTemplate<float>& bounds);\n\n\tvoid addToGroup(void* newObject, const BoundsTemplate<float>& newObjectBounds, const void* groupRepresentative, const BoundsTemplate<float>& groupRepBounds);\n\tvoid mergeGroups(const void* groupRepA, const BoundsTemplate<float>& repABounds, const void* groupRepB, const BoundsTemplate<float>& repBBounds);\n\tvoid transferGroupTo(const void* groupRep, const BoundsTemplate<float>& groupRepBounds, BoundsTreePrototype& destinationTree);\n\t\n\tvoid updateObjectBounds(const void* object, const BoundsTemplate<float>& originalBounds, const BoundsTemplate<float>& newBounds);\n\t// oldObject and newObject should have the same bounds\n\tvoid findAndReplaceObject(const void* oldObject, void* newObject, const BoundsTemplate<float>& bounds);\n\n\tvoid disbandGroup(const void* groupRep, const BoundsTemplate<float>& groupRepBounds);\n\n\tbool contains(const void* object, const BoundsTemplate<float>& bounds) const;\n\tbool groupContains(const void* groupRep, const BoundsTemplate<float>& groupRepBounds, const void* object, const BoundsTemplate<float>& bounds) const;\n\tsize_t size() const;\n\tsize_t groupSize(const void* groupRep, const BoundsTemplate<float>& groupRepBounds) const;\n\n\tinline bool isEmpty() const {\n\t\treturn this->baseTrunkSize == 0;\n\t}\n\n\tvoid clear();\n\n\n\ttemplate<typename GroupIter, typename GroupIterEnd>\n\tvoid removeSubGroup(GroupIter iter, const GroupIterEnd& iterEnd) {\n\t\tif(!(iter != iterEnd)) return;\n\t\tstd::pair<const void*, BoundsTemplate<float>> firstObject = *iter;\n\t\t++iter;\n\t\tif(!(iter != iterEnd)) { // just one item\n\t\t\tthis->remove(firstObject.first, firstObject.second);\n\t\t} else {\n\t\t\tint newMainSize = contractGroupRecursive(this->allocator, this->baseTrunk, this->baseTrunkSize, firstObject.first, firstObject.second, [this, &iter, &iterEnd, &firstObject](TreeNodeRef& group, const BoundsTemplate<float>& groupNodeBounds) {\n\t\t\t\tif(!group.isTrunkNode()) {\n\t\t\t\t\tthrow \"Attempting to remove more than one object from a single-object group!\";\n\t\t\t\t}\n\t\t\t\tTreeTrunk& groupTrunk = group.asTrunk();\n\t\t\t\tint groupTrunkSize = group.getTrunkSize();\n\n\t\t\t\tgroupTrunkSize = removeRecursive(this->allocator, groupTrunk, groupTrunkSize, firstObject.first, firstObject.second);\n\t\t\t\tassert(groupTrunkSize != -1); // should have been verified \n\n\t\t\t\tdo {\n\t\t\t\t\tstd::pair<const void*, BoundsTemplate<float>> currentlyMoving = *iter;\n\t\t\t\t\tgroupTrunkSize = removeRecursive(this->allocator, groupTrunk, groupTrunkSize, currentlyMoving.first, currentlyMoving.second);\n\t\t\t\t\tif(groupTrunkSize == -1) {\n\t\t\t\t\t\tthrow \"Iterator provided an object which could not be found in this group!\";\n\t\t\t\t\t}\n\t\t\t\t\t++iter;\n\t\t\t\t} while(iter != iterEnd);\n\n\t\t\t\tif(groupTrunkSize >= 2) {\n\t\t\t\t\tgroup.setTrunkSize(groupTrunkSize);\n\t\t\t\t\treturn std::optional<BoundsTemplate<float>>(TrunkSIMDHelperFallback::getTotalBounds(groupTrunk, groupTrunkSize));\n\t\t\t\t} else if(groupTrunkSize == 1) {\n\t\t\t\t\tBoundsTemplate<float> resultingBounds = groupTrunk.getBoundsOfSubNode(0);\n\t\t\t\t\tgroup = std::move(groupTrunk.subNodes[0]);\n\t\t\t\t\tif(group.isTrunkNode()) {\n\t\t\t\t\t\tgroup.makeGroupHead(); // make sure to preserve the group head if the trunk is overwritten\n\t\t\t\t\t}\n\t\t\t\t\tthis->allocator.freeTrunk(&groupTrunk);\n\t\t\t\t\treturn std::optional<BoundsTemplate<float>>(resultingBounds);\n\t\t\t\t} else {\n\t\t\t\t\tthis->allocator.freeTrunk(&groupTrunk);\n\t\t\t\t\treturn std::optional<BoundsTemplate<float>>();\n\t\t\t\t}\n\t\t\t});\n\t\t\tthis->baseTrunkSize = newMainSize;\n\t\t}\n\t}\n\n\t// the given iterator should return objects of type std::pair<void*, BoundsTemplate<float>>\n\ttemplate<typename GroupIter, typename GroupIterEnd>\n\tvoid transferSplitGroupTo(GroupIter iter, const GroupIterEnd& iterEnd, BoundsTreePrototype& destinationTree) {\n\t\tif(!(iter != iterEnd)) return; // no items\n\n\t\tthis->removeSubGroup(iter, iterEnd);\n\n\t\tstd::pair<const void*, BoundsTemplate<float>> firstObject = *iter;\n\t\t++iter;\n\t\t\n\t\tif(iter != iterEnd) {\n\t\t\tTreeTrunk* newGroupTrunk = destinationTree.allocator.allocTrunk();\n\t\t\tnewGroupTrunk->setSubNode(0, TreeNodeRef(const_cast<void*>(firstObject.first)), firstObject.second);\n\t\t\tint newGroupTrunkSize = 1;\n\n\t\t\tdo {\n\t\t\t\tstd::pair<const void*, BoundsTemplate<float>> obj = *iter;\n\t\t\t\tnewGroupTrunkSize = addRecursive(destinationTree.allocator, *newGroupTrunk, newGroupTrunkSize, TreeNodeRef(const_cast<void*>(obj.first)), obj.second);\n\t\t\t\t++iter;\n\t\t\t} while(iter != iterEnd);\n\n\t\t\tdestinationTree.baseTrunkSize = addRecursive(destinationTree.allocator, destinationTree.baseTrunk, destinationTree.baseTrunkSize, TreeNodeRef(newGroupTrunk, newGroupTrunkSize, true), TrunkSIMDHelperFallback::getTotalBounds(*newGroupTrunk, newGroupTrunkSize));\n\t\t} else {\n\t\t\tdestinationTree.add(const_cast<void*>(firstObject.first), firstObject.second);\n\t\t}\n\t}\n\n\t// the given iterator should return objects of type std::pair<void*, BoundsTemplate<float>>\n\ttemplate<typename GroupIter, typename GroupIterEnd>\n\tvoid splitGroup(GroupIter iter, const GroupIterEnd& iterEnd) {\n\t\tthis->transferSplitGroupTo(iter, iterEnd, *this);\n\t}\n\n\tvoid improveStructure();\n\tvoid maxImproveStructure();\n\n\tBoundsTreeIteratorPrototype begin() const { return BoundsTreeIteratorPrototype(baseTrunk, baseTrunkSize); }\n\tIteratorEnd end() const { return IteratorEnd(); }\n\n\ttemplate<typename Filter>\n\tIteratorFactoryWithEnd<FilteredTreeIteratorPrototype<Filter>> iterFiltered(const Filter& filter) const { \n\t\treturn IteratorFactoryWithEnd<FilteredTreeIteratorPrototype<Filter>>{FilteredTreeIteratorPrototype<Filter>(baseTrunk, baseTrunkSize, filter)}; \n\t}\n\n\t// unsafe functions\n\tinline std::pair<TreeTrunk&, int> getBaseTrunk() { return std::pair<TreeTrunk&, int>(this->baseTrunk, this->baseTrunkSize); }\n\tinline std::pair<const TreeTrunk&, int> getBaseTrunk() const { return std::pair<const TreeTrunk&, int>(this->baseTrunk, this->baseTrunkSize); }\n\n\tinline TrunkAllocator& getAllocator() { return allocator; }\n\tinline const TrunkAllocator& getAllocator() const { return allocator; }\n\n\tvoid addGroupTrunk(TreeTrunk* newNode, int newNodeSize);\n};\n\ntemplate<typename Boundable>\nvoid recalculateBoundsRecursive(TreeTrunk& curTrunk, int curTrunkSize) {\n\tfor(int i = 0; i < curTrunkSize; i++) {\n\t\tTreeNodeRef& subNode = curTrunk.subNodes[i];\n\n\t\tif(subNode.isTrunkNode()) {\n\t\t\tTreeTrunk& subTrunk = subNode.asTrunk();\n\t\t\tint subTrunkSize = subNode.getTrunkSize();\n\t\t\trecalculateBoundsRecursive<Boundable>(subTrunk, subTrunkSize);\n\t\t\tcurTrunk.setBoundsOfSubNode(i, TrunkSIMDHelperFallback::getTotalBounds(subTrunk, subTrunkSize));\n\t\t} else {\n\t\t\tBoundable* object = static_cast<Boundable*>(subNode.asObject());\n\t\t\tcurTrunk.setBoundsOfSubNode(i, object->getBounds());\n\t\t}\n\t}\n}\n\ntemplate<typename Boundable>\nbool updateGroupBoundsRecursive(TreeTrunk& curTrunk, int curTrunkSize, const Boundable* groupRep, const BoundsTemplate<float>& originalGroupRepBounds) {\n\tassert(curTrunkSize >= 0 && curTrunkSize <= BRANCH_FACTOR);\n\tstd::array<bool, BRANCH_FACTOR> couldContain = TrunkSIMDHelperFallback::getAllContainsBounds(curTrunk, originalGroupRepBounds);\n\tfor(int i = 0; i < curTrunkSize; i++) {\n\t\tif(!couldContain[i]) continue;\n\n\t\tTreeNodeRef& subNode = curTrunk.subNodes[i];\n\t\tif(subNode.isTrunkNode()) {\n\t\t\tTreeTrunk& subTrunk = subNode.asTrunk();\n\t\t\tint subTrunkSize = subNode.getTrunkSize();\n\t\t\tif(subNode.isGroupHead()) {\n\t\t\t\tif(containsObjectRecursive(subTrunk, subTrunkSize, groupRep, originalGroupRepBounds)) {\n\t\t\t\t\trecalculateBoundsRecursive<Boundable>(subTrunk, subTrunkSize);\n\t\t\t\t\tcurTrunk.setBoundsOfSubNode(i, TrunkSIMDHelperFallback::getTotalBounds(subTrunk, subTrunkSize));\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif(updateGroupBoundsRecursive<Boundable>(subTrunk, subTrunkSize, groupRep, originalGroupRepBounds)) {\n\t\t\t\t\tcurTrunk.setBoundsOfSubNode(i, TrunkSIMDHelperFallback::getTotalBounds(subTrunk, subTrunkSize));\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tif(subNode.asObject() == groupRep) {\n\t\t\t\tcurTrunk.setBoundsOfSubNode(i, groupRep->getBounds());\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n}\n\ntemplate<typename Boundable, typename UnderlyingIter>\nclass BoundableCastIterator {\n\tUnderlyingIter iter;\npublic:\n\tBoundableCastIterator() = default;\n\tBoundableCastIterator(const UnderlyingIter& iter) : iter(iter) {}\n\tBoundableCastIterator(const TreeTrunk& baseTrunk, int baseTrunkSize) : iter(baseTrunk, baseTrunkSize) {}\n\n\tBoundableCastIterator& operator++() { ++iter; return *this; }\n\tBoundable& operator*() const { return *static_cast<Boundable*>(*iter); }\n\tbool operator!=(IteratorEnd) const { return iter != IteratorEnd{}; }\n};\n\ntemplate<typename Boundable>\nclass BoundsTree {\n\tBoundsTreePrototype tree;\n\npublic:\n\tinline const BoundsTreePrototype& getPrototype() const { return tree; }\n\tinline BoundsTreePrototype& getPrototype() { return tree; }\n\n\ttemplate<typename BoundableIter>\n\tstruct BoundableIteratorAdapter {\n\t\tBoundableIter iter;\n\n\t\tstd::pair<const void*, BoundsTemplate<float>> operator*() const {\n\t\t\tconst Boundable* item = *iter;\n\t\t\treturn std::pair<const void*, BoundsTemplate<float>>(static_cast<const void*>(item), item->getBounds());\n\t\t}\n\t\tBoundableIteratorAdapter& operator++() {\n\t\t\t++iter;\n\t\t\treturn *this;\n\t\t}\n\t\ttemplate<typename BoundableIterEnd>\n\t\tbool operator!=(const BoundableIterEnd& end) const {\n\t\t\treturn this->iter != end;\n\t\t}\n\t};\n\n\tvoid add(Boundable* newObject) {\n\t\ttree.add(static_cast<void*>(newObject), newObject->getBounds());\n\t}\n\tvoid remove(const Boundable* objectToRemove) {\n\t\ttree.remove(static_cast<const void*>(objectToRemove), objectToRemove->getBounds());\n\t}\n\tvoid addToGroup(Boundable* newObject, const Boundable* groupRepresentative) {\n\t\ttree.addToGroup(static_cast<void*>(newObject), newObject->getBounds(), static_cast<const void*>(groupRepresentative), groupRepresentative->getBounds());\n\t}\n\ttemplate<typename BoundableIter, typename BoundableIterEnd>\n\tvoid addAllToGroup(BoundableIter iter, const BoundableIterEnd& iterEnd, const Boundable* groupRep) {\n\t\tif(!(iter != iterEnd)) return;\n\t\tmodifyGroupRecursive(tree.allocator, tree.baseTrunk, tree.baseTrunkSize, groupRep, groupRep->getBounds(), [this, &iter, &iterEnd](TreeNodeRef& groupNode, BoundsTemplate<float> groupBounds) {\n\t\t\tif(groupNode.isLeafNode()) {\n\t\t\t\tTreeTrunk* newTrunk = this->tree.allocator.allocTrunk();\n\t\t\t\tnewTrunk->setSubNode(0, std::move(groupNode), groupBounds);\n\n\t\t\t\tBoundable* newObj = *iter;\n\t\t\t\tBoundsTemplate<float> newObjBounds = newObj->getBounds();\n\t\t\t\tnewTrunk->setSubNode(1, TreeNodeRef(newObj), newObjBounds);\n\n\t\t\t\tgroupNode = TreeNodeRef(newTrunk, 2, true);\n\t\t\t\t++iter;\n\t\t\t}\n\t\t\tTreeTrunk& trunk = groupNode.asTrunk();\n\t\t\tint curTrunkSize = groupNode.getTrunkSize();\n\t\t\twhile(iter != iterEnd) {\n\t\t\t\tBoundable* curObj = *iter;\n\t\t\t\tBoundsTemplate<float> curObjBounds = curObj->getBounds();\n\n\t\t\t\tcurTrunkSize = addRecursive(this->tree.allocator, trunk, curTrunkSize, TreeNodeRef(curObj), curObjBounds);\n\n\t\t\t\t++iter;\n\t\t\t}\n\t\t\treturn TrunkSIMDHelperFallback::getTotalBounds(trunk, curTrunkSize);\n\t\t});\n\t}\n\tvoid mergeGroups(const Boundable* groupRepA, const Boundable* groupRepB) {\n\t\ttree.mergeGroups(static_cast<const void*>(groupRepA), groupRepA->getBounds(), static_cast<const void*>(groupRepB), groupRepB->getBounds());\n\t}\n\tbool contains(const Boundable* object) const {\n\t\treturn tree.contains(static_cast<const void*>(object), object->getBounds());\n\t}\n\tbool groupContains(const Boundable* groupRep, const Boundable* object) const {\n\t\tassert(this->contains(groupRep));\n\t\treturn tree.groupContains(static_cast<const void*>(groupRep), groupRep->getBounds(), static_cast<const void*>(object), object->getBounds());\n\t}\n\tvoid updateObjectBounds(const Boundable* object, const BoundsTemplate<float>& originalBounds) {\n\t\ttree.updateObjectBounds(static_cast<const void*>(object), originalBounds, object->getBounds());\n\t}\n\tvoid updateObjectGroupBounds(const Boundable* groupRep, const BoundsTemplate<float>& originalGroupRepBounds) {\n\t\tbool success = updateGroupBoundsRecursive<Boundable>(tree.baseTrunk, tree.baseTrunkSize, groupRep, originalGroupRepBounds);\n\t\tif(!success) throw \"groupRep was not found in tree!\";\n\t}\n\t// oldObject and newObject should have the same bounds\n\tvoid findAndReplaceObject(const Boundable* oldObject, Boundable* newObject, const BoundsTemplate<float>& bounds) {\n\t\tassert(this->tree.contains(oldObject, bounds));\n\t\ttree.findAndReplaceObject(static_cast<const void*>(oldObject), static_cast<void*>(newObject), bounds);\n\t}\n\tvoid disbandGroup(const Boundable* groupRep) {\n\t\tassert(this->contains(groupRep));\n\t\ttree.disbandGroup(static_cast<const void*>(groupRep), groupRep->getBounds());\n\t}\n\tsize_t size() const {\n\t\treturn tree.size();\n\t}\n\tsize_t groupSize(const Boundable* groupRep) const {\n\t\treturn tree.groupSize(static_cast<const void*>(groupRep), groupRep->getBounds());\n\t}\n\tbool isEmpty() const {\n\t\treturn tree.isEmpty();\n\t}\n\tvoid clear() {\n\t\ttree.clear();\n\t}\n\n\tvoid transferGroupTo(const Boundable* groupRep, BoundsTree& destinationTree) {\n\t\ttree.transferGroupTo(static_cast<const void*>(groupRep), groupRep->getBounds(), destinationTree.tree);\n\t}\n\n\t// the given iterator should return objects of type Boundable*\n\ttemplate<typename GroupIter, typename GroupIterEnd>\n\tvoid transferSplitGroupTo(GroupIter&& iter, const GroupIterEnd& iterEnd, BoundsTree& destinationTree) {\n\t\ttree.transferSplitGroupTo(BoundableIteratorAdapter<GroupIter>{std::move(iter)}, iterEnd, destinationTree.tree);\n\t}\n\n\tvoid transferTo(Boundable* obj, BoundsTree& destinationTree) {\n\t\tBoundsTemplate<float> bounds = obj->getBounds();\n\t\ttree.remove(static_cast<void*>(obj), bounds);\n\t\tdestinationTree.tree.add(static_cast<void*>(obj), bounds);\n\t}\n\n\tvoid moveOutOfGroup(Boundable* obj) {\n\t\tBoundsTemplate<float> bounds = obj->getBounds();\n\t\ttree.remove(static_cast<void*>(obj), bounds);\n\t\ttree.add(static_cast<void*>(obj), bounds);\n\t}\n\n\t// the given iterator should return objects of type Boundable*\n\ttemplate<typename GroupIter, typename GroupIterEnd>\n\tvoid splitGroup(GroupIter iter, const GroupIterEnd& iterEnd) {\n\t\ttree.splitGroup(BoundableIteratorAdapter<GroupIter>{std::move(iter)}, iterEnd);\n\t}\n\n\t// expects a function of the form void(Boundable& object)\n\ttemplate<typename Func>\n\tvoid forEach(const Func& func) const {\n\t\tforEachRecurse<Boundable, Func>(this->tree.baseTrunk, this->tree.baseTrunkSize, func);\n\t}\n\n\t// expects a function of the form void(Boundable& object)\n\ttemplate<typename Filter, typename Func>\n\tvoid forEachFiltered(const Filter& filter, const Func& func) const {\n\t\tforEachFilteredRecurse<Boundable, Filter, Func>(this->tree.baseTrunk, this->tree.baseTrunkSize, filter, func);\n\t}\n\n\t// expects a function of the form void(Boundable& object)\n\ttemplate<typename Func>\n\tvoid forEachInGroup(const void* groupRepresentative, const BoundsTemplate<float>& groupRepBounds, const Func& func) const {\n\t\tconst TreeNodeRef* group = getGroupRecursive(this->tree.baseTrunk, this->tree.baseTrunkSize, groupRepresentative, groupRepBounds);\n\t\tif(group == nullptr) {\n\t\t\tthrow \"Group not found!\";\n\t\t}\n\t\tif(group->isTrunkNode()) {\n\t\t\tforEachRecurse<Boundable, Func>(group->asTrunk(), group->getTrunkSize(), func);\n\t\t} else {\n\t\t\tfunc(*static_cast<Boundable*>(group->asObject()));\n\t\t}\n\t}\n\n\tBoundableCastIterator<Boundable, BoundsTreeIteratorPrototype> begin() const { return BoundableCastIterator<Boundable, BoundsTreeIteratorPrototype>(this->tree.begin()); }\n\tIteratorEnd end() const { return IteratorEnd(); }\n\n\ttemplate<typename Filter>\n\tIteratorFactoryWithEnd<BoundableCastIterator<Boundable, FilteredTreeIteratorPrototype<Filter>>> iterFiltered(const Filter& filter) const { \n\t\treturn IteratorFactoryWithEnd<BoundableCastIterator<Boundable, FilteredTreeIteratorPrototype<Filter>>>{\n\t\t\tBoundableCastIterator<Boundable, FilteredTreeIteratorPrototype<Filter>>(\n\t\t\t\tFilteredTreeIteratorPrototype<Filter>(this->tree.baseTrunk, this->tree.baseTrunkSize, filter)\n\t\t\t)\n\t\t};\n\t}\n\n\ttemplate<typename Func>\n\tvoid forEachColission(const Func& func) const {\n\t\tif(this->tree.baseTrunkSize == 0) return;\n\t\tforEachColissionInternalRecursive<Boundable, TrunkSIMDHelperFallback, Func>(this->tree.baseTrunk, this->tree.baseTrunkSize, func);\n\t}\n\n\ttemplate<typename Func>\n\tvoid forEachColissionWith(const BoundsTree& other, const Func& func) const {\n\t\tif(this->tree.baseTrunkSize == 0 || other.tree.baseTrunkSize == 0) return;\n\t\tforEachColissionBetweenRecursive<Boundable, TrunkSIMDHelperFallback, Func>(this->tree.baseTrunk, this->tree.baseTrunkSize, other.tree.baseTrunk, other.tree.baseTrunkSize, func);\n\t}\n\n\tvoid recalculateBounds() {\n\t\trecalculateBoundsRecursive<Boundable>(this->tree.baseTrunk, this->tree.baseTrunkSize);\n\t}\n\n\tvoid improveStructure() { tree.improveStructure(); }\n\tvoid maxImproveStructure() { tree.maxImproveStructure(); }\n};\n\nstruct BasicBounded {\n\tBoundsTemplate<float> bounds;\n\tBoundsTemplate<float> getBounds() const { return bounds; }\n};\n\n};\n"
  },
  {
    "path": "Physics3D/boundstree/boundsTreeAVX.cpp",
    "content": "#include \"boundsTree.h\" \n\n#include \"../datastructures/alignedPtr.h\"\n#include <immintrin.h>\n\nnamespace P3D {\n\nOverlapMatrix TrunkSIMDHelperFallback::computeBoundsOverlapMatrixAVX(const TreeTrunk& trunkA, int trunkASize, const TreeTrunk& trunkB, int trunkBSize) {\n\tOverlapMatrix result;\n\n    __m256 rx0 = _mm256_set1_ps(0);\n    __m256 ry0 = _mm256_set1_ps(0);\n    __m256 rz0 = _mm256_set1_ps(0);\n\n    __m256 rx1 = _mm256_set1_ps(0);\n    __m256 ry1 = _mm256_set1_ps(0);\n    __m256 rz1 = _mm256_set1_ps(0);\n    \n    alignas(32) float tempBuff[8];\n\n\n    __m256 bxmin = _mm256_load_ps(trunkB.subNodeBounds.xMin);\n    \n    __m256 bymin = _mm256_load_ps(trunkB.subNodeBounds.yMin);\n    \n    __m256 bzmin = _mm256_load_ps(trunkB.subNodeBounds.zMin);\n    \n    __m256 bxmax = _mm256_load_ps(trunkB.subNodeBounds.xMax);\n    \n    __m256 bymax = _mm256_load_ps(trunkB.subNodeBounds.yMax);\n    \n    __m256 bzmax = _mm256_load_ps(trunkB.subNodeBounds.zMax);\n\n\n\n\tfor(int a = 0; a < trunkASize; a++) {\n\t\t\n    \tBoundsTemplate<float> aBounds0 = trunkA.getBoundsOfSubNode(a);\n     \n        __m256 axmin = _mm256_set1_ps(aBounds0.min.x);\n\n        __m256 aymin = _mm256_set1_ps(aBounds0.min.y);\n\n        __m256 azmin = _mm256_set1_ps(aBounds0.min.z);\n\n        __m256 axmax = _mm256_set1_ps(aBounds0.max.x);\n\n        __m256 aymax = _mm256_set1_ps(aBounds0.max.y);\n\n        __m256 azmax = _mm256_set1_ps(aBounds0.max.z);\n\n\n\n            rx0 = _mm256_cmp_ps(axmax, bxmin, _CMP_GE_OQ);\n\n            ry0 = _mm256_cmp_ps(aymax, bymin, _CMP_GE_OQ);\n\n            rz0 = _mm256_cmp_ps(azmax, bzmin, _CMP_GE_OQ);\n\n            rx1 = _mm256_cmp_ps(axmin, bxmax, _CMP_LE_OQ);\n\n            ry1 = _mm256_cmp_ps(aymin, bymax, _CMP_LE_OQ);\n\n            rz1 = _mm256_cmp_ps(azmin, bzmax, _CMP_LE_OQ);\n\n\n            __m256 resultBool = _mm256_and_ps(  _mm256_and_ps(_mm256_and_ps(rx0, ry0), rz0),\n                                                _mm256_and_ps( _mm256_and_ps(rx1, ry1), rz1)  );\n\n\n            _mm256_store_ps(tempBuff, resultBool);\n\n\t\t\t\n            result[a][0] =  tempBuff[0];\n            result[a][1] =  tempBuff[1];\n            result[a][2] =  tempBuff[2];\n            result[a][3] =  tempBuff[3];\n            result[a][4] =  tempBuff[4];\n            result[a][5] =  tempBuff[5];\n            result[a][6] =  tempBuff[6];\n            result[a][7] =  tempBuff[7];\n\n\t\t\n\t}\n\treturn result;\n}\n\n\n\n\n\n\n}"
  },
  {
    "path": "Physics3D/boundstree/boundsTreeSSE.cpp",
    "content": "#include \"boundsTree.h\" \n\n#include \"../datastructures/alignedPtr.h\"\n#include <immintrin.h>\n \nnamespace P3D {\n\nOverlapMatrix TrunkSIMDHelperFallback::computeBoundsOverlapMatrixSSE(const TreeTrunk& trunkA, int trunkASize, const TreeTrunk& trunkB, int trunkBSize) {\n\tOverlapMatrix result;\n\n    __m128 rx0 = _mm_set1_ps(0);\n    __m128 ry0 = _mm_set1_ps(0);\n    __m128 rz0 = _mm_set1_ps(0);\n\n    __m128 rx1 = _mm_set1_ps(0);\n    __m128 ry1 = _mm_set1_ps(0);\n    __m128 rz1 = _mm_set1_ps(0);\n    \n    alignas(32) float tempBuff[4];\n\n\n\n\n\tfor(int a = 0; a < trunkASize; a++) {\n\t\t\n    \tBoundsTemplate<float> aBounds0 = trunkA.getBoundsOfSubNode(a);\n     \n        __m128 axmin = _mm_set1_ps(aBounds0.min.x);\n\n        __m128 aymin = _mm_set1_ps(aBounds0.min.y);\n\n        __m128 azmin = _mm_set1_ps(aBounds0.min.z);\n\n        __m128 axmax = _mm_set1_ps(aBounds0.max.x);\n\n        __m128 aymax = _mm_set1_ps(aBounds0.max.y);\n\n        __m128 azmax = _mm_set1_ps(aBounds0.max.z);\n\n\n        for(unsigned short int i=0; i<2; i++){\n\n            __m128 bxmin = _mm_load_ps(trunkB.subNodeBounds.xMin + i * 4);\n    \n            __m128 bymin = _mm_load_ps(trunkB.subNodeBounds.yMin + i * 4);\n    \n            __m128 bzmin = _mm_load_ps(trunkB.subNodeBounds.zMin + i * 4);\n    \n            __m128 bxmax = _mm_load_ps(trunkB.subNodeBounds.xMax + i * 4);\n    \n            __m128 bymax = _mm_load_ps(trunkB.subNodeBounds.yMax + i * 4);\n    \n            __m128 bzmax = _mm_load_ps(trunkB.subNodeBounds.zMax + i * 4);\n\n\n            rx0 = _mm_cmp_ps(axmax, bxmin, _CMP_GE_OQ);\n\n            ry0 = _mm_cmp_ps(aymax, bymin, _CMP_GE_OQ);\n\n            rz0 = _mm_cmp_ps(azmax, bzmin, _CMP_GE_OQ);\n\n            rx1 = _mm_cmp_ps(axmin, bxmax, _CMP_LE_OQ);\n\n            ry1 = _mm_cmp_ps(aymin, bymax, _CMP_LE_OQ);\n\n            rz1 = _mm_cmp_ps(azmin, bzmax, _CMP_LE_OQ);\n\n\n            __m128 resultBool = _mm_and_ps(  _mm_and_ps(_mm_and_ps(rx0, ry0), rz0),\n                                                _mm_and_ps( _mm_and_ps(rx1, ry1), rz1)  );\n\n\n            _mm_store_ps(tempBuff, resultBool);\n\n\t\t\t\n            result[a][0 + i * 4] =  tempBuff[0];\n            result[a][1 + i * 4] =  tempBuff[1];\n            result[a][2 + i * 4] =  tempBuff[2];\n            result[a][3 + i * 4] =  tempBuff[3];\n\n        }\n\t}\n\treturn result;\n}\n\n\n\n\n\n\n}"
  },
  {
    "path": "Physics3D/boundstree/filters/outOfBoundsFilter.h",
    "content": "#pragma once\n\n#include \"../../math/bounds.h\"\n#include \"../boundsTree.h\"\n#include \"../../part.h\"\n\nnamespace P3D {\nstruct OutOfBoundsFilter {\n\tBounds bounds;\n\n\tOutOfBoundsFilter() = default;\n\tOutOfBoundsFilter(const Bounds& bounds) : bounds(bounds) {}\n\n\tstd::array<bool, BRANCH_FACTOR> operator()(const TreeTrunk& trunk, int trunkSize) const {\n\t\tstd::array<bool, BRANCH_FACTOR> results;\n\t\tfor(int i = 0; i < trunkSize; i++) {\n\t\t\tresults[i] = !this->bounds.contains(trunk.getBoundsOfSubNode(i));\n\t\t}\n\t\treturn results;\n\t}\n\tbool operator()(const Part& part) const {\n\t\treturn true;\n\t}\n};\n};"
  },
  {
    "path": "Physics3D/boundstree/filters/rayIntersectsBoundsFilter.h",
    "content": "#pragma once\n\n#include \"../../math/bounds.h\"\n#include \"../../math/ray.h\"\n#include \"../../part.h\"\n#include \"../boundsTree.h\"\n\nnamespace P3D {\nstruct RayIntersectBoundsFilter {\n\tRay ray;\n\n\tRayIntersectBoundsFilter() = default;\n\tRayIntersectBoundsFilter(const Ray& ray) : ray(ray) {}\n\n\tstd::array<bool, BRANCH_FACTOR> operator()(const TreeTrunk& trunk, int trunkSize) const {\n\t\tstd::array<bool, BRANCH_FACTOR> results;\n\t\tfor(int i = 0; i < trunkSize; i++) {\n\t\t\tresults[i] = doRayAndBoundsIntersect(trunk.getBoundsOfSubNode(i), this->ray);\n\t\t}\n\t\treturn results;\n\t}\n\tbool operator()(const Part& part) const {\n\t\treturn true;\n\t}\n};\n};\n"
  },
  {
    "path": "Physics3D/boundstree/filters/visibilityFilter.cpp",
    "content": "#include \"visibilityFilter.h\"\n\n#include \"../../math/linalg/trigonometry.h\"\n#include \"../../math/position.h\"\n#include \"../../math/bounds.h\"\n#include \"../../part.h\"\n\nnamespace P3D {\nVisibilityFilter::VisibilityFilter(const Position& origin, Vec3 normals[5], double maxDepth) :\n\torigin(origin),\n\tup(normals[0]), down(normals[1]), left(normals[2]), right(normals[3]), forward(normals[4]),\n\tmaxDepth(maxDepth) {}\n\nVisibilityFilter VisibilityFilter::fromSteps(const Position& origin, const Vec3& stepForward, const Vec3& stepUp, const Vec3& stepRight, double maxDepth) {\n\tVec3 upNormal = (stepForward + stepUp) % stepRight;\n\tVec3 downNormal = -(stepForward - stepUp) % stepRight;\n\tVec3 leftNormal = -(stepForward + stepRight) % stepUp;\n\tVec3 rightNormal = (stepForward - stepRight) % stepUp;\n\n\tVec3 normals[5]{upNormal, downNormal, leftNormal, rightNormal, stepForward};\n\n\treturn VisibilityFilter(origin, normals, maxDepth);\n}\n\nVisibilityFilter VisibilityFilter::fromSteps(const Position& origin, const Vec3& stepForward, const Vec3& stepUp, const Vec3& stepRight, double maxDepth, double left, double right, double down, double up) {\n\tVec3 upNormal = (stepForward + stepUp * up) % stepRight;\n\tVec3 downNormal = -(stepForward + stepUp * down) % stepRight;\n\tVec3 leftNormal = -(stepForward - stepRight * left) % stepUp;\n\tVec3 rightNormal = (stepForward - stepRight * right) % stepUp;\n\n\tVec3 normals[5]{upNormal, downNormal, leftNormal, rightNormal, stepForward};\n\n\treturn VisibilityFilter(origin, normals, maxDepth);\n}\n\nVisibilityFilter VisibilityFilter::forWindow(const Position& origin, const Vec3& cameraForward, const Vec3& cameraUp, double fov, double aspect, double maxDepth) {\n\tdouble tanFov = tan(fov / 2);\n\n\tVec3 stepForward = normalize(cameraForward);\n\tVec3 stepUp = normalize(cameraUp) * tanFov;\n\tVec3 stepRight = normalize(cameraUp % cameraForward) * tanFov * aspect;\n\n\treturn fromSteps(\n\t\torigin,\n\t\tstepForward,\n\t\tstepUp,\n\t\tstepRight,\n\t\tmaxDepth\n\t);\n}\n\nVisibilityFilter VisibilityFilter::forSubWindow(const Position& origin, const Vec3& cameraForward, const Vec3& cameraUp, double fov, double aspect, double maxDepth, double left, double right, double down, double up) {\n\tdouble tanFov = tan(fov / 2);\n\n\tVec3 stepForward = normalize(cameraForward);\n\tVec3 stepUp = normalize(cameraUp) * tanFov;\n\tVec3 stepRight = normalize(cameraUp % cameraForward) * tanFov * aspect;\n\n\treturn fromSteps(\n\t\torigin,\n\t\tstepForward,\n\t\tstepUp,\n\t\tstepRight,\n\t\tmaxDepth,\n\t\tleft, right, down, up\n\t);\n}\n\nbool VisibilityFilter::operator()(const Position& point) const {\n\tdouble offsets[5]{0,0,0,0,maxDepth};\n\tVec3 normals[5]{up, down, left, right, forward};\n\tfor(int i = 0; i < 5; i++) {\n\t\tVec3& normal = normals[i];\n\n\t\tVec3 relativePos = point - origin;\n\t\tif(relativePos * normal > offsets[i])\n\t\t\treturn false;\n\t}\n\treturn true;\n}\n\nbool VisibilityFilter::operator()(const Bounds& bounds) const {\n\tdouble offsets[5]{0,0,0,0,maxDepth};\n\tVec3 normals[5]{up, down, left, right, forward};\n\tfor(int i = 0; i < 5; i++) {\n\t\tVec3& normal = normals[i];\n\t\t// we're checking that *a* corner of the TreeNode's bounds is within the viewport, basically similar to rectangle-rectangle colissions, google it!\n\t\t// cornerOfInterest is the corner that is the furthest positive corner relative to the normal, so if it is not visible (eg above the normal) then the whole box must be invisible\n\t\tPosition cornerOfInterest(\n\t\t\t(normal.x >= 0) ? bounds.min.x : bounds.max.x,\n\t\t\t(normal.y >= 0) ? bounds.min.y : bounds.max.y, // let's look at the top of the viewport, if the bottom of the box is above this then the whole box must be above it. \n\t\t\t(normal.z >= 0) ? bounds.min.z : bounds.max.z\n\t\t);\n\n\t\tVec3 relativePos = cornerOfInterest - origin;\n\t\tif(relativePos * normal > offsets[i])\n\t\t\treturn false;\n\t}\n\treturn true;\n}\n\n\nbool VisibilityFilter::operator()(const Part& part) const {\n\treturn true;\n}\n};\n/*   A\n\t/\n   / o---o  <-- cornerOfInterest for B\n  /  |   |\n /   |   |\no    o---o  <-- cornerOfInterest for A\n \\\n  \\\n   \\\n\t\\\n\t B\n\n\nA               B\n \\       COI B /\n  \\        v  /\n   \\       o---o <- COI A\n\t\\      |/  |\n\t \\     |   |\n\t  \\   /o---o\n\t   \\ /\n\t\to\n\n*/"
  },
  {
    "path": "Physics3D/boundstree/filters/visibilityFilter.h",
    "content": "#pragma once\n\n#include \"../../math/linalg/vec.h\"\n#include \"../../math/bounds.h\"\n#include \"../../part.h\"\n\nnamespace P3D {\nclass VisibilityFilter {\npublic:\n\tPosition origin;\nprivate:\n\t// normals of the viewPort, facing outward\n\tVec3 up;\n\tVec3 down;\n\tVec3 left;\n\tVec3 right;\n\tVec3 forward;\n\tdouble maxDepth;\npublic:\n\tVisibilityFilter() : up(), down(), left(), right(), forward(), maxDepth() {};\n\tVisibilityFilter(const Position& origin, Vec3 normals[5], double maxDepth);\n\n\t/*\n\t\tCreates a VisibilityFilter from the values derived from usual camera parameters.\n\n\t\tstepForward: the direction of the camera\n\t\tstepUp: should be perpendicular to stepForward & stepRight, furthest visible point, starting from stepForward, in the up direction.\n\t\tstepRight: should be perpendicular to stepForward & stepUp, furthest visible point, starting from stepForward, in the right direction.\n\t*/\n\tstatic VisibilityFilter fromSteps(const Position& origin, const Vec3& stepForward, const Vec3& stepUp, const Vec3& stepRight, double maxDepth);\n\n\t/*\n\t\tCreates a VisibilityFilter from the values derived from common camera parameters.\n\n\t\tcameraForward: the direction of the camera\n\t\tcameraUp: should be perpendicular to cameraForward & cameraRight, furthest visible point, starting from cameraForward, in the up direction.\n\t\tcameraRight: should be perpendicular to cameraForward & cameraUp, furthest visible point, starting from cameraForward, in the right direction.\n\n\t\tAlso accepts subWindow parameters:\n\t\tleft-right goes from -1..1\n\t\tdown-up goes from -1..1\n\t*/\n\tstatic VisibilityFilter fromSteps(const Position& origin, const Vec3& stepForward, const Vec3& stepUp, const Vec3& stepRight, double maxDepth, double left, double right, double down, double up);\n\n\t/*\n\t\tCreates a VisibilityFilter from the values derived from usual camera parameters.\n\n\t\tcameraForward: the direction of the camera\n\t\tcameraUp: should be perpendicular to cameraForward, up direction relative to the camera\n\n\t\tfov: Field Of View of the camera, expressed in radians\n\n\t\taspect: aspect ratio of the camera, == width / height\n\t*/\n\tstatic VisibilityFilter forWindow(const Position& origin, const Vec3& cameraForward, const Vec3& cameraUp, double fov, double aspect, double maxDepth);\n\n\t/*\n\t\tCreates a VisibilityFilter for a subregion of the screen. Useful for selection and stuff\n\n\t\tCreate it by giving the same arguments as forWindow, but also pass which portion of the screen to select.\n\t\tleft-right goes from -1..1\n\t\tdown-up goes from -1..1\n\t*/\n\tstatic VisibilityFilter forSubWindow(const Position& origin, const Vec3& cameraForward, const Vec3& cameraUp, double fov, double aspect, double maxDepth, double left, double right, double down, double up);\n\n\tbool operator()(const Position& point) const;\n\tbool operator()(const Part& part) const;\n\tbool operator()(const Bounds& bounds) const;\n\n\tVec3 getForwardStep() const { return forward; }\n\tVec3 getTopOfViewPort() const { return projectToPlaneNormal(forward, up); }\n\tVec3 getBottomOfViewPort() const { return projectToPlaneNormal(forward, down); }\n\tVec3 getLeftOfViewPort() const { return projectToPlaneNormal(forward, left); }\n\tVec3 getRightOfViewPort() const { return projectToPlaneNormal(forward, right); }\n};\n};"
  },
  {
    "path": "Physics3D/colissionBuffer.h",
    "content": "#pragma once\n\n#include <vector>\n\nnamespace P3D {\nstruct Colission {\n\tPart* p1;\n\tPart* p2;\n\tPosition intersection;\n\tVec3 exitVector;\n};\n\nstruct ColissionBuffer {\n\tstd::vector<Colission> freePartColissions;\n\tstd::vector<Colission> freeTerrainColissions;\n\n\tinline void addFreePartColission(Part* a, Part* b, Position intersection, Vec3 exitVector) {\n\t\tfreePartColissions.push_back(Colission{a, b, intersection, exitVector});\n\t}\n\tinline void addTerrainColission(Part* freePart, Part* terrainPart, Position intersection, Vec3 exitVector) {\n\t\tfreeTerrainColissions.push_back(Colission{freePart, terrainPart, intersection, exitVector});\n\t}\n\tinline void clear() {\n\t\tfreePartColissions.clear();\n\t\tfreeTerrainColissions.clear();\n\t}\n};\n};\n\n"
  },
  {
    "path": "Physics3D/constraints/ballConstraint.cpp",
    "content": "#include \"ballConstraint.h\"\n#include \"constraintImpl.h\"\n\nnamespace P3D {\nint BallConstraint::maxNumberOfParameters() const {\n\treturn 3;\n}\n\nstatic ConstraintMatrixPair<3> makeMatrices(const PhysicalInfo& phys, const Vec3& attach) {\n\tVec3 attachRelativeToCOM = phys.cframe.localToRelative(attach) - phys.relativeCenterOfMass;\n\n\tMat3 crossEquivAttach = createCrossProductEquivalent(attachRelativeToCOM);\n\n\tMatrix<double, 6, 3> parameterToMotion = joinVertical(Mat3::DIAGONAL(phys.forceResponse), phys.momentResponse * crossEquivAttach);\n\tMatrix<double, 3, 6> motionToEquation = joinHorizontal(Mat3::IDENTITY(), -crossEquivAttach);\n\n\treturn ConstraintMatrixPair<3>{parameterToMotion, motionToEquation};\n}\n\nConstraintMatrixPack BallConstraint::getMatrices(const PhysicalInfo& physA, const PhysicalInfo& physB, double* matrixBuf, double* errorBuf) const {\n\tConstraintMatrixPair<3> cA = makeMatrices(physA, attachA);\n\tConstraintMatrixPair<3> cB = makeMatrices(physB, attachB);\n\n\tVec3 error0 = physB.cframe.localToGlobal(attachB) - physA.cframe.localToGlobal(attachA);\n\n\tVec3 velocityA = cA.motionToEquation * physA.motion.getDerivAsVec6(0);\n\tVec3 velocityB = cB.motionToEquation * physB.motion.getDerivAsVec6(0);\n\tVec3 error1 = velocityB - velocityA;\n\n\tMatrix<double, 3, NUMBER_OF_ERROR_DERIVATIVES> error = Matrix<double, 3, NUMBER_OF_ERROR_DERIVATIVES>::fromColumns({error0, error1});\n\n\t/*inMemoryMatrixVectorMultiply(motionToEquationMatrixA, getMotionVecForDeriv(physA.mainPhysical->motionOfCenterOfMass, 1), mA);\n\tinMemoryMatrixVectorMultiply(motionToEquationMatrixB, getMotionVecForDeriv(physB.mainPhysical->motionOfCenterOfMass, 1), mB);\n\tmB -= mA;\n\terrorValue.setCol(2, mB);*/\n\n\treturn ConstraintMatrixPack(matrixBuf, errorBuf, cA, cB, error);\n}\n};"
  },
  {
    "path": "Physics3D/constraints/ballConstraint.h",
    "content": "#pragma once\n\n#include \"../math/linalg/vec.h\"\n#include \"constraint.h\"\n\nnamespace P3D {\nstruct BallConstraint : public Constraint {\n\tVec3 attachA;\n\tVec3 attachB;\n\n\tBallConstraint() = default;\n\tinline BallConstraint(Vec3 attachA, Vec3 attachB) :\n\t\tattachA(attachA), attachB(attachB) {}\n\n\tvirtual int maxNumberOfParameters() const override;\n\tvirtual ConstraintMatrixPack getMatrices(const PhysicalInfo& physA, const PhysicalInfo& physB, double* matrixBuf, double* errorBuf) const override;\n};\n};\n"
  },
  {
    "path": "Physics3D/constraints/barConstraint.cpp",
    "content": "#include \"barConstraint.h\"\n#include \"constraintImpl.h\"\n\nnamespace P3D {\nint BarConstraint::maxNumberOfParameters() const {\n\treturn 1;\n}\n\nstatic ConstraintMatrixPair<1> makeMatrices(const PhysicalInfo& phys, const Vec3& attach, const Vec3& barAxis) {\n\tVec3 attachRelativeToCOM = phys.cframe.localToRelative(attach) - phys.relativeCenterOfMass;\n\n\tMat3 crossEquivAttach = createCrossProductEquivalent(attachRelativeToCOM);\n\n\tMatrix<double, 6, 1> parameterToMotion = Matrix<double, 6, 1>::fromColumns({join(phys.forceResponse * barAxis, phys.momentResponse * crossEquivAttach * barAxis)});\n\tMatrix<double, 1, 6> motionToEquation = Matrix<double, 1, 6>::fromRows({join(barAxis, (attachRelativeToCOM % barAxis))});\n\n\treturn ConstraintMatrixPair<1>{parameterToMotion, motionToEquation};\n}\n\nConstraintMatrixPack BarConstraint::getMatrices(const PhysicalInfo& physA, const PhysicalInfo& physB, double* matrixBuf, double* errorBuf) const {\n\tVec3 barAxis = physB.cframe.localToGlobal(attachB) - physA.cframe.localToGlobal(attachA);\n\n\tConstraintMatrixPair<1> cA = makeMatrices(physA, attachA, barAxis);\n\tConstraintMatrixPair<1> cB = makeMatrices(physB, attachB, barAxis);\n\n\tdouble error0 = length(barAxis) - this->barLength;\n\n\tdouble velocityA = cA.motionToEquation * physA.motion.getDerivAsVec6(0);\n\tdouble velocityB = cB.motionToEquation * physB.motion.getDerivAsVec6(0);\n\tdouble error1 = velocityB - velocityA;\n\n\tMatrix<double, 1, NUMBER_OF_ERROR_DERIVATIVES> error = Matrix<double, 1, NUMBER_OF_ERROR_DERIVATIVES>::fromColumns({error0, error1});\n\n\t/*inMemoryMatrixVectorMultiply(motionToEquationMatrixA, getMotionVecForDeriv(physA.mainPhysical->motionOfCenterOfMass, 1), mA);\n\tinMemoryMatrixVectorMultiply(motionToEquationMatrixB, getMotionVecForDeriv(physB.mainPhysical->motionOfCenterOfMass, 1), mB);\n\tmB -= mA;\n\terrorValue.setCol(2, mB);*/\n\n\treturn ConstraintMatrixPack(matrixBuf, errorBuf, cA, cB, error);\n}\n};"
  },
  {
    "path": "Physics3D/constraints/barConstraint.h",
    "content": "#pragma once\n\n\n#include \"../math/linalg/vec.h\"\n#include \"constraint.h\"\n\nnamespace P3D {\nstruct BarConstraint : public Constraint {\n\tVec3 attachA;\n\tVec3 attachB;\n\tdouble barLength;\n\n\tBarConstraint() = default;\n\tinline BarConstraint(Vec3 attachA, Vec3 attachB, double barLength) :\n\t\tattachA(attachA), attachB(attachB), barLength(barLength) {}\n\n\tvirtual int maxNumberOfParameters() const override;\n\tvirtual ConstraintMatrixPack getMatrices(const PhysicalInfo& physA, const PhysicalInfo& physB, double* matrixBuf, double* errorBuf) const override;\n};\n};\n\n"
  },
  {
    "path": "Physics3D/constraints/constraint.cpp",
    "content": "#include \"constraint.h\"\n\nnamespace P3D {\nConstraint::~Constraint() {}\n}\n"
  },
  {
    "path": "Physics3D/constraints/constraint.h",
    "content": "#pragma once\n\nnamespace P3D {\nclass ConstraintMatrixPack;\nstruct PhysicalInfo;\nstruct Constraint {\n\tvirtual int maxNumberOfParameters() const = 0;\n\tvirtual ConstraintMatrixPack getMatrices(const PhysicalInfo& physA, const PhysicalInfo& physB, double* matrixBuf, double* errorBuf) const = 0;\n\tvirtual ~Constraint();\n};\n}\n"
  },
  {
    "path": "Physics3D/constraints/constraintGroup.cpp",
    "content": "#include \"constraintGroup.h\"\n\n#include \"constraintImpl.h\"\n\n#include \"../math/linalg/largeMatrix.h\"\n#include \"../math/linalg/largeMatrixAlgorithms.h\"\n#include \"../math/linalg/mat.h\"\n#include \"../physical.h\"\n\n#include \"../math/mathUtil.h\"\n\n#include \"../misc/validityHelper.h\"\n\n#include <fstream>\n#include <cstddef>\n\n#include <map>\n\nnamespace P3D {\nint PhysicalConstraint::maxNumberOfParameters() const {\n\treturn constraint->maxNumberOfParameters();\n}\nstatic PhysicalInfo getInfo(const Physical& phys) {\n\tGlobalCFrame cf = phys.getCFrame();\n\tVec3 relativeCOM = phys.mainPhysical->totalCenterOfMass - (cf.getPosition() - phys.mainPhysical->getCFrame().getPosition());\n\treturn PhysicalInfo{cf, phys.getMotion(), 1 / phys.mainPhysical->totalMass, phys.mainPhysical->momentResponse, relativeCOM};\n}\nConstraintMatrixPack PhysicalConstraint::getMatrices(double* matrixBuf, double* errorBuf) const {\n\tPhysicalInfo infoA = getInfo(*physA);\n\tPhysicalInfo infoB = getInfo(*physB);\n\n\treturn constraint->getMatrices(infoA, infoB, matrixBuf, errorBuf);\n}\n\nvoid ConstraintGroup::add(Physical* first, Physical* second, Constraint* constraint) {\n\tthis->constraints.push_back(PhysicalConstraint(first, second, constraint));\n}\nvoid ConstraintGroup::add(Part* first, Part* second, Constraint* constraint) {\n\tthis->constraints.push_back(PhysicalConstraint(first->ensureHasPhysical(), second->ensureHasPhysical(), constraint));\n}\n\nvoid ConstraintGroup::apply() const {\n\tstd::size_t maxNumberOfParameters = 0;\n\tConstraintMatrixPack* constraintMatrices = new ConstraintMatrixPack[constraints.size()];\n\n\tfor(std::size_t i = 0; i < constraints.size(); i++) {\n\t\tmaxNumberOfParameters += constraints[i].constraint->maxNumberOfParameters();\n\t}\n\n\tdouble* matrixBuffer = new double[std::size_t(24) * maxNumberOfParameters];\n\tdouble* errorBuffer = new double[std::size_t(NUMBER_OF_ERROR_DERIVATIVES) * maxNumberOfParameters];\n\n\tstd::size_t numberOfParams = 0;\n\tfor(std::size_t i = 0; i < constraints.size(); i++) {\n\t\tconstraintMatrices[i] = constraints[i].getMatrices(matrixBuffer + std::size_t(24) * numberOfParams, errorBuffer + std::size_t(NUMBER_OF_ERROR_DERIVATIVES) * numberOfParams);\n\n\t\tnumberOfParams += constraintMatrices[i].getSize();\n\t}\n\n\tUnmanagedHorizontalFixedMatrix<double, NUMBER_OF_ERROR_DERIVATIVES> vectorToSolve(errorBuffer, maxNumberOfParameters);\n\n\tLargeMatrix<double> systemToSolve(numberOfParams, numberOfParams);\n\t{\n\t\tstd::size_t curColIndex = 0;\n\t\tfor(std::size_t blockCol = 0; blockCol < constraints.size(); blockCol++) {\n\t\t\tint colSize = constraintMatrices[blockCol].getSize();\n\n\t\t\tMotorizedPhysical* mPhysA = constraints[blockCol].physA->mainPhysical;\n\t\t\tMotorizedPhysical* mPhysB = constraints[blockCol].physB->mainPhysical;\n\n\t\t\tconst UnmanagedHorizontalFixedMatrix<double, 6> motionToEq1 = constraintMatrices[blockCol].getMotionToEquationMatrixA();\n\t\t\tconst UnmanagedHorizontalFixedMatrix<double, 6> motionToEq2 = constraintMatrices[blockCol].getMotionToEquationMatrixB();\n\n\t\t\tstd::size_t curRowIndex = 0;\n\t\t\tfor(std::size_t blockRow = 0; blockRow < constraints.size(); blockRow++) {\n\t\t\t\tint rowSize = constraintMatrices[blockRow].getSize();\n\n\t\t\t\tMotorizedPhysical* cPhysA = constraints[blockRow].physA->mainPhysical;\n\t\t\t\tMotorizedPhysical* cPhysB = constraints[blockRow].physB->mainPhysical;\n\n\t\t\t\tconst UnmanagedVerticalFixedMatrix<double, 6> paramToMotion1 = constraintMatrices[blockRow].getParameterToMotionMatrixA();\n\t\t\t\tconst UnmanagedVerticalFixedMatrix<double, 6> paramToMotion2 = constraintMatrices[blockRow].getParameterToMotionMatrixB();\n\n\t\t\t\tdouble resultBuf1[6 * 6]; UnmanagedLargeMatrix<double> resultMat1(resultBuf1, rowSize, colSize);\n\t\t\t\tfor(double& d : resultMat1) d = 0.0;\n\t\t\t\tdouble resultBuf2[6 * 6]; UnmanagedLargeMatrix<double> resultMat2(resultBuf2, rowSize, colSize);\n\t\t\t\tfor(double& d : resultMat2) d = 0.0;\n\t\t\t\tif(mPhysA == cPhysA) {\n\t\t\t\t\tinMemoryMatrixMultiply(motionToEq1, paramToMotion1, resultMat1);\n\t\t\t\t} else if(mPhysA == cPhysB) {\n\t\t\t\t\tinMemoryMatrixMultiply(motionToEq1, paramToMotion2, resultMat1);\n\t\t\t\t\tinMemoryMatrixNegate(resultMat1);\n\t\t\t\t}\n\t\t\t\tif(mPhysB == cPhysA) {\n\t\t\t\t\tinMemoryMatrixMultiply(motionToEq2, paramToMotion1, resultMat2);\n\t\t\t\t\tinMemoryMatrixNegate(resultMat2);\n\t\t\t\t} else if(mPhysB == cPhysB) {\n\t\t\t\t\tinMemoryMatrixMultiply(motionToEq2, paramToMotion2, resultMat2);\n\t\t\t\t}\n\n\t\t\t\tresultMat1 += resultMat2;\n\n\t\t\t\tsystemToSolve.setSubMatrix(curColIndex, curRowIndex, resultMat1);\n\n\t\t\t\tcurRowIndex += rowSize;\n\t\t\t}\n\t\t\tcurColIndex += colSize;\n\t\t}\n\t}\n\n\tassert(isMatValid(vectorToSolve));\n\n\tdestructiveSolve(systemToSolve, vectorToSolve);\n\n\tassert(isMatValid(vectorToSolve));\n\n\t{\n\t\tstd::size_t curParameterIndex = 0;\n\t\tfor(std::size_t i = 0; i < constraints.size(); i++) {\n\t\t\tconst UnmanagedVerticalFixedMatrix<double, 6> curP2MA = constraintMatrices[i].getParameterToMotionMatrixA();\n\t\t\tconst UnmanagedVerticalFixedMatrix<double, 6> curP2MB = constraintMatrices[i].getParameterToMotionMatrixB();\n\t\t\tstd::size_t curSize = curP2MA.cols;\n\n\t\t\tUnmanagedHorizontalFixedMatrix<double, NUMBER_OF_ERROR_DERIVATIVES> parameterVec = vectorToSolve.subRows(curParameterIndex, curSize);\n\t\t\tMatrix<double, 6, NUMBER_OF_ERROR_DERIVATIVES> effectOnA = curP2MA * parameterVec;\n\t\t\tMatrix<double, 6, NUMBER_OF_ERROR_DERIVATIVES> effectOnB = -(curP2MB * parameterVec);\n\n\t\t\t// TODO add moving correction\n\t\t\tVector<double, 6> offsetAngularEffectOnA = effectOnA.getCol(0);\n\t\t\tVector<double, 6> offsetAngularEffectOnB = effectOnB.getCol(0);\n\n\t\t\tassert(isVecValid(offsetAngularEffectOnA));\n\t\t\tassert(isVecValid(offsetAngularEffectOnB));\n\n\t\t\tGlobalCFrame& mainPACF = constraints[i].physA->mainPhysical->rigidBody.mainPart->cframe;\n\t\t\tGlobalCFrame& mainPBCF = constraints[i].physB->mainPhysical->rigidBody.mainPart->cframe;\n\t\t\tmainPACF.position += offsetAngularEffectOnA.getSubVector<3>(0);\n\t\t\tmainPACF.rotation = Rotation::fromRotationVector(offsetAngularEffectOnA.getSubVector<3>(3)) * mainPACF.rotation;\n\t\t\tmainPBCF.position += offsetAngularEffectOnB.getSubVector<3>(0);\n\t\t\tmainPBCF.rotation = Rotation::fromRotationVector(offsetAngularEffectOnB.getSubVector<3>(3)) * mainPBCF.rotation;\n\n\t\t\tVector<double, 6> velAngularEffectOnA = effectOnA.getCol(1);\n\t\t\tVector<double, 6> velAngularEffectOnB = effectOnB.getCol(1);\n\t\t\tassert(isVecValid(velAngularEffectOnA));\n\t\t\tassert(isVecValid(velAngularEffectOnB));\n\t\t\tconstraints[i].physA->mainPhysical->motionOfCenterOfMass.translation.translation[0] += velAngularEffectOnA.getSubVector<3>(0);\n\t\t\tconstraints[i].physA->mainPhysical->motionOfCenterOfMass.rotation.rotation[0] += velAngularEffectOnA.getSubVector<3>(3);\n\t\t\tconstraints[i].physB->mainPhysical->motionOfCenterOfMass.translation.translation[0] += velAngularEffectOnB.getSubVector<3>(0);\n\t\t\tconstraints[i].physB->mainPhysical->motionOfCenterOfMass.rotation.rotation[0] += velAngularEffectOnB.getSubVector<3>(3);\n\n\n\t\t\t/*Vector<double, 6> accelAngularEffectOnA = effectOnA.getCol(2);\n\t\t\tVector<double, 6> accelAngularEffectOnB = effectOnB.getCol(2);\n\t\t\tconstraints[i].physA->mainPhysical->totalForce += constraints[i].physA->mainPhysical->totalMass * velAngularEffectOnA.getSubVector<3>(0);\n\t\t\tconstraints[i].physA->mainPhysical->totalMoment += ~constraints[i].physA->mainPhysical->momentResponse * velAngularEffectOnA.getSubVector<3>(3);\n\t\t\tconstraints[i].physB->mainPhysical->totalForce += constraints[i].physB->mainPhysical->totalMass * velAngularEffectOnB.getSubVector<3>(0);\n\t\t\tconstraints[i].physB->mainPhysical->totalMoment += ~constraints[i].physB->mainPhysical->momentResponse * velAngularEffectOnB.getSubVector<3>(3);*/\n\n\n\t\t\tcurParameterIndex += curSize;\n\t\t}\n\t\tassert(curParameterIndex == numberOfParams);\n\t}\n}\n};"
  },
  {
    "path": "Physics3D/constraints/constraintGroup.h",
    "content": "#pragma once\n\n#include <vector>\n#include \"constraint.h\"\n\nnamespace P3D {\nclass Physical;\nclass Part;\n\nclass PhysicalConstraint {\npublic:\n\tPhysical* physA;\n\tPhysical* physB;\n\tConstraint* constraint;\n\n\tinline PhysicalConstraint(Physical* physA, Physical* physB, Constraint* constraint) :\n\t\tphysA(physA), physB(physB), constraint(constraint) {}\n\n\tint maxNumberOfParameters() const;\n\tConstraintMatrixPack getMatrices(double* matrixBuf, double* errorBuf) const;\n};\n\nclass ConstraintGroup {\npublic:\n\tstd::vector<PhysicalConstraint> constraints;\n\t//std::vector<MotorizedPhysical*> physicals;\n\n\tvoid add(Physical* first, Physical* second, Constraint* constraint);\n\tvoid add(Part* first, Part* second, Constraint* constraint);\n\n\tvoid apply() const;\n};\n}\n"
  },
  {
    "path": "Physics3D/constraints/constraintImpl.h",
    "content": "#pragma once\n\n#include \"constraint.h\"\n\n#include \"../math/linalg/mat.h\"\n#include \"../math/linalg/largeMatrix.h\"\n#include \"../math/globalCFrame.h\"\n#include \"../motion.h\"\n\nnamespace P3D {\n#define NUMBER_OF_ERROR_DERIVATIVES 2\n\ntemplate<std::size_t Size>\nstruct ConstraintMatrixPair {\n\tMatrix<double, 6, Size> paramToMotion;\n\tMatrix<double, Size, 6> motionToEquation;\n\n\tConstraintMatrixPair operator-() const {\n\t\treturn ConstraintMatrixPair{-paramToMotion, -motionToEquation};\n\t}\n};\n\nstruct PhysicalInfo {\n\tGlobalCFrame cframe;\n\tMotion motion;\n\tdouble forceResponse; // 1/mass\n\tMat3 momentResponse;\n\tVec3 relativeCenterOfMass;\n};\n\nclass ConstraintMatrixPack {\n\tdouble* matrixData;\n\tdouble* errorData;\n\tint size; // size * 6 for matrix size, size * 6 * 4 for total size\n\npublic:\n\tConstraintMatrixPack() = default;\n\ttemplate<std::size_t Size>\n\tConstraintMatrixPack(double* matrixBuf, double* errorBuf,\n\t\t\t\t\t\t const Matrix<double, 6, Size>& paramToMotionA,\n\t\t\t\t\t\t const Matrix<double, 6, Size>& paramToMotionB,\n\t\t\t\t\t\t const Matrix<double, Size, 6>& motionToEqA,\n\t\t\t\t\t\t const Matrix<double, Size, 6>& motionToEqB,\n\t\t\t\t\t\t const Matrix<double, Size, NUMBER_OF_ERROR_DERIVATIVES>& errorMat) : matrixData(matrixBuf), errorData(errorBuf), size(Size) {\n\n\t\tparamToMotionA.toColMajorData(matrixData);\n\t\tparamToMotionB.toColMajorData(matrixData + 6 * Size);\n\t\tmotionToEqA.toRowMajorData(matrixData + 12 * Size);\n\t\tmotionToEqB.toRowMajorData(matrixData + 18 * Size);\n\t\terrorMat.toRowMajorData(errorData);\n\t}\n\ttemplate<std::size_t Size>\n\tConstraintMatrixPack(double* matrixBuf, double* errorBuf,\n\t\t\t\t\t\t const ConstraintMatrixPair<Size>& mA,\n\t\t\t\t\t\t const ConstraintMatrixPair<Size>& mB,\n\t\t\t\t\t\t const Matrix<double, Size, NUMBER_OF_ERROR_DERIVATIVES>& errorMat) : matrixData(matrixBuf), errorData(errorBuf), size(Size) {\n\n\t\tmA.paramToMotion.toColMajorData(matrixData);\n\t\tmB.paramToMotion.toColMajorData(matrixData + 6 * Size);\n\t\tmA.motionToEquation.toRowMajorData(matrixData + 12 * Size);\n\t\tmB.motionToEquation.toRowMajorData(matrixData + 18 * Size);\n\t\terrorMat.toRowMajorData(errorData);\n\t}\n\tint getSize() const { return size; }\n\tUnmanagedVerticalFixedMatrix<double, 6> getParameterToMotionMatrixA() const {\n\t\treturn UnmanagedVerticalFixedMatrix<double, 6>(matrixData, size);\n\t}\n\tUnmanagedVerticalFixedMatrix<double, 6> getParameterToMotionMatrixB() const {\n\t\treturn UnmanagedVerticalFixedMatrix<double, 6>(matrixData + size_t(6) * size, size);\n\t}\n\tUnmanagedHorizontalFixedMatrix<double, 6> getMotionToEquationMatrixA() const {\n\t\treturn UnmanagedHorizontalFixedMatrix<double, 6>(matrixData + size_t(12) * size, size);\n\t}\n\tUnmanagedHorizontalFixedMatrix<double, 6> getMotionToEquationMatrixB() const {\n\t\treturn UnmanagedHorizontalFixedMatrix<double, 6>(matrixData + size_t(18) * size, size);\n\t}\n\tUnmanagedHorizontalFixedMatrix<double, NUMBER_OF_ERROR_DERIVATIVES> getErrorMatrix() const {\n\t\treturn UnmanagedHorizontalFixedMatrix<double, NUMBER_OF_ERROR_DERIVATIVES>(errorData, size);\n\t}\n};\n}\n"
  },
  {
    "path": "Physics3D/constraints/hingeConstraint.cpp",
    "content": "#include \"hingeConstraint.h\"\n#include \"constraintImpl.h\"\n\nnamespace P3D {\nint HingeConstraint::maxNumberOfParameters() const {\n\treturn 5;\n}\n\nstatic ConstraintMatrixPair<5> makeMatrices(const PhysicalInfo& phys, const Vec3& attach, const Vec3& p1, const Vec3& p2) {\n\tVec3 attachRelativeToCOM = phys.cframe.localToRelative(attach) - phys.relativeCenterOfMass;\n\n\tMat3 crossEquivAttach = createCrossProductEquivalent(attachRelativeToCOM);\n\n\tMatrix<double, 3, 5> impulseToMotion = joinHorizontal(Mat3::DIAGONAL(phys.forceResponse), Matrix<double, 3, 2>::ZEROS());\n\tMatrix<double, 3, 5> angularEffect = joinHorizontal(crossEquivAttach, Matrix<double, 3, 2>::fromColumns({p1, p2}));\n\n\tMatrix<double, 6, 5> parameterToMotion = joinVertical(impulseToMotion, phys.momentResponse * angularEffect);\n\tMatrix<double, 5, 6> motionToEquation = join(Mat3::IDENTITY(), -crossEquivAttach, Matrix<double, 2, 3>::ZEROS(), Matrix<double, 2, 3>::fromRows({p1, p2}));\n\n\treturn ConstraintMatrixPair<5>{parameterToMotion, motionToEquation};\n}\n\nConstraintMatrixPack HingeConstraint::getMatrices(const PhysicalInfo& physA, const PhysicalInfo& physB, double* matrixBuf, double* errorBuf) const {\n\tVec3 localMainAxis = normalize(this->axisA);\n\tVec3 localP1 = normalize(getPerpendicular(localMainAxis));\n\tVec3 localP2 = normalize(localMainAxis % localP1);\n\n\tVec3 localMainOffsetAxis = normalize(this->axisB);\n\n\tVec3 mainAxis = physA.cframe.localToRelative(localMainAxis);\n\tVec3 p1 = physA.cframe.localToRelative(localP1);\n\tVec3 p2 = physA.cframe.localToRelative(localP2);\n\tVec3 mainOffsetAxis = physB.cframe.localToRelative(localMainOffsetAxis);\n\n\t// rotationOffset will be in the plane defined by p1 and p2, as it is perpendicular to mainAxis\n\tVec3 rotationOffset = mainAxis % mainOffsetAxis;\n\tdouble rotationOffsetP1 = p1 * rotationOffset;\n\tdouble rotationOffsetP2 = p2 * rotationOffset;\n\n\tConstraintMatrixPair<5> cA = makeMatrices(physA, attachA, p1, p2);\n\tConstraintMatrixPair<5> cB = makeMatrices(physB, attachB, p1, p2);\n\n\tVec5 error0 = join(Vec3(physB.cframe.localToGlobal(attachB) - physA.cframe.localToGlobal(attachA)), Vec2(rotationOffsetP1, rotationOffsetP2));\n\n\tVec5 velocityA = cA.motionToEquation * physA.motion.getDerivAsVec6(0);\n\tVec5 velocityB = cB.motionToEquation * physB.motion.getDerivAsVec6(0);\n\tVec5 error1 = velocityB - velocityA;\n\n\tMatrix<double, 5, NUMBER_OF_ERROR_DERIVATIVES> error = Matrix<double, 5, NUMBER_OF_ERROR_DERIVATIVES>::fromColumns({error0, error1});\n\n\treturn ConstraintMatrixPack(matrixBuf, errorBuf, cA, cB, error);\n}\n};"
  },
  {
    "path": "Physics3D/constraints/hingeConstraint.h",
    "content": "#pragma once\n\n#include \"../math/linalg/vec.h\"\n#include \"constraint.h\"\n\nnamespace P3D {\nstruct HingeConstraint : public Constraint {\n\tVec3 attachA;\n\tVec3 axisA;\n\tVec3 attachB;\n\tVec3 axisB;\n\n\tHingeConstraint() = default;\n\tinline HingeConstraint(Vec3 attachA, Vec3 axisA, Vec3 attachB, Vec3 axisB) :\n\t\tattachA(attachA), axisA(axisA), attachB(attachB), axisB(axisB) {}\n\n\tvirtual int maxNumberOfParameters() const override;\n\tvirtual ConstraintMatrixPack getMatrices(const PhysicalInfo& physA, const PhysicalInfo& physB, double* matrixBuf, double* errorBuf) const override;\n};\n};\n"
  },
  {
    "path": "Physics3D/datastructures/alignedPtr.h",
    "content": "#pragma once\n\n#include <utility>\n#include <cstddef>\n\n#include \"aligned_alloc.h\"\n\nnamespace P3D {\ntemplate<typename T>\nclass UniqueAlignedPointer {\n\tT* data;\n\npublic:\n\tUniqueAlignedPointer() : data(nullptr) {}\n\tUniqueAlignedPointer(std::size_t size, std::size_t align = alignof(T)) :\n\t\tdata(static_cast<T*>(aligned_malloc(sizeof(T)* size, align))) {}\n\t~UniqueAlignedPointer() {\n\t\taligned_free(static_cast<void*>(data));\n\t}\n\n\tinline T* get() const { return data; }\n\toperator T* () const { return data; }\n\n\tUniqueAlignedPointer(const UniqueAlignedPointer& other) = delete;\n\tUniqueAlignedPointer& operator=(const UniqueAlignedPointer& other) = delete;\n\n\tUniqueAlignedPointer(UniqueAlignedPointer&& other) noexcept : data(other.data) {\n\t\tother.data = nullptr;\n\t}\n\tUniqueAlignedPointer& operator=(UniqueAlignedPointer&& other) noexcept {\n\t\tstd::swap(this->data, other.data);\n\n\t\treturn *this;\n\t}\n};\n\ntemplate<typename T>\nclass SharedAlignedPointer {\n\tT* data;\n\tstd::size_t* refCount;\n\npublic:\n\tSharedAlignedPointer() : data(nullptr), refCount(nullptr) {}\n\tSharedAlignedPointer(std::size_t size, std::size_t align = alignof(T)) :\n\t\tdata(static_cast<T*>(aligned_malloc(sizeof(T)* size, align))),\n\t\trefCount(new std::size_t(1)) {}\n\t~SharedAlignedPointer() {\n\t\tif(refCount != nullptr && --(*refCount) == 0) {\n\t\t\taligned_free(static_cast<void*>(data));\n\t\t\tdelete refCount;\n\t\t}\n\t}\n\n\tinline T* get() const { return data; }\n\toperator T* () const { return data; }\n\n\tSharedAlignedPointer(const SharedAlignedPointer& other) : data(other.data), refCount(other.refCount) {\n\t\t(*refCount)++;\n\t}\n\tSharedAlignedPointer& operator=(const SharedAlignedPointer& other) {\n\t\tthis->~SharedAlignedPointer();\n\n\t\tthis->data = other.data;\n\t\tthis->refCount = other.refCount;\n\n\t\t(*refCount)++;\n\n\t\treturn *this;\n\t}\n\n\tSharedAlignedPointer(SharedAlignedPointer&& other) noexcept : data(other.data), refCount(other.refCount) {\n\t\tother.data = nullptr;\n\t\tother.refCount = nullptr;\n\t}\n\tSharedAlignedPointer& operator=(SharedAlignedPointer&& other) noexcept {\n\t\tstd::swap(this->data, other.data);\n\t\tstd::swap(this->refCount, other.refCount);\n\n\t\treturn *this;\n\t}\n};\n};\n"
  },
  {
    "path": "Physics3D/datastructures/aligned_alloc.cpp",
    "content": "#include \"aligned_alloc.h\"\n\n#include <malloc.h>\n#include <stdlib.h>\n\nnamespace P3D {\nvoid* aligned_malloc(size_t size, size_t align) {\n#ifdef _MSC_VER\n\treturn _aligned_malloc(size, align);\n#else\n\treturn aligned_alloc(align, size);\n#endif\n}\nvoid aligned_free(void* ptr) {\n#ifdef _MSC_VER\n\t_aligned_free(ptr);\n#else\n\tfree(ptr);\n#endif\n}\n};"
  },
  {
    "path": "Physics3D/datastructures/aligned_alloc.h",
    "content": "#pragma once\n\n#include <cstddef>\n\nnamespace P3D {\nvoid* aligned_malloc(std::size_t size, std::size_t align);\nvoid aligned_free(void* ptr);\n};\n"
  },
  {
    "path": "Physics3D/datastructures/buffers.h",
    "content": "#pragma once\n\n#include <assert.h>\n\n#include \"iteratorEnd.h\"\n\nnamespace P3D {\ninline unsigned long long nextPowerOf2(unsigned long long v) {\n\tv--;\n\tv |= v >> 1;\n\tv |= v >> 2;\n\tv |= v >> 4;\n\tv |= v >> 8;\n\tv |= v >> 16;\n\tv |= v >> 32;\n\treturn v + 1;\n}\n\ntemplate<typename T>\nstruct ListIter {\n\tT* start;\n\tT* fin;\n\tT* begin() const { return start; }\n\tT* end() const { return fin; }\n};\n\n/*template<typename T>\nstruct ConstListIter {\n\tconst T* start;\n\tconst T* fin;\n\tconst T* begin() const { return start; }\n\tconst T* end() const { return fin; }\n};*/\n\ntemplate<typename T>\nstruct ListOfPtrIter {\n\tT* const* cur;\n\n\tListOfPtrIter() = default;\n\tListOfPtrIter(T* const* cur) : cur(cur) {}\n\n\tT& operator*() const {\n\t\treturn **cur;\n\t}\n\n\tListOfPtrIter& operator++() {\n\t\tcur++;\n\t\treturn *this;\n\t}\n\n\tListOfPtrIter operator++(int) {\n\t\tListOfPtrIter prevSelf = *this;\n\t\tcur++;\n\t\treturn prevSelf;\n\t}\n\n\tbool operator==(const ListOfPtrIter& other) const {\n\t\treturn this->cur == other.cur;\n\t}\n\n\tbool operator!=(const ListOfPtrIter& other) const {\n\t\treturn this->cur != other.cur;\n\t}\n\n\tT* operator->() const {\n\t\treturn *cur;\n\t}\n\n\toperator T* () const {\n\t\treturn *cur;\n\t}\n};\n\ntemplate<typename T>\nstruct ListOfPtrIterFactory {\n\tT* const* start;\n\tT* const* fin;\n\tListOfPtrIterFactory() {}\n\tListOfPtrIterFactory(T* const* start, T* const* fin) : start(start), fin(fin) {}\n\tListOfPtrIterFactory(const ListIter<T* const>& iter) : start(iter.start), fin(iter.fin) {}\n\tListOfPtrIterFactory(const ListIter<T*>& iter) : start(iter.start), fin(iter.fin) {}\n\n\tListOfPtrIter<T> begin() const { return ListOfPtrIter<T>{start}; }\n\tListOfPtrIter<T> end() const { return ListOfPtrIter<T>{fin}; }\n};\n\ntemplate<typename T>\nstruct BufferWithCapacity {\n\tT* data;\n\tsize_t capacity;\n\n\tBufferWithCapacity() : data(nullptr), capacity(0) {};\n\tBufferWithCapacity(size_t initialCapacity) : data(new T[initialCapacity]), capacity(initialCapacity) {}\n\n\tBufferWithCapacity(BufferWithCapacity&& other) noexcept {\n\t\tthis->data = other.data;\n\t\tthis->capacity = other.capacity;\n\t\tother.data = nullptr;\n\t\tother.capacity = 0;\n\t}\n\n\t~BufferWithCapacity() {\n\t\tdelete[] data;\n\t}\n\n\tBufferWithCapacity(const BufferWithCapacity& other) = delete;\n\tvoid operator=(const BufferWithCapacity& other) = delete;\n\n\tBufferWithCapacity& operator=(BufferWithCapacity&& other) noexcept {\n\t\tstd::swap(this->data, other.data);\n\t\tstd::swap(this->capacity, other.capacity);\n\t\treturn *this;\n\t}\n\n\tvoid resize(size_t newCapacity, size_t sizeToCopy) {\n\t\tT* newBuf = new T[newCapacity];\n\t\tfor(size_t i = 0; i < sizeToCopy; i++)\n\t\t\tnewBuf[i] = std::move(data[i]);\n\n\t\tdelete[] data;\n\t\tdata = newBuf;\n\t\tcapacity = newCapacity;\n\t}\n\n\tsize_t ensureCapacity(size_t newCapacity, size_t sizeToCopy) {\n\t\tif(newCapacity > this->capacity) {\n\t\t\tsize_t nextPower = nextPowerOf2(newCapacity);\n\t\t\tresize(nextPower, sizeToCopy);\n\t\t\treturn nextPower;\n\t\t}\n\n\t\treturn this->capacity;\n\t}\n\n\tT& operator[](size_t index) { return data[index]; }\n\tconst T& operator[](size_t index) const { return data[index]; }\n};\n\ntemplate<typename T>\nstruct AddableBuffer : public BufferWithCapacity<T> {\n\tsize_t size = 0;\n\n\tAddableBuffer() : BufferWithCapacity<T>() {}\n\tAddableBuffer(size_t initialCapacity) : BufferWithCapacity<T>(initialCapacity) {}\n\n\tAddableBuffer(T* data, size_t dataSize, size_t initialCapacity) : BufferWithCapacity<T>(initialCapacity), size(dataSize) {\n\t\tassert(data != nullptr);\n\n\t\tfor(size_t i = 0; i < dataSize; i++)\n\t\t\tthis->data[i] = data[i];\n\t}\n\n\t~AddableBuffer() {}\n\n\tAddableBuffer(const AddableBuffer<T>&) = delete;\n\tAddableBuffer& operator=(const AddableBuffer<T>&) = delete;\n\n\tAddableBuffer(AddableBuffer<T>&& other) noexcept : BufferWithCapacity<T>(std::move(other)), size(other.size) {\n\t\tother.size = 0;\n\t}\n\n\tAddableBuffer<T>& operator=(AddableBuffer<T>&& other) noexcept {\n\t\tBufferWithCapacity<T>::operator=(std::move(other));\n\t\tsize_t tmpSize = this->size;\n\t\tthis->size = other.size;\n\t\tother.size = tmpSize;\n\t\treturn *this;\n\t}\n\n\tinline void resize(size_t newCapacity) {\n\t\tBufferWithCapacity<T>::resize(newCapacity, this->size);\n\t}\n\n\tinline size_t ensureCapacity(size_t newCapacity) {\n\t\tsize_t newSize = BufferWithCapacity<T>::ensureCapacity(newCapacity, this->size);\n\t\treturn newSize;\n\t}\n\n\tinline T* add(const T& obj) {\n\t\tthis->ensureCapacity(this->size + 1);\n\t\tthis->data[this->size] = obj;\n\t\treturn &this->data[this->size++];\n\t}\n\n\tinline T* add(T&& obj) {\n\t\tthis->ensureCapacity(this->size + 1);\n\t\tthis->data[this->size] = std::move(obj);\n\t\treturn &this->data[this->size++];\n\t}\n\n\tinline void clear() {\n\t\tsize = 0;\n\t}\n\n\tinline T* begin() { return this->data; }\n\tinline const T* begin() const { return this->data; }\n\n\tinline T* end() { return this->data + size; }\n\tinline const T* end() const { return this->data + this->size; }\n\n\tinline bool liesInList(const T* obj) const {\n\t\treturn obj >= this->data && obj < this->data + this->size;\n\t}\n};\n\ntemplate<typename T, int N>\nstruct FixedLocalBuffer {\n\tT buf[N]{};\n\tint size = 0;\n\n\tT& operator[](int index) { return buf[index]; }\n\tconst T& operator[](int index) const { return buf[index]; }\n\n\tconst T* begin() const { return &buf; }\n\tT* begin() { return &buf; }\n\n\tconst T* end() const { return buf + size; }\n\tT* end() { return buf + size; }\n\n\tvoid add(const T& obj) {\n\t\tbuf[size++] = obj;\n\t}\n};\n\ntemplate<typename T>\nstruct CircularIter {\n\tT* iter;\n\tT* bufStart;\n\tT* bufEnd;\n\tsize_t itemsLeft;\n\n\tvoid operator++() {\n\t\titer++;\n\t\tif(iter == bufEnd) {\n\t\t\titer = bufStart;\n\t\t}\n\t\titemsLeft--;\n\t}\n\n\tT& operator*() const { return *iter; }\n\n\tbool operator==(IteratorEnd) const {\n\t\treturn this->itemsLeft == 0;\n\t}\n\n\tbool operator!=(IteratorEnd) const {\n\t\treturn this->itemsLeft != 0;\n\t}\n};\n\ntemplate<typename T>\nstruct CircularBuffer {\nprivate:\n\tT* buf;\n\tsize_t curI = 0;\n\tsize_t capacity;\n\tbool hasComeAround = false;\npublic:\n\tCircularBuffer() : buf(nullptr), capacity(0) {}\n\tCircularBuffer(size_t capacity) : buf(new T[capacity + 1]), capacity(capacity) {}\n\t~CircularBuffer() { delete[] buf; }\n\n\tinline size_t size() const {\n\t\tif(hasComeAround)\n\t\t\treturn capacity;\n\t\telse\n\t\t\treturn curI;\n\t}\n\n\tCircularBuffer(const CircularBuffer<T>& other) : buf(new T[other.capacity + 1]), curI(other.curI), capacity(other.capacity), hasComeAround(other.hasComeAround) {\n\t\tfor(size_t i = 0; i < other.capacity; i++) {\n\t\t\tthis->buf[i] = other.buf[i];\n\t\t}\n\t}\n\tCircularBuffer& operator=(const CircularBuffer<T>& other) {\n\t\tif(this->capacity != other.capacity) {\n\t\t\tdelete[] this->buf;\n\t\t\tthis->buf = new T[other.capacity];\n\t\t}\n\n\t\tthis->curI = other.curI;\n\t\tthis->capacity = other.capacity;\n\t\tthis->hasComeAround = other.hasComeAround;\n\t\tfor(size_t i = 0; i < other.capacity; i++) {\n\t\t\tthis->buf[i] = other.buf[i];\n\t\t}\n\t\treturn *this;\n\t}\n\tCircularBuffer(CircularBuffer<T>&& other) : buf(other.buf), curI(other.curI), capacity(other.capacity), hasComeAround(other.hasComeAround) {\n\t\tother.buf = nullptr;\n\t\tother.capacity = 0;\n\t\tother.curI = 0;\n\t\tother.hasComeAround = false;\n\t}\n\tCircularBuffer& operator=(CircularBuffer<T>&& other) {\n\t\tstd::swap(this->buf, other.buf);\n\t\tstd::swap(this->curI, other.curI);\n\t\tstd::swap(this->capacity, other.capacity);\n\t\tstd::swap(this->hasComeAround, other.hasComeAround);\n\t\treturn *this;\n\t}\n\n\tinline void add(const T& newObj) {\n\t\tbuf[curI] = newObj;\n\t\tcurI++;\n\n\t\tif(curI >= capacity) {\n\t\t\tcurI = 0;\n\t\t\thasComeAround = true;\n\t\t}\n\t}\n\n\tinline T sum() const {\n\t\tsize_t limit = size();\n\n\t\tif(limit == 0)\n\t\t\treturn T();\n\n\t\tT total = buf[0];\n\n\t\tfor(size_t i = 1; i < limit; i++)\n\t\t\ttotal += buf[i];\n\n\t\treturn total;\n\t}\n\n\tinline T avg() const {\n\t\tsize_t limit = size();\n\n\t\tif(limit == 0)\n\t\t\treturn T();\n\n\t\tT total = sum();\n\n\t\treturn T(total / limit);\n\t}\n\n\tinline void resize(size_t newCapacity) {\n\t\tT* newBuf = new T[newCapacity];\n\n\t\tT* cur = newBuf;\n\n\t\tsize_t elementsForgotten = (this->capacity > newCapacity) ? this->capacity - newCapacity : 0;\n\n\t\tif(hasComeAround) {\n\t\t\tfor(size_t i = curI + elementsForgotten; i < capacity; i++) {\n\t\t\t\t*cur = buf[i];\n\t\t\t\tcur++;\n\t\t\t}\n\n\t\t\tif(elementsForgotten > capacity - curI) {\n\t\t\t\telementsForgotten -= (capacity - curI);\n\t\t\t}\n\t\t}\n\t\tfor(size_t i = elementsForgotten; i < curI; i++) {\n\t\t\t*cur = buf[i];\n\t\t\tcur++;\n\t\t}\n\n\t\tdelete[] buf;\n\t\tthis->buf = newBuf;\n\t}\n\n\tT& front() {\n\t\treturn (curI == 0) ? buf[capacity - 1] : buf[curI - 1];\n\t}\n\n\tconst T& front() const {\n\t\treturn (curI == 0) ? buf[capacity - 1] : buf[curI - 1];\n\t}\n\n\tT& tail() {\n\t\treturn hasComeAround ? buf[curI] : buf[0];\n\t}\n\n\tconst T& tail() const {\n\t\treturn hasComeAround ? buf[curI] : buf[0];\n\t}\n\n\tinline CircularIter<T> begin() {\n\t\treturn CircularIter<T>{hasComeAround ? buf + curI : buf, buf, buf + capacity, size()};\n\t}\n\n\tinline CircularIter<const T> begin() const {\n\t\treturn CircularIter<const T>{hasComeAround ? buf + curI : buf, buf, buf + capacity, size()};\n\t}\n\n\tinline IteratorEnd end() {\n\t\treturn IteratorEnd();\n\t}\n};\n};"
  },
  {
    "path": "Physics3D/datastructures/compactPtrDataPair.h",
    "content": "#pragma once\n\n#include <cstddef> \n#include <assert.h>\n\n/*\n\tStores a little extra data in the lower bits of the given ptr type. \n\tThis is usually only 3 bits, but on stronger aligned types this may be more\n\n\tPointers are aligned on 4 or 8 bytes usually, this means we can use these few bits for storing some extra small data\n\tFor example, the length of an array pointed to by the pointer if that array will always be very small. \n\n\t0bPPP...PPPPP000 | 0b000...00000DDD = 0bPPP...PPPPPDDD\n*/\nnamespace P3D {\ntemplate<typename PtrT, unsigned int BitWidth = 1, typename DataType = unsigned int>\nclass CompactPtrDataPair {\nprotected:\n\tstd::uintptr_t value;\n\n\tCompactPtrDataPair(std::uintptr_t value) : value(value) {}\n\npublic:\n\tstatic constexpr std::uintptr_t dataMask = (std::uintptr_t(1) << BitWidth) - std::uintptr_t(1);\n\tstatic constexpr std::uintptr_t ptrMask = ~dataMask;\n\n\tCompactPtrDataPair() noexcept : value(reinterpret_cast<std::uintptr_t>(nullptr)) {}\n\n\tCompactPtrDataPair(PtrT* ptr, DataType data) noexcept : value(reinterpret_cast<std::uintptr_t>(ptr) | data) {\n\t\tassert(reinterpret_cast<std::uintptr_t>(ptr) & dataMask == std::uintptr_t(0));\n\t\tassert(data & ptrMask == std::uintptr_t(0));\n\t}\n\n\tPtrT* getPtr() const noexcept {\n\t\treturn reinterpret_cast<PtrT*>(value & ptrMask);\n\t}\n\n\tbool isNullptr() const noexcept {\n\t\treturn value & ptrMask == reinterpret_cast<std::uintptr_t>(nullptr) & ptrMask;\n\t}\n\n\tDataType getData() const noexcept {\n\t\treturn value & dataMask;\n\t}\n\n\tvoid setPtr(PtrT* ptr) noexcept {\n\t\tassert(reinterpret_cast<std::uintptr_t>(ptr) & dataMask == std::uintptr_t(0));\n\n\t\tvalue = reinterpret_cast<std::uintptr_t>(ptr) | (value & dataMask);\n\t}\n\n\tvoid setData(DataType data) noexcept {\n\t\tassert(data & ptrMask == std::uintptr_t(0));\n\n\t\tvalue = data | (value & ptrMask)\n\t}\n\n\tCompactPtrDataPair& operator++() {\n\t\tassert(getData() < dataMask);\n\t\t++value;\n\t\treturn *this;\n\t}\n\n\tCompactPtrDataPair& operator--() {\n\t\tassert(getData() != 0);\n\t\t--value;\n\t\treturn *this;\n\t}\n\n\tCompactPtrDataPair operator++(int) {\n\t\tCompactPtrDataPair result = *this;\n\t\t++(*this);\n\t\treturn result;\n\t}\n\n\tCompactPtrDataPair operator--(int) {\n\t\tCompactPtrDataPair result = *this;\n\t\t--(*this);\n\t\treturn result;\n\t}\n};\n\ntemplate<typename PtrT>\nclass CompactPtrDataPair<PtrT, 1, bool> {\nprotected:\n\tstd::uintptr_t value;\n\n\tCompactPtrDataPair(std::uintptr_t value) : value(value) {}\n\npublic:\n\tstatic constexpr std::uintptr_t dataMask = std::uintptr_t(1);\n\tstatic constexpr std::uintptr_t ptrMask = ~dataMask;\n\n\tCompactPtrDataPair() noexcept : value(reinterpret_cast<std::uintptr_t>(nullptr)) {}\n\n\tCompactPtrDataPair(PtrT* ptr, bool data) noexcept : value(reinterpret_cast<std::uintptr_t>(ptr) | (data ? std::uintptr_t(1) : std::uintptr_t(0))) {\n\t\tassert(reinterpret_cast<std::uintptr_t>(ptr) & dataMask == std::uintptr_t(0));\n\t}\n\n\tPtrT* getPtr() const noexcept {\n\t\treturn reinterpret_cast<PtrT*>(value & ptrMask);\n\t}\n\n\tbool isNullptr() const noexcept {\n\t\treturn value & ptrMask == reinterpret_cast<std::uintptr_t>(nullptr) & ptrMask;\n\t}\n\n\tbool getData() const noexcept {\n\t\treturn value & dataMask != std::uintptr_t(0);\n\t}\n\n\tvoid setPtr(PtrT* ptr) noexcept {\n\t\tassert(reinterpret_cast<std::uintptr_t>(ptr) & dataMask == std::uintptr_t(0));\n\n\t\tvalue = reinterpret_cast<std::uintptr_t>(ptr) | (value & dataMask);\n\t}\n\n\tvoid setData(bool data) noexcept {\n\t\tif(data) {\n\t\t\tvalue |= std::uintptr_t(1);\n\t\t} else {\n\t\t\tvalue &= ptrMask;\n\t\t}\n\t}\n\n\tvoid setDataTrue() noexcept {\n\t\tvalue |= std::uintptr_t(1);\n\t}\n\n\tvoid setDataFalse() noexcept {\n\t\tvalue &= ptrMask;\n\t}\n\n\tvoid invertData() noexcept {\n\t\tvalue ^= std::uintptr_t(1);\n\t}\n};\n\ntemplate<typename PtrT, unsigned int BitWidth, typename DataType>\nbool operator==(CompactPtrDataPair<PtrT, BitWidth, DataType> first, CompactPtrDataPair<PtrT, BitWidth, DataType> second) {\n\treturn first.value == second.value;\n}\ntemplate<typename PtrT, unsigned int BitWidth, typename DataType>\nbool operator!=(CompactPtrDataPair<PtrT, BitWidth, DataType> first, CompactPtrDataPair<PtrT, BitWidth, DataType> second) {\n\treturn first.value != second.value;\n}\n\ntemplate<typename PtrT, unsigned int BitWidth = 1, typename DataType = unsigned int>\nclass CompactUniquePtrDataPair : public CompactPtrDataPair<PtrT, BitWidth, DataType> {\npublic:\n\tCompactUniquePtrDataPair() noexcept : CompactPtrDataPair() {}\n\tCompactUniquePtrDataPair(PtrT* ptr, DataType data) noexcept : CompactPtrDataPair(ptr, data) {}\n\t\n\tCompactUniquePtrDataPair(const CompactUniquePtrDataPair&) = delete;\n\tCompactUniquePtrDataPair& operator=(const CompactUniquePtrDataPair&) = delete;\n\n\tCompactUniquePtrDataPair(CompactUniquePtrDataPair&& other) noexcept : CompactPtrDataPair(other.value) {\n\t\tother.value = reinterpret_cast<std::uintptr_t>(nullptr);\n\t}\n\tCompactUniquePtrDataPair& operator=(CompactUniquePtrDataPair&& other) noexcept {\n\t\tstd::uintptr_t tmpValue = this->value;\n\t\tthis->value = other.value;\n\t\tother.value = tmpValue;\n\t}\n\n\t~CompactPtrDataPair() {\n\t\tif(!this->isNullptr()) delete this->getPtr();\n\t}\n};\n\ntemplate<typename PtrT>\nusing CompactPtrBoolPair = CompactPtrDataPair<PtrT, 1, bool>;\ntemplate<typename PtrT>\nusing CompactUniquePtrBoolPair = CompactUniquePtrDataPair<PtrT, 1, bool>;\n\n}"
  },
  {
    "path": "Physics3D/datastructures/iteratorEnd.h",
    "content": "#pragma once\nnamespace P3D {\nstruct IteratorEnd {};\n};"
  },
  {
    "path": "Physics3D/datastructures/iteratorFactory.h",
    "content": "#pragma once\n#include <utility>\n#include \"iteratorEnd.h\"\n\nnamespace P3D {\ntemplate<typename BeginType, typename EndType = BeginType>\nclass IteratorFactory {\n\tBeginType start;\n\tEndType fin;\npublic:\n\tIteratorFactory() = default;\n\tIteratorFactory(const BeginType& start, const EndType& fin) : start(start), fin(fin) {}\n\tIteratorFactory(BeginType&& start, EndType&& fin) : start(std::move(start)), fin(std::move(fin)) {}\n\n\tBeginType begin() const { return start; }\n\tEndType end() const { return fin; }\n};\n\ntemplate<typename BeginType>\nclass IteratorFactoryWithEnd {\n\tBeginType iter;\npublic:\n\tIteratorFactoryWithEnd() = default;\n\tIteratorFactoryWithEnd(const BeginType& iter) : iter(iter) {}\n\tIteratorFactoryWithEnd(BeginType&& iter) : iter(std::move(iter)) {}\n\n\tBeginType begin() const { return iter; }\n\tIteratorEnd end() const { return IteratorEnd(); }\n};\n};"
  },
  {
    "path": "Physics3D/datastructures/monotonicTree.h",
    "content": "#pragma once\n\n#include <utility>\n#include <cstddef>\n#include <assert.h>\n\n#include \"unmanagedArray.h\"\n\nnamespace P3D {\ntemplate<typename T>\nstruct MonotonicTreeNode {\n\tMonotonicTreeNode* children;\n\tT value;\n};\ntemplate<typename T>\nclass MonotonicTree;\n\n/*\n\tWarning: This is an unmanaged object, does not automatically free memory on delete\n*/\ntemplate<typename T>\nclass MonotonicTreeBuilder {\n\tfriend class MonotonicTree<T>;\n\tUnmanagedArray<MonotonicTreeNode<T>> allocatedMemory;\n\tMonotonicTreeNode<T>* currentAlloc;\npublic:\n\n\tMonotonicTreeBuilder() : allocatedMemory(), currentAlloc(nullptr) {}\n\tMonotonicTreeBuilder(UnmanagedArray<MonotonicTreeNode<T>>&& memory) : allocatedMemory(std::move(memory)), currentAlloc(allocatedMemory.get()) {}\n\n\tMonotonicTreeNode<T>* alloc(std::size_t size) {\n\t\tMonotonicTreeNode<T>* claimedBlock = currentAlloc;\n\t\tcurrentAlloc += size;\n\t\tassert(currentAlloc <= allocatedMemory.getEnd());\n\t\treturn claimedBlock;\n\t}\n\n\tT* getPtrToFree() {\n\t\treturn allocatedMemory.getPtrToFree();\n\t}\n};\n\n/*\n\tWarning: This is an unmanaged object, does not automatically free memory on delete\n*/\ntemplate<typename T>\nclass MonotonicTree {\n\tUnmanagedArray<MonotonicTreeNode<T>> allocatedMemory;\npublic:\n\n\tMonotonicTree() : allocatedMemory() {}\n\tMonotonicTree(MonotonicTreeBuilder<T>&& builder) : allocatedMemory(std::move(builder.allocatedMemory)) {\n\t\tassert(builder.currentAlloc == this->allocatedMemory.getEnd());\n\t}\n\tMonotonicTree& operator=(MonotonicTreeBuilder<T>&& builder) {\n\t\tassert(builder.currentAlloc == builder.allocatedMemory.getEnd());\n\n\t\tthis->allocatedMemory = std::move(builder.allocatedMemory);\n\t}\n\n\tMonotonicTreeNode<T>& operator[](std::size_t index) { return allocatedMemory[index]; }\n\tconst MonotonicTreeNode<T>& operator[](std::size_t index) const { return allocatedMemory[index]; }\n\n\tMonotonicTreeNode<T>* begin() { return allocatedMemory.begin(); }\n\tconst MonotonicTreeNode<T>* begin() const { return allocatedMemory.begin(); }\n\tMonotonicTreeNode<T>* end() { return allocatedMemory.end(); }\n\tconst MonotonicTreeNode<T>* end() const { return allocatedMemory.end(); }\n\n\tMonotonicTreeNode<T>* getPtrToFree() {\n\t\treturn allocatedMemory.getPtrToFree();\n\t}\n};\n};"
  },
  {
    "path": "Physics3D/datastructures/parallelArray.h",
    "content": "#pragma once\n\n#include <cstddef>\n\nnamespace P3D {\ntemplate<typename T, std::size_t C>\nstruct ParallelArray {\n\tT values[C];\n\n\tParallelArray() = default;\n\n\tParallelArray(T* values) : values{} {\n\t\tfor(std::size_t i = 0; i < C; i++) {\n\t\t\tthis->values[i] = values[i];\n\t\t}\n\t}\n\n\tParallelArray<T, C> operator+(const ParallelArray<T, C>& other) const {\n\t\tT newValues[C];\n\t\tfor(std::size_t i = 0; i < C; i++) {\n\t\t\tnewValues[i] = values[i] + other.values[i];\n\t\t}\n\t\treturn ParallelArray<T, C>{newValues};\n\t}\n\tParallelArray<T, C> operator-(const ParallelArray<T, C>& other) const {\n\t\tT newValues[C];\n\t\tfor(std::size_t i = 0; i < C; i++) {\n\t\t\tnewValues[i] = values[i] - other.values[i];\n\t\t}\n\t\treturn ParallelArray<T, C>{newValues};\n\t}\n\ttemplate<typename T2>\n\tParallelArray<T, C> operator*(T2& other) const {\n\t\tT newValues[C];\n\t\tfor(std::size_t i = 0; i < C; i++) {\n\t\t\tnewValues[i] = values[i] / other;\n\t\t}\n\t\treturn ParallelArray<T, C>{newValues};\n\t}\n\ttemplate<typename T2>\n\tParallelArray<T, C> operator/(T2& other) const {\n\t\tT newValues[C];\n\t\tfor(std::size_t i = 0; i < C; i++) {\n\t\t\tnewValues[i] = values[i] / other;\n\t\t}\n\t\treturn ParallelArray<T, C>{newValues};\n\t}\n\n\tvoid operator+=(const ParallelArray<T, C>& other) {\n\t\tfor(std::size_t i = 0; i < C; i++) {\n\t\t\tvalues[i] += other.values[i];\n\t\t}\n\t}\n\tvoid operator-=(const ParallelArray<T, C>& other) {\n\t\tfor(std::size_t i = 0; i < C; i++) {\n\t\t\tvalues[i] -= other.values[i];\n\t\t}\n\t}\n\ttemplate<typename T2>\n\tvoid operator*=(T2& other) {\n\t\tfor(std::size_t i = 0; i < C; i++) {\n\t\t\tvalues[i] *= other;\n\t\t}\n\t}\n\ttemplate<typename T2>\n\tvoid operator/=(T2& other) {\n\t\tfor(std::size_t i = 0; i < C; i++) {\n\t\t\tvalues[i] /= other;\n\t\t}\n\t}\n\n\tT& operator[](std::size_t index) {\n\t\treturn values[index];\n\t}\n\n\tT sum() const {\n\t\tT total = values[0];\n\t\tfor(std::size_t i = 1; i < C; i++) {\n\t\t\ttotal += values[i];\n\t\t}\n\t\treturn total;\n\t}\n};\n};"
  },
  {
    "path": "Physics3D/datastructures/sharedArray.h",
    "content": "#pragma once\n\nnamespace P3D {\ntemplate <typename T>\nclass SharedArrayPtr {\n\tT* ptr;\n\tsize_t* refCount;\n\n\tinline SharedArrayPtr(T* data, size_t* refCount)\n\t\t: ptr(data)\n\t\t, refCount(refCount) {}\n\npublic:\n\tSharedArrayPtr()\n\t\t: ptr(nullptr)\n\t\t, refCount(nullptr) {}\n\n\texplicit SharedArrayPtr(T* data)\n\t\t: ptr(data)\n\t\t, refCount((data == nullptr) ? nullptr : new size_t(0)) {}\n\n\tSharedArrayPtr(const SharedArrayPtr<T>& other)\n\t\t: ptr(other.ptr)\n\t\t, refCount(other.refCount) {\n\t\tif (refCount != nullptr)\n\t\t\t++(*refCount);\n\t}\n\n\tSharedArrayPtr<T>& operator=(const SharedArrayPtr<T>& other) {\n\t\tthis->~SharedArrayPtr();\n\t\tthis->ptr = other.ptr;\n\t\tthis->refCount = other.refCount;\n\t\tif (refCount != nullptr)\n\t\t\t++(*refCount);\n\n\t\treturn *this;\n\t}\n\n\tSharedArrayPtr(SharedArrayPtr<T>&& other) noexcept\n\t\t: ptr(other.ptr)\n\t\t, refCount(other.refCount) {\n\t\tother.ptr = nullptr;\n\t\tother.refCount = nullptr;\n\t}\n\n\tSharedArrayPtr& operator=(SharedArrayPtr<T>&& other) noexcept {\n\t\tthis->~SharedArrayPtr();\n\t\tthis->ptr = other.ptr;\n\t\tthis->refCount = other.refCount;\n\t\tother.ptr = nullptr;\n\t\tother.refCount = nullptr;\n\t\treturn *this;\n\t}\n\n\tstatic SharedArrayPtr<T> staticSharedArrayPtr(T* data) {\n\t\treturn SharedArrayPtr<T>(data, nullptr);\n\t}\n\n\t~SharedArrayPtr() {\n\t\tif (refCount != nullptr) {\n\t\t\tif (*refCount == 0) {\n\t\t\t\tdelete refCount;\n\t\t\t\tdelete[] ptr;\n\t\t\t} else {\n\t\t\t\t--(*refCount);\n\t\t\t}\n\t\t}\n\t}\n\n\tT& operator*() const {\n\t\treturn *ptr;\n\t}\n\n\tT& operator[](size_t index) const {\n\t\treturn ptr[index];\n\t}\n\n\tT* operator+(size_t offset) const {\n\t\treturn ptr + offset;\n\t}\n\n\tT* operator-(size_t offset) const {\n\t\treturn ptr - offset;\n\t}\n\n\tT* operator->() const {\n\t\treturn ptr;\n\t}\n\n\tT* get() const {\n\t\treturn ptr;\n\t}\n\n\tbool operator==(T* other) const {\n\t\treturn ptr == other;\n\t}\n\n\tbool operator!=(T* other) const {\n\t\treturn ptr != other;\n\t}\n\n\tbool operator<=(T* other) const {\n\t\treturn ptr <= other;\n\t}\n\n\tbool operator>=(T* other) const {\n\t\treturn ptr >= other;\n\t}\n\n\tbool operator<(T* other) const {\n\t\treturn ptr < other;\n\t}\n\n\tbool operator>(T* other) const {\n\t\treturn ptr > other;\n\t}\n};\n};\n"
  },
  {
    "path": "Physics3D/datastructures/smartPointers.h",
    "content": "#pragma once\n\n#include <memory>\n#include <atomic>\n\nnamespace P3D {\n\nstruct RC {\n\tstd::size_t refCount = 0;\n\n\tvirtual ~RC() {}\n};\n\nstruct AtomicRC {\n\tstd::atomic<std::size_t> refCount = 0;\n\n\tvirtual ~AtomicRC() {}\n};\n\ntemplate<typename T>\nvoid intrusive_ptr_add_ref(T* iptr) noexcept {\n\tiptr->refCount++;\n}\n\ntemplate<typename T>\nvoid intrusive_ptr_release(T* iptr) noexcept {\n\t// retrieve resulting count right from the --count operator, so that std::atomic is properly used if iptr->refCount is atomic. \n\tauto resultingCount = --iptr->refCount;\n\n\tif (resultingCount == 0)\n\t\tdelete iptr;\n}\n\n/*\n\tDefines a managed pointer to a shared object, of which unlike shared_ptr, the refCount is stored in the object itself. \n\tRequires the managed object to define a public (optionally atomic) integer-like field called 'refCount'. \n*/\ntemplate<typename T>\nclass intrusive_ptr {\nprotected:\n\ttemplate<typename U> friend class intrusive_ptr;\n\n\tT* ptr;\n\npublic:\n\tintrusive_ptr() noexcept : ptr(nullptr) {}\n\n\texplicit intrusive_ptr(T* ptr, bool addRef = true) noexcept : ptr(ptr) {\n\t\tif (ptr && addRef)\n\t\t\tintrusive_ptr_add_ref(ptr);\n\t}\n\n\tintrusive_ptr(const intrusive_ptr& iptr) noexcept : ptr(iptr.ptr) {\n\t\tif (ptr)\n\t\t\tintrusive_ptr_add_ref(ptr);\n\t}\n\n\tintrusive_ptr(intrusive_ptr&& iptr) noexcept : ptr(iptr.ptr) {\n\t\tiptr.ptr = nullptr;\n\t}\n\n\t~intrusive_ptr() noexcept {\n\t\tif (ptr)\n\t\t\tintrusive_ptr_release(ptr);\n\t}\n\n\tintrusive_ptr& operator=(const intrusive_ptr& iptr) noexcept {\n\t\treturn operator=(iptr.ptr);\n\t}\n\n\tintrusive_ptr& operator=(intrusive_ptr&& iptr) noexcept {\n\t\tswap(iptr);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename U>\n\tintrusive_ptr& operator=(const intrusive_ptr<U>& iptr) noexcept {\n\t\treturn operator=(iptr.ptr);\n\t}\n\n\tintrusive_ptr& operator=(T* ptr) noexcept {\n\t\tif (ptr != this->ptr) {\n\t\t\tconst T* tmp = this->ptr;\n\t\t\tif (ptr)\n\t\t\t\tintrusive_ptr_add_ref(ptr);\n\t\t\tthis->ptr = ptr;\n\t\t\tif (tmp)\n\t\t\t\tintrusive_ptr_release(tmp);\n\t\t}\n\n\t\treturn *this;\n\t}\n\n\t[[nodiscard]] T& operator*() const noexcept {\n\t\treturn *ptr;\n\t}\n\n\t[[nodiscard]] T* get() const noexcept {\n\t\treturn ptr;\n\t}\n\n\t[[nodiscard]] T* operator->() const noexcept {\n\t\treturn ptr;\n\t}\n\n\t[[nodiscard]] bool valid() const noexcept {\n\t\treturn ptr != nullptr;\n\t}\n\n\t[[nodiscard]] bool invalid() const noexcept {\n\t\treturn ptr == nullptr;\n\t}\n\n\tvoid reset() noexcept {\n\t\tT* const tmp = ptr;\n\t\tptr = nullptr;\n\t\tif (tmp)\n\t\t\tintrusive_ptr_release(tmp);\n\t}\n\n\tvoid swap(intrusive_ptr& iptr) noexcept {\n\t\tT* const tmp = ptr;\n\t\tptr = iptr.ptr;\n\t\tiptr.ptr = tmp;\n\t}\n\n\tvoid attach(T* ptr) noexcept {\n\t\tT* const tmp = this->ptr;\n\t\tthis->ptr = ptr;\n\t\tif (tmp)\n\t\t\tintrusive_ptr_release(tmp);\n\t}\n\n\t[[nodiscard]] T* detach() noexcept {\n\t\tT* const tmp = ptr;\n\t\tptr = nullptr;\n\t\treturn tmp;\n\t}\n\n\t[[nodiscard]] operator bool() const noexcept {\n\t\treturn ptr != nullptr;\n\t}\n\n\t[[nodiscard]] bool operator!() const noexcept {\n\t\treturn ptr == nullptr;\n\t}\n};\n\ntemplate <typename T, typename U>\nbool operator==(const intrusive_ptr<T>& iptr1, const intrusive_ptr<U>& iptr2) noexcept {\n\treturn (iptr1.get() == iptr2.get());\n}\n\ntemplate <typename T, typename U>\nbool operator!=(const intrusive_ptr<T>& iptr1, const intrusive_ptr<U>& iptr2) noexcept {\n\treturn (iptr1.get() != iptr2.get());\n}\n\ntemplate <typename T>\nbool operator==(const intrusive_ptr<T>& iptr, T* ptr) noexcept {\n\treturn (iptr.get() == ptr);\n}\n\ntemplate <typename T>\nbool operator!=(const intrusive_ptr<T>& iptr, T* ptr) noexcept {\n\treturn (iptr.get() != ptr);\n}\n\ntemplate <typename T>\nbool operator==(T* ptr, const intrusive_ptr<T>& iptr) noexcept {\n\treturn (ptr == iptr.get());\n}\n\ntemplate <typename T>\nbool operator!=(T* ptr, const intrusive_ptr<T>& iptr) noexcept {\n\treturn (ptr != iptr.get());\n}\n\ntemplate <typename T>\nbool operator==(std::nullptr_t nptr, const intrusive_ptr<T>& iptr) noexcept {\n\treturn (nullptr == iptr.get());\n}\n\ntemplate <typename T>\nbool operator!=(std::nullptr_t nptr, const intrusive_ptr<T>& iptr) noexcept {\n\treturn (nullptr != iptr.get());\n}\n\ntemplate <typename T>\nbool operator==(const intrusive_ptr<T>& iptr, std::nullptr_t nptr) noexcept {\n\treturn (iptr.get() == nullptr);\n}\n\ntemplate <typename T>\nbool operator!=(const intrusive_ptr<T>& iptr, std::nullptr_t nptr) noexcept {\n\treturn (iptr.get() != nullptr);\n}\n\ntemplate<typename T, typename... Args>\nintrusive_ptr<T> make_intrusive(Args&&... args) noexcept {\n\treturn intrusive_ptr<T>(new T(std::forward<Args>(args)...));\n}\n\ntemplate <class T, class U>\nintrusive_ptr<T> intrusive_cast(const intrusive_ptr<U>& iptr) noexcept {\n\treturn intrusive_ptr<T>(static_cast<T*>(iptr.get()));\n}\n\ntemplate<typename T>\nusing IRef = intrusive_ptr<T>;\n\ntemplate<typename T>\nusing SRef = std::shared_ptr<T>;\n\ntemplate<typename T>\nusing URef = std::unique_ptr<T>;\n\n}"
  },
  {
    "path": "Physics3D/datastructures/uniqueArrayPtr.h",
    "content": "#include <cstddef>\n#include <utility>\n#include <assert.h>\n\nnamespace P3D {\ntemplate<typename T>\nstruct DefaultArrayDelete {\n\tvoid operator()(T* arr) const {\n\t\tdelete[] arr;\n\t}\n};\nstruct DoNothingDelete {\n\tvoid operator()(void* arr) const noexcept {}\n};\n\ntemplate<typename T, typename Deleter = DefaultArrayDelete<T>>\nclass UniqueArrayPtr {\n\tT* ptr;\n\tT* endPtr;\n\n\tDeleter deleter;\npublic:\n\t// ignore endPtr, endPtr is only valid if ptr is not nullptr\n\tUniqueArrayPtr() : ptr(nullptr) {}\n\tUniqueArrayPtr(T* ptr, std::size_t size, Deleter deleter = {}) : ptr(ptr), endPtr(ptr + size), deleter(deleter) {}\n\t~UniqueArrayPtr() {\n\t\tdeleter(this->ptr);\n\t}\n\tUniqueArrayPtr(const UniqueArrayPtr&) = delete;\n\tUniqueArrayPtr& operator=(const UniqueArrayPtr&) = delete;\n\n\tUniqueArrayPtr(UniqueArrayPtr&& other) noexcept : ptr(other.ptr), endPtr(other.endPtr), deleter(std::move(other.deleter)) {\n\t\tother.ptr = nullptr;\n\t}\n\tUniqueArrayPtr& operator=(UniqueArrayPtr&& other) noexcept {\n\t\tstd::swap(this->ptr, other.ptr);\n\t\tstd::swap(this->endPtr, other.endPtr);\n\t\tstd::swap(this->deleter, other.deleter);\n\t\treturn *this;\n\t}\n\n\tT& operator[](std::size_t index) {\n\t\tassert(ptr != nullptr);\n\t\tassert(index >= 0 && ptr + index < endPtr);\n\t\treturn ptr[index];\n\t}\n\tconst T& operator[](std::size_t index) const {\n\t\tassert(ptr != nullptr);\n\t\tassert(index >= 0 && ptr + index < endPtr);\n\t\treturn ptr[index];\n\t}\n\tT& operator*() { assert(ptr != nullptr); return *ptr; }\n\tconst T& operator*() const { assert(ptr != nullptr); return *ptr; }\n\n\tT* begin() { assert(ptr != nullptr); return ptr; }\n\tconst T* begin() const { assert(ptr != nullptr); return ptr; }\n\tT* end() { assert(ptr != nullptr); return endPtr; }\n\tconst T* end() const { assert(ptr != nullptr); return endPtr; }\n\n\tT* get() { return ptr; }\n\tconst T* get() const { return ptr; }\n\n\tT* getEnd() { assert(ptr != nullptr); return endPtr; }\n\tconst T* getEnd() const { assert(ptr != nullptr); return endPtr; }\n};\n};"
  },
  {
    "path": "Physics3D/datastructures/unmanagedArray.h",
    "content": "\n#include <cstddef>\n#include <utility>\n#include <assert.h>\n\n/*\n\tWarning: This is an unmanaged object, does not automatically free memory on delete\n*/\nnamespace P3D {\ntemplate<typename T>\nclass UnmanagedArray {\n\tT* ptr;\n\tT* endPtr;\npublic:\n\t// ignore endPtr, endPtr is only valid if ptr is not nullptr\n\tUnmanagedArray() : ptr(nullptr) {}\n\tUnmanagedArray(T* ptr, std::size_t size) : ptr(ptr), endPtr(ptr + size) {}\n\n\tT& operator[](std::size_t index) {\n\t\tassert(ptr != nullptr);\n\t\tassert(index >= 0 && ptr + index < endPtr);\n\t\treturn ptr[index];\n\t}\n\tconst T& operator[](std::size_t index) const {\n\t\tassert(ptr != nullptr);\n\t\tassert(index >= 0 && ptr + index < endPtr);\n\t\treturn ptr[index];\n\t}\n\tT& operator*() { assert(ptr != nullptr); return *ptr; }\n\tconst T& operator*() const { assert(ptr != nullptr); return *ptr; }\n\n\tT* begin() { assert(ptr != nullptr); return ptr; }\n\tconst T* begin() const { assert(ptr != nullptr); return ptr; }\n\tT* end() { assert(ptr != nullptr); return endPtr; }\n\tconst T* end() const { assert(ptr != nullptr); return endPtr; }\n\n\tT* get() { return ptr; }\n\tconst T* get() const { return ptr; }\n\n\tT* getEnd() { assert(ptr != nullptr); return endPtr; }\n\tconst T* getEnd() const { assert(ptr != nullptr); return endPtr; }\n\n\tT* getPtrToFree() {\n\t\treturn ptr;\n\t}\n};\n};"
  },
  {
    "path": "Physics3D/datastructures/unorderedVector.h",
    "content": "#pragma once\n\n#include <vector>\n#include <assert.h>\n\nnamespace P3D {\ntemplate<typename T>\nclass UnorderedVector : public std::vector<T> {\npublic:\n\tinline void remove(T&& element) {\n\t\tT* el = &element;\n\t\tassert(el >= &std::vector<T>::front());\n\n\t\tT* bck = &std::vector<T>::back();\n\n\t\tassert(el <= bck);\n\n\t\tif(el != bck) {\n\t\t\t*el = std::move(*bck);\n\t\t}\n\t\tstd::vector<T>::pop_back();\n\t}\n};\n};\n"
  },
  {
    "path": "Physics3D/externalforces/directionalGravity.cpp",
    "content": "#include \"directionalGravity.h\"\n\n#include \"../math/position.h\"\n#include \"../part.h\"\n#include \"../physical.h\"\n#include \"../world.h\"\n\nnamespace P3D {\nvoid DirectionalGravity::apply(WorldPrototype* world) {\n\tfor(MotorizedPhysical* p : world->physicals) {\n\t\tp->applyForceAtCenterOfMass(gravity * p->totalMass);\n\t}\n}\ndouble DirectionalGravity::getPotentialEnergyForObject(const WorldPrototype* world, const Part& part) const {\n\treturn Vec3(Position() - part.getCenterOfMass()) * gravity * part.getMass();\n}\ndouble DirectionalGravity::getPotentialEnergyForObject(const WorldPrototype* world, const MotorizedPhysical& phys) const {\n\treturn Vec3(Position() - phys.getCenterOfMass()) * gravity * phys.totalMass;\n}\n};\n"
  },
  {
    "path": "Physics3D/externalforces/directionalGravity.h",
    "content": "#pragma once\n\n#include \"../math/linalg/vec.h\"\n#include \"externalForce.h\"\n\nnamespace P3D {\nclass WorldPrototype;\nclass Part;\nclass MotorizedPhysical;\n\nclass DirectionalGravity : public ExternalForce {\npublic:\n\tVec3 gravity;\n\n\tDirectionalGravity(Vec3 gravity) : gravity(gravity) {}\n\n\tvirtual void apply(WorldPrototype* world) override;\n\tvirtual double getPotentialEnergyForObject(const WorldPrototype* world, const Part& part) const override;\n\tvirtual double getPotentialEnergyForObject(const WorldPrototype* world, const MotorizedPhysical& phys) const override;\n};\n};\n"
  },
  {
    "path": "Physics3D/externalforces/externalForce.cpp",
    "content": "#include \"externalForce.h\"\n\n#include \"../world.h\"\n#include \"../part.h\"\n#include \"../physical.h\"\n\nnamespace P3D {\ndouble ExternalForce::getPotentialEnergyForObject(const WorldPrototype* world, const Part& part) const {\n\treturn 0.0;\n}\ndouble ExternalForce::getPotentialEnergyForObject(const WorldPrototype* world, const MotorizedPhysical& phys) const {\n\tdouble total = 0.0;\n\tfor(const Part& p : phys.rigidBody) {\n\t\ttotal += this->getPotentialEnergyForObject(world, p);\n\t}\n\treturn total;\n}\n\ndouble ExternalForce::getTotalPotentialEnergyForThisForce(const WorldPrototype* world) const {\n\tdouble total = 0.0;\n\tfor(MotorizedPhysical* p : world->physicals) {\n\t\ttotal += this->getPotentialEnergyForObject(world, *p);\n\t}\n\treturn total;\n}\n};\n"
  },
  {
    "path": "Physics3D/externalforces/externalForce.h",
    "content": "#pragma once\n\nnamespace P3D {\nclass WorldPrototype;\nclass Part;\nclass MotorizedPhysical;\n\nclass ExternalForce {\npublic:\n\tvirtual void apply(WorldPrototype* world) = 0;\n\n\t// These do not necessarity have to be implemented. Used for world potential energy computation\n\tvirtual double getPotentialEnergyForObject(const WorldPrototype* world, const Part& part) const;\n\n\t// default implementation sums potential energies of constituent parts\n\tvirtual double getPotentialEnergyForObject(const WorldPrototype* world, const MotorizedPhysical& phys) const;\n\tvirtual double getTotalPotentialEnergyForThisForce(const WorldPrototype* world) const;\n};\n};\n"
  },
  {
    "path": "Physics3D/externalforces/magnetForce.cpp",
    "content": "#include \"magnetForce.h\"\n\n#include \"../world.h\"\n\nnamespace P3D {\n\nMagnetForce::MagnetForce(double pickerStrength, double pickerSpeedStrength) : \n\tselectedPart(nullptr),\n\tlocalSelectedPoint(),\n\tmagnetPoint(),\n\tpickerStrength(pickerStrength),\n\tpickerSpeedStrength(pickerSpeedStrength) {}\n\nMagnetForce::MagnetForce(Part& selectedPart, Vec3 localSelectedPoint, Position magnetPoint, double pickerStrength, double pickerSpeedStrength) :\n\tselectedPart(&selectedPart),\n\tlocalSelectedPoint(localSelectedPoint),\n\tmagnetPoint(magnetPoint),\n\tpickerStrength(pickerStrength),\n\tpickerSpeedStrength(pickerSpeedStrength) {}\n\nvoid MagnetForce::apply(WorldPrototype* world) {\n\tif(selectedPart != nullptr) {\n\t\tPhysical* selectedPartPhys = selectedPart->getPhysical();\n\t\tif(selectedPartPhys != nullptr) {\n\t\t\tMotorizedPhysical* selectedPhysical = selectedPartPhys->mainPhysical;\n\n\t\t\t// Magnet force\n\t\t\tPosition absoluteSelectedPoint = selectedPart->getCFrame().localToGlobal(localSelectedPoint);\n\t\t\tPosition centerOfmass = selectedPhysical->getCenterOfMass();\n\t\t\tVec3 delta = magnetPoint - absoluteSelectedPoint;\n\t\t\tVec3 relativeSelectedPointSpeed = selectedPart->getMotion().getVelocityOfPoint(absoluteSelectedPoint - centerOfmass);\n\t\t\tVec3 force = selectedPhysical->totalMass * (delta * pickerStrength - relativeSelectedPointSpeed * pickerSpeedStrength);\n\n\t\t\tselectedPhysical->applyForceToPhysical(absoluteSelectedPoint - centerOfmass, force);\n\t\t\tselectedPhysical->motionOfCenterOfMass.rotation.rotation[0] *= 0.8;\n\t\t}\n\t}\n}\n};\n\n"
  },
  {
    "path": "Physics3D/externalforces/magnetForce.h",
    "content": "#pragma once\n\n#include \"externalForce.h\"\n#include \"../part.h\"\n#include \"../math/linalg/vec.h\"\n#include \"../math/position.h\"\n\nnamespace P3D {\n\nclass MagnetForce : public ExternalForce {\npublic:\n\tPart* selectedPart;\n\tVec3 localSelectedPoint;\n\tPosition magnetPoint;\n\n\tdouble pickerStrength;\n\tdouble pickerSpeedStrength;\n\n\tMagnetForce() = default;\n\tMagnetForce(double pickerStrength, double pickerSpeedStrength);\n\tMagnetForce(Part& selectedPart, Vec3 localSelectedPoint, Position magnetPoint, double pickerStrength, double pickerSpeedStrength);\n\tvirtual void apply(WorldPrototype* world) override;\n};\n};\n"
  },
  {
    "path": "Physics3D/geometry/builtinShapeClasses.cpp",
    "content": "﻿#include \"builtinShapeClasses.h\"\n\n#include \"shapeCreation.h\"\n#include \"shapeLibrary.h\"\n#include \"../math/constants.h\"\n\n\nnamespace P3D {\n#pragma region CubeClass\nCubeClass::CubeClass() : ShapeClass(8, Vec3(0, 0, 0), ScalableInertialMatrix(Vec3(8.0 / 3.0, 8.0 / 3.0, 8.0 / 3.0), Vec3(0, 0, 0)), CUBE_CLASS_ID) {\n\t// CubeClass is a singleton instance, starting refCount >= 1 ensures it is never deleted\n\tthis->refCount = 1;\n}\n\nbool CubeClass::containsPoint(Vec3 point) const {\n\treturn std::abs(point.x) <= 1.0 && std::abs(point.y) <= 1.0 && std::abs(point.z) <= 1.0;\n}\n\ndouble CubeClass::getIntersectionDistance(Vec3 origin, Vec3 direction) const {\n\tif(origin.x < 0) {\n\t\torigin.x = -origin.x;\n\t\tdirection.x = -direction.x;\n\t}\n\tif(origin.y < 0) {\n\t\torigin.y = -origin.y;\n\t\tdirection.y = -direction.y;\n\t}\n\tif(origin.z < 0) {\n\t\torigin.z = -origin.z;\n\t\tdirection.z = -direction.z;\n\t}\n\n\t//origin + t * direction = x1z\n\tdouble tx = (1 - origin.x) / direction.x;\n\n\tVec3 intersX = origin + tx * direction;\n\tif(std::abs(intersX.y) <= 1.0 && std::abs(intersX.z) <= 1.0) return tx;\n\n\tdouble ty = (1 - origin.y) / direction.y;\n\n\tVec3 intersY = origin + ty * direction;\n\tif(std::abs(intersY.x) <= 1.0 && std::abs(intersY.z) <= 1.0) return ty;\n\n\tdouble tz = (1 - origin.z) / direction.z;\n\n\tVec3 intersZ = origin + tz * direction;\n\tif(std::abs(intersZ.x) <= 1.0 && std::abs(intersZ.y) <= 1.0) return tz;\n\n\treturn std::numeric_limits<double>::infinity();\n}\n\nBoundingBox CubeClass::getBounds(const Rotation& rotation, const DiagonalMat3& scale) const {\n\tMat3 referenceFrame = rotation.asRotationMatrix() * scale;\n\tdouble x = std::abs(referenceFrame(0, 0)) + std::abs(referenceFrame(0, 1)) + std::abs(referenceFrame(0, 2));\n\tdouble y = std::abs(referenceFrame(1, 0)) + std::abs(referenceFrame(1, 1)) + std::abs(referenceFrame(1, 2));\n\tdouble z = std::abs(referenceFrame(2, 0)) + std::abs(referenceFrame(2, 1)) + std::abs(referenceFrame(2, 2));\n\tBoundingBox result{-x,-y,-z,x,y,z};\n\treturn result;\n}\n\ndouble CubeClass::getScaledMaxRadiusSq(DiagonalMat3 scale) const {\n\treturn scale[0] * scale[0] + scale[1] * scale[1] + scale[2] * scale[2];\n}\n\nVec3f CubeClass::furthestInDirection(const Vec3f& direction) const {\n\treturn Vec3f(direction.x < 0 ? -1.0f : 1.0f, direction.y < 0 ? -1.0f : 1.0f, direction.z < 0 ? -1.0f : 1.0f);\n}\n\nPolyhedron CubeClass::asPolyhedron() const {\n\treturn ShapeLibrary::createCube(2.0);\n}\n#pragma endregion\n\n#pragma region SphereClass\nSphereClass::SphereClass() : ShapeClass(4.0 / 3.0 * PI, Vec3(0, 0, 0), ScalableInertialMatrix(Vec3(4.0 / 15.0 * PI, 4.0 / 15.0 * PI, 4.0 / 15.0 * PI), Vec3(0, 0, 0)), SPHERE_CLASS_ID) {\n\t// SphereClass is a singleton instance, starting refCount >= 1 ensures it is never deleted\n\tthis->refCount = 1;\n}\n\nbool SphereClass::containsPoint(Vec3 point) const {\n\treturn lengthSquared(point) <= 1.0;\n}\n\ndouble SphereClass::getIntersectionDistance(Vec3 origin, Vec3 direction) const {\n\t//o*o + o*d*t + o*d*t + t*t*d*d\n\tdouble c = origin * origin - 1;\n\tdouble b = origin * direction;\n\tdouble a = direction * direction;\n\n\t// solve a*t^2 + 2*b*t + c\n\tdouble D = b * b - a * c;\n\tif(D >= 0) {\n\t\treturn (-b + -sqrt(D)) / a;\n\t} else {\n\t\treturn std::numeric_limits<double>::infinity();\n\t}\n}\n\nBoundingBox SphereClass::getBounds(const Rotation& rotation, const DiagonalMat3& scale) const {\n\tdouble s = scale[0];\n\treturn BoundingBox{-s, -s, -s, s, s, s};\n}\n\ndouble SphereClass::getScaledMaxRadiusSq(DiagonalMat3 scale) const {\n\treturn scale[0] * scale[0];\n}\n\ndouble SphereClass::getScaledMaxRadius(DiagonalMat3 scale) const {\n\treturn scale[0];\n}\n\nVec3f SphereClass::furthestInDirection(const Vec3f& direction) const {\n\tfloat lenSq = lengthSquared(direction);\n\tif(lenSq == 0.0f) return Vec3f(1.0f, 0.0f, 0.0f);\n\treturn direction / std::sqrt(lenSq);\n}\n\nPolyhedron SphereClass::asPolyhedron() const {\n\treturn ShapeLibrary::createSphere(1.0, 3);\n}\n\nvoid SphereClass::setScaleX(double newX, DiagonalMat3& scale) const {\n\tscale[0] = newX;\n\tscale[1] = newX;\n\tscale[2] = newX;\n}\n\nvoid SphereClass::setScaleY(double newY, DiagonalMat3& scale) const {\n\tscale[0] = newY;\n\tscale[1] = newY;\n\tscale[2] = newY;\n}\n\nvoid SphereClass::setScaleZ(double newZ, DiagonalMat3& scale) const {\n\tscale[0] = newZ;\n\tscale[1] = newZ;\n\tscale[2] = newZ;\n}\n#pragma endregion\n\n#pragma region CylinderClass\n/*\nInertia of cyllinder:\n\tz = V * 1/2\n\tx, y = V * 7/12\n\n\tX = y + z = 7/12\n\tY = x + z = 7/12\n\tZ = x + y = 1/2\n\n\tx = 1/4 * PI * 2\n\ty = 1/4 * PI * 2\n\tz = 1/3 * PI * 2\n*/\nCylinderClass::CylinderClass() : ShapeClass(PI * 2.0, Vec3(0, 0, 0), ScalableInertialMatrix(Vec3(PI / 2.0, PI / 2.0, PI * 2.0 / 3.0), Vec3(0, 0, 0)), CYLINDER_CLASS_ID) {\n\t// CylinderClass is a singleton instance, starting refCount >= 1 ensures it is never deleted\n\tthis->refCount = 1;\n}\n\nbool CylinderClass::containsPoint(Vec3 point) const {\n\treturn std::abs(point.z) <= 1.0 && point.x * point.x + point.y + point.y <= 1.0;\n}\n\ndouble CylinderClass::getIntersectionDistance(Vec3 origin, Vec3 direction) const {\n\tVec2 xyOrigin(origin.x, origin.y);\n\tVec2 xyDirection(direction.x, direction.y);\n\n\t//o*o + o*d*t + o*d*t + t*t*d*d\n\tdouble c = xyOrigin * xyOrigin - 1;\n\tdouble b = xyOrigin * xyDirection;\n\tdouble a = xyDirection * xyDirection;\n\n\t// solve a*t^2 + 2*b*t + c\n\tdouble D = b * b - a * c;\n\tif(D >= 0) {\n\t\tdouble t = (-b + -sqrt(D)) / a;\n\t\tdouble z = origin.z + t * direction.z;\n\t\tif(std::abs(z) <= 1.0) {\n\t\t\treturn t;\n\t\t} else {\n\t\t\t// origin + t * direction = 1 => t = (1-origin)/direction\n\n\t\t\tdouble t2 = (((origin.z >= 0) ? 1 : -1) - origin.z) / direction.z;\n\n\t\t\tdouble x = origin.x + t2 * direction.x;\n\t\t\tdouble y = origin.y + t2 * direction.y;\n\n\t\t\tif(x * x + y * y <= 1.0) {\n\t\t\t\treturn t2;\n\t\t\t} else {\n\t\t\t\treturn std::numeric_limits<double>::infinity();\n\t\t\t}\n\t\t}\n\t} else {\n\t\treturn std::numeric_limits<double>::infinity();\n\t}\n}\n\nBoundingBox CylinderClass::getBounds(const Rotation& rotation, const DiagonalMat3& scale) const {\n\tdouble height = scale[2];\n\tdouble radius = scale[0];\n\n\tVec3 normalizedZVector = rotation.getZ();\n\tVec3 zVector = normalizedZVector * height;\n\n\tdouble extraX = std::hypot(normalizedZVector.y, normalizedZVector.z);\n\tdouble extraY = std::hypot(normalizedZVector.x, normalizedZVector.z);\n\tdouble extraZ = std::hypot(normalizedZVector.x, normalizedZVector.y);\n\n\tdouble x = std::abs(zVector.x) + extraX * radius;\n\tdouble y = std::abs(zVector.y) + extraY * radius;\n\tdouble z = std::abs(zVector.z) + extraZ * radius;\n\n\treturn BoundingBox{-x, -y, -z, x, y, z};\n}\n\ndouble CylinderClass::getScaledMaxRadiusSq(DiagonalMat3 scale) const {\n\treturn scale[0] * scale[0] + scale[2] * scale[2];\n}\n\nVec3f CylinderClass::furthestInDirection(const Vec3f& direction) const {\n\tfloat z = (direction.z >= 0.0f) ? 1.0f : -1.0f;\n\tfloat lenSq = direction.x * direction.x + direction.y * direction.y;\n\tif(lenSq == 0.0) return Vec3f(1.0f, 0.0f, z);\n\tfloat length = sqrt(lenSq);\n\treturn Vec3f(direction.x / length, direction.y / length, z);\n}\n\nPolyhedron CylinderClass::asPolyhedron() const {\n\treturn ShapeLibrary::createPrism(64, 1.0, 2.0);\n}\n\nvoid CylinderClass::setScaleX(double newX, DiagonalMat3& scale) const {\n\tscale[0] = newX;\n\tscale[1] = newX;\n}\n\nvoid CylinderClass::setScaleY(double newY, DiagonalMat3& scale) const {\n\tscale[0] = newY;\n\tscale[1] = newY;\n}\n#pragma endregion\n\n#pragma region WedgeClass\nWedgeClass::WedgeClass() : ShapeClass(4.0, Vec3(-1 / 3, 0, 1 / 3), ScalableInertialMatrix(Vec3(0.9030, 0.6032, 0.8411), Vec3(0.3517, 0.0210, 0.1667)), WEDGE_CLASS_ID) {\n\t// WedgeClass is a singleton instance, starting refCount >= 1 ensures it is never deleted\n\tthis->refCount = 1;\n}\nbool WedgeClass::containsPoint(Vec3 point) const {\n\treturn std::abs(point.x) <= 1.0 && std::abs(point.y) <= 1.0 && std::abs(point.z) <= 1.0 && point.x + point.y <= 0.0;\n}\ndouble WedgeClass::getIntersectionDistance(Vec3 origin, Vec3 direction) const {\n\tdouble currMin = std::numeric_limits<double>::max();\n\n\tdouble ty = (-1 - origin.y) / direction.y;\n\tVec3 intersY = origin + ty * direction;\n\tif(std::abs(intersY.x) <= 1.0 && std::abs(intersY.z) <= 1.0 && intersY.x <= 1.0  && ty > 0) {\n\t\tif(ty < currMin) {\n\t\t\tcurrMin = ty;\n\t\t}\n\t}\n\tdouble tx = (-1 - origin.x) / direction.x;\n\tVec3 intersX = origin + tx * direction;\n\tif(std::abs(intersX.y) <= 1.0 && std::abs(intersX.z) <= 1.0 && intersX.y <= 1.0 && tx > 0) {\n\t\tif(tx < currMin) {\n\t\t\tcurrMin = tx;\n\t\t}\n\t}\n\t\n\t{\n\t\tdouble tz = (-1 - origin.z) / direction.z;\n\t\tVec3 intersZ = origin + tz * direction;\n\t\tif(std::abs(intersZ.x) <= 1.0 && std::abs(intersZ.y) <= 1.0 && intersZ.x + intersZ.y <= 0.0 && tz > 0) {\n\t\t\tif(tz < currMin) {\n\t\t\t\tcurrMin = tz;\n\t\t\t}\n\t\t}\n\t}\n\t{\n\t\tdouble tz = (1 - origin.z) / direction.z;\n\t\tVec3 intersZ = origin + tz * direction;\n\t\tif(std::abs(intersZ.x) <= 1.0 && std::abs(intersZ.y) <= 1.0 && intersZ.x + intersZ.y <= 0.0 && tz > 0) {\n\t\t\tif(tz < currMin) {\n\t\t\t\tcurrMin = tz;\n\t\t\t}\n\t\t}\n\t}\n\tconst double dn = direction.x + direction.y;\n\tdouble t = (-origin.x - origin.y) / dn;\n\tVec3 point = origin + t * direction;\n\tif(std::abs(point.x) <= 1.0 && std::abs(point.y) <= 1.0 && std::abs(point.z) <= 1.0 && t > 0) {\n\t\tif(t < currMin) {\n\t\t\tcurrMin = t;\n\t\t}\n\t}\n\treturn currMin;\n}\nBoundingBox WedgeClass::getBounds(const Rotation& rotation, const DiagonalMat3& scale) const {\n\tconst Mat3& rotMat = rotation.asRotationMatrix();\n\tVec3 scaleRot[3] = {};\n\tfor(int i = 0; i < 3; i++) {\n\t\tscaleRot[i] = scale[i] * rotMat.getCol(i);\n\t}\n\tconst Vec3 vertices[] = {\n\t\t-scaleRot[0] - scaleRot[1] - scaleRot[2],\n\t\t-scaleRot[0] - scaleRot[1] + scaleRot[2],\n\t\t scaleRot[0] - scaleRot[1] + scaleRot[2],\n\t\t scaleRot[0] - scaleRot[1] - scaleRot[2],\n\t\t-scaleRot[0] + scaleRot[1] - scaleRot[2],\n\t\t-scaleRot[0] + scaleRot[1] + scaleRot[2],\n\t};\n\tdouble xmin = vertices[0].x; double xmax = vertices[0].x;\n\tdouble ymin = vertices[0].y; double ymax = vertices[0].y;\n\tdouble zmin = vertices[0].z; double zmax = vertices[0].z;\n\n\tfor(int i = 1; i < ShapeLibrary::wedgeVertexCount; i++) {\n\t\tconst Vec3& current = vertices[i];\n\t\tif(current.x < xmin) xmin = current.x;\n\t\tif(current.x > xmax) xmax = current.x;\n\t\tif(current.y < ymin) ymin = current.y;\n\t\tif(current.y > ymax) ymax = current.y;\n\t\tif(current.z < zmin) zmin = current.z;\n\t\tif(current.z > zmax) zmax = current.z;\n\t}\n\treturn BoundingBox{xmin, ymin, zmin, xmax, ymax, zmax};\n}\ndouble WedgeClass::getScaledMaxRadiusSq(DiagonalMat3 scale) const {\n\treturn scale[0] * scale[0] + scale[1] * scale[1] + scale[2] * scale[2];\n}\nVec3f WedgeClass::furthestInDirection(const Vec3f& direction) const {\n\tfloat best = ShapeLibrary::wedgeVertices[0] * direction;\n\tVec3f bestVertex = ShapeLibrary::wedgeVertices[0];\n\n\tfor(int i = 1; i < ShapeLibrary::wedgeVertexCount; i++) {\n\t\tfloat current = ShapeLibrary::wedgeVertices[i] * direction;\n\t\tif(current > best) {\n\t\t\tbest = current;\n\t\t\tbestVertex = ShapeLibrary::wedgeVertices[i];\n\t\t}\n\t}\n\treturn bestVertex;\n}\nPolyhedron WedgeClass::asPolyhedron() const {\n\treturn ShapeLibrary::wedge;\n}\n#pragma endregion\n\n#pragma region CornerClass\nCornerClass::CornerClass() : ShapeClass(4 / 3, Vec3(-2 / 3, -2 / 3, -2 / 3), ScalableInertialMatrix(Vec3(0.2000, 0.2000, 0.2000), Vec3(0.0667, 0.0667, 0.0667)), CORNER_CLASS_ID) {\n\t// CornerClass is a singleton instance, starting refCount >= 1 ensures it is never deleted\n\tthis->refCount = 1;\n}\nbool CornerClass::containsPoint(Vec3 point) const {\n\treturn point.x >= -1.0 && point.y >= -1.0 && point.z >= -1.0 && point.x + point.y + point.z <= -1.0;\n}\ndouble CornerClass::getIntersectionDistance(Vec3 origin, Vec3 direction) const {\n\t/*\n\t\t-x - 1\t\t\t= 0;\n\t\t-y - 1\t\t\t= 0;\n\t\t-z - 1\t\t\t= 0;\n\t\tx + y + z + 1\t= 0;\n\t*/\n\tdouble currMin = std::numeric_limits<double>::max();\n\n\tdouble tx = (-1 - origin.x) / direction.x;\n\tVec3 intersX = origin + tx * direction;\n\tif(intersX.y >= -1.0 && intersX.z >= -1.0 && intersX.y + intersX.z <= 0.0 && tx > 0) {\n\t\tif(tx < currMin) {\n\t\t\tcurrMin = tx;\n\t\t}\n\t}\n\tdouble ty = (-1 - origin.y) / direction.y;\n\tVec3 intersY = origin + ty * direction;\n\tif(intersY.x >= -1.0 && intersY.z >= -1.0 && intersY.x + intersY.z <= 0.0 && ty > 0) {\n\t\tif(ty < currMin) {\n\t\t\tcurrMin = ty;\n\t\t}\n\t}\n\tdouble tz = (-1 - origin.z) / direction.z;\n\tVec3 intersZ = origin + tz * direction;\n\tif(intersZ.x >= -1.0 && intersZ.y >= -1.0 && intersZ.x + intersZ.y <= 0.0 && tz > 0) {\n\t\tif(tz < currMin) {\n\t\t\tcurrMin = tz;\n\t\t}\n\t}\n\tconst double dn = direction.x + direction.y + direction.z;\n\tdouble t = (-1 - origin.x - origin.y - origin.z) / dn;\n\tVec3 point = origin + t * direction;\n\tif(point.x >= -1.0 && point.y >= -1.0 && point.z >= -1.0 && t > 0) {\n\t\tif(t < currMin) {\n\t\t\tcurrMin = t;\n\t\t}\n\t}\n\treturn currMin;\n}\nBoundingBox CornerClass::getBounds(const Rotation& rotation, const DiagonalMat3& scale) const {\n\tconst Mat3f& rot = rotation.asRotationMatrix();\n\tVec3f scaleRot[3] = {};\n\tfor(int i = 0; i < 3; i++) {\n\t\tscaleRot[i] = scale[i] * rot.getCol(i);\n\t}\n\tconst Vec3f vertices[] = {\n\t\t-scaleRot[0] - scaleRot[1] - scaleRot[2],\n\t\t-scaleRot[0] - scaleRot[1] + scaleRot[2],\n\t\t-scaleRot[0] + scaleRot[1] - scaleRot[2],\n\t\t scaleRot[0] - scaleRot[1] - scaleRot[2],\n\t};\n\tdouble xmin = vertices[0].x; double xmax = vertices[0].x;\n\tdouble ymin = vertices[0].y; double ymax = vertices[0].y;\n\tdouble zmin = vertices[0].z; double zmax = vertices[0].z;\n\n\tfor(int i = 1; i < ShapeLibrary::cornerVertexCount; i++) {\n\t\tconst Vec3f& current = vertices[i];\n\t\tif(current.x < xmin) xmin = current.x;\n\t\tif(current.x > xmax) xmax = current.x;\n\t\tif(current.y < ymin) ymin = current.y;\n\t\tif(current.y > ymax) ymax = current.y;\n\t\tif(current.z < zmin) zmin = current.z;\n\t\tif(current.z > zmax) zmax = current.z;\n\t}\n\treturn BoundingBox{xmin, ymin, zmin, xmax, ymax, zmax};\n}\ndouble CornerClass::getScaledMaxRadiusSq(DiagonalMat3 scale) const {\n\treturn scale[0] * scale[0] + scale[1] * scale[1] + scale[2] * scale[2];\n}\nVec3f CornerClass::furthestInDirection(const Vec3f& direction) const {\n\tfloat bestDir = ShapeLibrary::cornerVertices[0] * direction;\n\tVec3f bestVertex = ShapeLibrary::cornerVertices[0];\n\tfor(int i = 1; i < ShapeLibrary::cornerVertexCount; i++) {\n\t\tfloat currBest = ShapeLibrary::cornerVertices[i] * direction;\n\t\tif(currBest > bestDir) {\n\t\t\tbestDir = currBest;\n\t\t\tbestVertex = ShapeLibrary::cornerVertices[i];\n\t\t}\n\t}\n\treturn bestVertex;\n}\nPolyhedron CornerClass::asPolyhedron() const {\n\treturn ShapeLibrary::corner;\n}\n#pragma endregion\n\n#pragma region PolyhedronShapeClass\nPolyhedronShapeClass::PolyhedronShapeClass(Polyhedron&& poly) noexcept : poly(std::move(poly)), ShapeClass(poly.getVolume(), poly.getCenterOfMass(), poly.getScalableInertiaAroundCenterOfMass(), CONVEX_POLYHEDRON_CLASS_ID) {}\n\nbool PolyhedronShapeClass::containsPoint(Vec3 point) const {\n\treturn poly.containsPoint(point);\n}\ndouble PolyhedronShapeClass::getIntersectionDistance(Vec3 origin, Vec3 direction) const {\n\treturn poly.getIntersectionDistance(origin, direction);\n}\nBoundingBox PolyhedronShapeClass::getBounds(const Rotation& rotation, const DiagonalMat3& scale) const {\n\treturn poly.getBounds(Mat3f(rotation.asRotationMatrix() * scale));\n}\ndouble PolyhedronShapeClass::getScaledMaxRadius(DiagonalMat3 scale) const {\n\treturn poly.getScaledMaxRadius(scale);\n}\ndouble PolyhedronShapeClass::getScaledMaxRadiusSq(DiagonalMat3 scale) const {\n\treturn poly.getScaledMaxRadiusSq(scale);\n}\nVec3f PolyhedronShapeClass::furthestInDirection(const Vec3f& direction) const {\n\treturn poly.furthestInDirection(direction);\n}\nPolyhedron PolyhedronShapeClass::asPolyhedron() const {\n\treturn poly;\n}\n#pragma endregion\n\n#pragma region PolyhedronShapeClassAVX\nBoundingBox PolyhedronShapeClassAVX::getBounds(const Rotation& rotation, const DiagonalMat3& scale) const {\n\treturn poly.getBoundsAVX(Mat3f(rotation.asRotationMatrix() * scale));\n}\nVec3f PolyhedronShapeClassAVX::furthestInDirection(const Vec3f& direction) const {\n\treturn poly.furthestInDirectionAVX(direction);\n}\n\nBoundingBox PolyhedronShapeClassSSE::getBounds(const Rotation& rotation, const DiagonalMat3& scale) const {\n\treturn poly.getBoundsSSE(Mat3f(rotation.asRotationMatrix() * scale));\n}\nVec3f PolyhedronShapeClassSSE::furthestInDirection(const Vec3f& direction) const {\n\treturn poly.furthestInDirectionSSE(direction);\n}\n\nBoundingBox PolyhedronShapeClassSSE4::getBounds(const Rotation& rotation, const DiagonalMat3& scale) const {\n\treturn poly.getBoundsSSE(Mat3f(rotation.asRotationMatrix() * scale));\n}\nVec3f PolyhedronShapeClassSSE4::furthestInDirection(const Vec3f& direction) const {\n\treturn poly.furthestInDirectionSSE4(direction);\n}\n\nBoundingBox PolyhedronShapeClassFallback::getBounds(const Rotation& rotation, const DiagonalMat3& scale) const {\n\treturn poly.getBoundsFallback(Mat3f(rotation.asRotationMatrix() * scale));\n}\nVec3f PolyhedronShapeClassFallback::furthestInDirection(const Vec3f& direction) const {\n\treturn poly.furthestInDirectionFallback(direction);\n}\n#pragma endregion\n\nconst CubeClass CubeClass::instance;\nconst SphereClass SphereClass::instance;\nconst CylinderClass CylinderClass::instance;\nconst WedgeClass WedgeClass::instance;\nconst CornerClass CornerClass::instance;\n};\n\n"
  },
  {
    "path": "Physics3D/geometry/builtinShapeClasses.h",
    "content": "#pragma once\n\n#include \"polyhedron.h\"\n#include \"shapeClass.h\"\n\nnamespace P3D {\n#define CUBE_CLASS_ID 0\n#define SPHERE_CLASS_ID 1\n#define CYLINDER_CLASS_ID 2\n#define WEDGE_CLASS_ID 3\n#define CORNER_CLASS_ID 4\n#define CONVEX_POLYHEDRON_CLASS_ID 10\n\n\nclass CubeClass : public ShapeClass {\n\tCubeClass();\n\npublic:\n\tvirtual bool containsPoint(Vec3 point) const;\n\tvirtual double getIntersectionDistance(Vec3 origin, Vec3 direction) const;\n\tvirtual BoundingBox getBounds(const Rotation& rotation, const DiagonalMat3& scale) const;\n\tvirtual double getScaledMaxRadiusSq(DiagonalMat3 scale) const;\n\tvirtual Vec3f furthestInDirection(const Vec3f& direction) const;\n\tvirtual Polyhedron asPolyhedron() const;\n\n\tstatic const CubeClass instance;\n};\n\nclass SphereClass : public ShapeClass {\n\tSphereClass();\n\npublic:\n\tvirtual bool containsPoint(Vec3 point) const;\n\tvirtual double getIntersectionDistance(Vec3 origin, Vec3 direction) const;\n\tvirtual BoundingBox getBounds(const Rotation& rotation, const DiagonalMat3& scale) const;\n\tvirtual double getScaledMaxRadiusSq(DiagonalMat3 scale) const;\n\tvirtual double getScaledMaxRadius(DiagonalMat3 scale) const;\n\tvirtual Vec3f furthestInDirection(const Vec3f& direction) const;\n\tvirtual Polyhedron asPolyhedron() const;\n\tvoid setScaleX(double newX, DiagonalMat3& scale) const override;\n\tvoid setScaleY(double newY, DiagonalMat3& scale) const override;\n\tvoid setScaleZ(double newZ, DiagonalMat3& scale) const override;\n\n\tstatic const SphereClass instance;\n};\n\nclass CylinderClass : public ShapeClass {\n\tCylinderClass();\n\npublic:\n\tvirtual bool containsPoint(Vec3 point) const;\n\tvirtual double getIntersectionDistance(Vec3 origin, Vec3 direction) const;\n\tvirtual BoundingBox getBounds(const Rotation& rotation, const DiagonalMat3& scale) const;\n\tvirtual double getScaledMaxRadiusSq(DiagonalMat3 scale) const;\n\tvirtual Vec3f furthestInDirection(const Vec3f& direction) const;\n\tvirtual Polyhedron asPolyhedron() const;\n\tvoid setScaleX(double newX, DiagonalMat3& scale) const override;\n\tvoid setScaleY(double newY, DiagonalMat3& scale) const override;\n\n\tstatic const CylinderClass instance;\n};\n\nclass WedgeClass : public ShapeClass {\n\tWedgeClass();\n\npublic:\n\tvirtual bool containsPoint(Vec3 point) const override;\n\tvirtual double getIntersectionDistance(Vec3 origin, Vec3 direction) const override;\n\tvirtual BoundingBox getBounds(const Rotation& rotation, const DiagonalMat3& scale) const override;\n\tvirtual double getScaledMaxRadiusSq(DiagonalMat3 scale) const override;\n\tvirtual Vec3f furthestInDirection(const Vec3f& direction) const override;\n\tvirtual Polyhedron asPolyhedron() const override;\n\n\tstatic const WedgeClass instance;\n};\n\nclass CornerClass : public ShapeClass {\n\tCornerClass();\n\npublic:\n\tvirtual bool containsPoint(Vec3 point) const override;\n\tvirtual double getIntersectionDistance(Vec3 origin, Vec3 direction) const override;\n\tvirtual BoundingBox getBounds(const Rotation& rotation, const DiagonalMat3& scale) const override;\n\tvirtual double getScaledMaxRadiusSq(DiagonalMat3 scale) const override;\n\tvirtual Vec3f furthestInDirection(const Vec3f& direction) const override;\n\tvirtual Polyhedron asPolyhedron() const override;\n\n\tstatic const CornerClass instance;\n\n};\n\nclass PolyhedronShapeClass : public ShapeClass {\nprotected:\n\tPolyhedron poly;\npublic:\n\tPolyhedronShapeClass(Polyhedron&& poly) noexcept;\n\n\tvirtual bool containsPoint(Vec3 point) const override;\n\tvirtual double getIntersectionDistance(Vec3 origin, Vec3 direction) const override;\n\tvirtual BoundingBox getBounds(const Rotation& rotation, const DiagonalMat3& scale) const override;\n\tvirtual double getScaledMaxRadius(DiagonalMat3 scale) const override;\n\tvirtual double getScaledMaxRadiusSq(DiagonalMat3 scale) const override;\n\tvirtual Vec3f furthestInDirection(const Vec3f& direction) const override;\n\tvirtual Polyhedron asPolyhedron() const override;\n};\n\nclass PolyhedronShapeClassAVX : public PolyhedronShapeClass {\npublic:\n\tusing PolyhedronShapeClass::PolyhedronShapeClass;\n\n\tvirtual BoundingBox getBounds(const Rotation& rotation, const DiagonalMat3& scale) const override;\n\tvirtual Vec3f furthestInDirection(const Vec3f& direction) const override;\n};\n\nclass PolyhedronShapeClassSSE : public PolyhedronShapeClass {\npublic:\n\tusing PolyhedronShapeClass::PolyhedronShapeClass;\n\n\tvirtual BoundingBox getBounds(const Rotation& rotation, const DiagonalMat3& scale) const override;\n\tvirtual Vec3f furthestInDirection(const Vec3f& direction) const override;\n};\n\nclass PolyhedronShapeClassSSE4 : public PolyhedronShapeClass {\npublic:\n\tusing PolyhedronShapeClass::PolyhedronShapeClass;\n\n\tvirtual BoundingBox getBounds(const Rotation& rotation, const DiagonalMat3& scale) const override;\n\tvirtual Vec3f furthestInDirection(const Vec3f& direction) const override;\n};\n\nclass PolyhedronShapeClassFallback : public PolyhedronShapeClass {\npublic:\n\tusing PolyhedronShapeClass::PolyhedronShapeClass;\n\n\tvirtual BoundingBox getBounds(const Rotation& rotation, const DiagonalMat3& scale) const override;\n\tvirtual Vec3f furthestInDirection(const Vec3f& direction) const override;\n};\n};"
  },
  {
    "path": "Physics3D/geometry/computationBuffer.cpp",
    "content": "#include \"computationBuffer.h\"\n\n#include \"../misc/debug.h\"\n#include \"genericIntersection.h\"\n\nnamespace P3D {\nComputationBuffers::ComputationBuffers(int initialVertCount, int initialTriangleCount) :\n\tvertexCapacity(initialVertCount), triangleCapacity(initialTriangleCount) {\n\tcreateVertexBuffersUnsafe(initialVertCount);\n\tcreateTriangleBuffersUnsafe(initialTriangleCount);\n}\n\nvoid ComputationBuffers::ensureCapacity(int vertCapacity, int triangleCapacity) {\n\tif(this->vertexCapacity < vertCapacity) {\n\t\tDebug::log(\"Increasing vertex buffer capacity from %d to %d\", this->vertexCapacity, vertCapacity);\n\t\tdeleteVertexBuffers();\n\t\tcreateVertexBuffersUnsafe(vertCapacity);\n\t}\n\tif(this->triangleCapacity < triangleCapacity) {\n\t\tDebug::log(\"Increasing vertex buffer capacity from %d to %d\", this->triangleCapacity, triangleCapacity);\n\t\tdeleteTriangleBuffers();\n\t\tcreateTriangleBuffersUnsafe(triangleCapacity);\n\t}\n}\n\nComputationBuffers::~ComputationBuffers() {\n\tdeleteVertexBuffers();\n\tdeleteTriangleBuffers();\n}\n\nvoid ComputationBuffers::createVertexBuffersUnsafe(int newVertexCapacity) {\n\tvertBuf = new Vec3f[newVertexCapacity];\n\tknownVecs = new MinkowskiPointIndices[newVertexCapacity];\n\tthis->vertexCapacity = newVertexCapacity;\n}\n\nvoid ComputationBuffers::createTriangleBuffersUnsafe(int newTriangleCapacity) {\n\ttriangleBuf = new Triangle[newTriangleCapacity];\n\tneighborBuf = new TriangleNeighbors[newTriangleCapacity];\n\tedgeBuf = new EdgePiece[newTriangleCapacity];\n\tremovalBuf = new int[newTriangleCapacity];\n\tthis->triangleCapacity = newTriangleCapacity;\n}\n\nvoid ComputationBuffers::deleteVertexBuffers() {\n\tdelete[] vertBuf;\n\tdelete[] knownVecs;\n}\n\nvoid ComputationBuffers::deleteTriangleBuffers() {\n\tdelete[] triangleBuf;\n\tdelete[] neighborBuf;\n\tdelete[] edgeBuf;\n\tdelete[] removalBuf;\n}\n};"
  },
  {
    "path": "Physics3D/geometry/computationBuffer.h",
    "content": "#pragma once\n\n#include \"../math/linalg/vec.h\"\n#include \"convexShapeBuilder.h\"\n\nnamespace P3D {\nstruct MinkowskiPointIndices;\n\nstruct ComputationBuffers {\n\tVec3f* vertBuf;\n\tTriangle* triangleBuf;\n\tTriangleNeighbors* neighborBuf;\n\tEdgePiece* edgeBuf;\n\tint* removalBuf;\n\tMinkowskiPointIndices* knownVecs;\n\n\tint vertexCapacity;\n\tint triangleCapacity;\n\n\tComputationBuffers(int initialVertCount, int initialTriangleCount);\n\tvoid ensureCapacity(int vertCapacity, int triangleCapacity);\n\n\t~ComputationBuffers();\n\n\tComputationBuffers(ComputationBuffers& other) = delete;\n\tComputationBuffers(ComputationBuffers&& other) = delete;\n\tvoid operator=(ComputationBuffers& other) = delete;\n\tvoid operator=(ComputationBuffers&& other) = delete;\n\nprivate:\n\tvoid createVertexBuffersUnsafe(int vertexCapacity);\n\tvoid createTriangleBuffersUnsafe(int triangleCapacity);\n\tvoid deleteVertexBuffers();\n\tvoid deleteTriangleBuffers();\n};\n};"
  },
  {
    "path": "Physics3D/geometry/convexShapeBuilder.cpp",
    "content": "#include \"convexShapeBuilder.h\"\n\n#include <algorithm>\n#include <vector>\n#include <utility>\n\n#include \"../misc/validityHelper.h\"\n#include \"../misc/catchable_assert.h\"\n\nnamespace P3D {\nConvexShapeBuilder::ConvexShapeBuilder(Vec3f* vertBuf, Triangle* triangleBuf, int vertexCount, int triangleCount, TriangleNeighbors* neighborBuf, int* removalBuffer, EdgePiece* newTriangleBuffer)\n\t: vertexBuf(vertBuf), triangleBuf(triangleBuf), vertexCount(vertexCount), triangleCount(triangleCount), neighborBuf(neighborBuf), removalBuffer(removalBuffer), newTriangleBuffer(newTriangleBuffer) {\n\tfillNeighborBuf(triangleBuf, triangleCount, neighborBuf);\n}\n\nConvexShapeBuilder::ConvexShapeBuilder(const Polyhedron& s, Vec3f* vertBuf, Triangle* triangleBuf, TriangleNeighbors* neighborBuf, int* removalBuffer, EdgePiece* newTriangleBuffer)\n\t: vertexBuf(vertBuf), triangleBuf(triangleBuf), vertexCount(s.vertexCount), triangleCount(s.triangleCount), neighborBuf(neighborBuf), removalBuffer(removalBuffer), newTriangleBuffer(newTriangleBuffer) {\n\n\tfor(int i = 0; i < s.vertexCount; i++) {\n\t\tvertBuf[i] = s.getVertex(i);\n\t}\n\n\tfor(int i = 0; i < s.triangleCount; i++) {\n\t\ttriangleBuf[i] = s.getTriangle(i);\n\t}\n\n\tfillNeighborBuf(triangleBuf, triangleCount, neighborBuf);\n}\n\nvoid moveTriangle(Triangle* triangleBuf, TriangleNeighbors* neighborBuf, int oldIndex, int newIndex) {\n\ttriangleBuf[newIndex] = triangleBuf[oldIndex];\n\tTriangleNeighbors neighbors = neighborBuf[oldIndex];\n\tneighborBuf[newIndex] = neighbors;\n\n\t// update neighbors of moved triangle\n\tfor(int neighborIndex : neighbors.neighbors) {\n\t\tneighborBuf[neighborIndex].replaceNeighbor(oldIndex, newIndex);\n\t}\n}\n\nvoid ConvexShapeBuilder::removeTriangle(int triangleIndex) {\n\tTriangle oldT = triangleBuf[triangleIndex];\n\tTriangleNeighbors& oldN = neighborBuf[triangleIndex];\n\n\t// update neighbors of deleted triangle\n\tfor(int neighbor : oldN.neighbors) {\n\t\toldN.replaceNeighbor(triangleIndex, -1);\n\t}\n\n\t// move last triangle in the list to the spot of the deleted triangle\n\ttriangleCount--;\n\tmoveTriangle(triangleBuf, neighborBuf, triangleCount, triangleIndex);\n}\n\nbool ConvexShapeBuilder::isAbove(const Vec3f& point, Triangle t) {\n\tVec3f* verts = vertexBuf;\n\tVec3f v0 = verts[t[0]];\n\tVec3f v1 = verts[t[1]];\n\tVec3f v2 = verts[t[2]];\n\tVec3f normalVec = (v1 - v0) % (v2 - v0);\n\n\treturn (point - v0) * normalVec > 0;\n}\n\n\nstruct ConvexTriangleIterator {\n\tint* removalList;\n\tEdgePiece* newTrianglesList;\n\n\tint newTriangleCount = 0;\n\tint removalCount = 0;\n\n\tVec3f point;\n\tConvexShapeBuilder& shapeBuilder;\n\n\tConvexTriangleIterator(const Vec3f& point, ConvexShapeBuilder& shapeBuilder, int* removalBuffer, EdgePiece* newTrianglesBuffer) : point(point), shapeBuilder(shapeBuilder), removalList(removalBuffer), newTrianglesList(newTrianglesBuffer) {}\n\n\tvoid markTriangleRemoved(int triangle) {\n\t\tshapeBuilder.neighborBuf[triangle].AB_Neighbor = -1;\n\t\tremovalList[removalCount++] = triangle;\n\t}\n\n\tbool isRemoved(int triangle) {\n\t\treturn shapeBuilder.neighborBuf[triangle].AB_Neighbor == -1;\n\t}\n\n\tbool isAbove(Triangle t) {\n\t\tVec3f* verts = shapeBuilder.vertexBuf;\n\t\tVec3f v0 = verts[t[0]];\n\t\tVec3f v1 = verts[t[1]];\n\t\tVec3f v2 = verts[t[2]];\n\t\tVec3f normalVec = (v1 - v0) % (v2 - v0);\n\n\t\treturn (point - v0) * normalVec > 0;\n\t}\n\n\t// returned value is whether the last triangle checked was an edgePiece, in that case add it to the list\n\tvoid recurseTriangle(int currentTriangle, int previousTriangle, int previousTriangleSide) {\n\t\tif(isRemoved(currentTriangle)) return;\n\n\t\tTriangle curTriangle = shapeBuilder.triangleBuf[currentTriangle];\n\n\t\tTriangleNeighbors currentNeighbors = shapeBuilder.neighborBuf[currentTriangle];\n\t\tint arrivingNeighborIndex = currentNeighbors.getNeighborIndex(previousTriangle);\n\n\t\tif(isAbove(curTriangle)) {\n\t\t\t// remove this triangle, check neighbors\n\n\t\t\tmarkTriangleRemoved(currentTriangle);\n\n\t\t\tint rightSide = (arrivingNeighborIndex + 1) % 3;\n\t\t\tint leftSide = (arrivingNeighborIndex + 2) % 3;\n\n\t\t\trecurseTriangle(currentNeighbors[rightSide], currentTriangle, rightSide);\n\n\t\t\trecurseTriangle(currentNeighbors[leftSide], currentTriangle, leftSide);\n\t\t} else {\n\t\t\t// this triangle is an edge, add it to the list\n\n\t\t\tint vertexInTriangleIndex = (previousTriangleSide + 2) % 3;\n\t\t\tint vertex = shapeBuilder.triangleBuf[previousTriangle][vertexInTriangleIndex];\n\n\t\t\tnewTrianglesList[newTriangleCount++] = EdgePiece{vertex, currentTriangle, arrivingNeighborIndex};\n\t\t}\n\t}\n\n\tvoid linkTipTriangles(int next, int previous) {\n\t\tshapeBuilder.neighborBuf[previous].CA_Neighbor = next;\n\t\tshapeBuilder.neighborBuf[next].AB_Neighbor = previous;\n\t}\n\n\tvoid createTipTriangle(int newPointVertex, int previousVertex, int triangleToBeReplaced, EdgePiece replacingInfo) {\n\t\t// int toBeReplaced = removalList[i];\n\t\t// EdgePiece replacingInfo = newTrianglesList[i];\n\n\t\tint edgeTriangle = replacingInfo.edgeTriangle;\n\n\t\tshapeBuilder.triangleBuf[triangleToBeReplaced] = Triangle{newPointVertex, previousVertex, replacingInfo.vertexIndex};\n\n\t\tshapeBuilder.neighborBuf[triangleToBeReplaced].BC_Neighbor = edgeTriangle;\n\t\tshapeBuilder.neighborBuf[edgeTriangle][replacingInfo.neighborIndexOfEdgeTriangle] = triangleToBeReplaced;\n\t}\n\n\tvoid applyUpdates(int newPointVertex) {\n\t\tint easilyMovableTriangles = std::min(newTriangleCount, removalCount);\n\n\t\tint previousVertex = newTrianglesList[newTriangleCount - 1].vertexIndex;\n\t\tint previousTriangle = -1;\n\n\t\t{\n\t\t\tint toBeReplaced = removalList[0];\n\t\t\tEdgePiece replacingInfo = newTrianglesList[0];\n\n\t\t\tcreateTipTriangle(newPointVertex, previousVertex, toBeReplaced, replacingInfo);\n\n\t\t\tpreviousVertex = replacingInfo.vertexIndex;\n\t\t\tpreviousTriangle = toBeReplaced;\n\t\t}\n\n\t\tfor(int i = 1; i < easilyMovableTriangles; i++) {\n\t\t\tint toBeReplaced = removalList[i];\n\t\t\tEdgePiece replacingInfo = newTrianglesList[i];\n\n\t\t\tcreateTipTriangle(newPointVertex, previousVertex, toBeReplaced, replacingInfo);\n\n\t\t\tlinkTipTriangles(toBeReplaced, previousTriangle);\n\n\t\t\tpreviousVertex = replacingInfo.vertexIndex;\n\t\t\tpreviousTriangle = toBeReplaced;\n\t\t}\n\n\t\tif(newTriangleCount >= removalCount) {\n\t\t\t// extra triangles, add at the end\n\n\t\t\tfor(int i = removalCount; i < newTriangleCount; i++) {\n\t\t\t\tint toBeReplaced = shapeBuilder.triangleCount++;\n\t\t\t\tEdgePiece replacingInfo = newTrianglesList[i];\n\n\t\t\t\tcreateTipTriangle(newPointVertex, previousVertex, toBeReplaced, replacingInfo);\n\n\t\t\t\tlinkTipTriangles(toBeReplaced, previousTriangle);\n\n\t\t\t\tpreviousVertex = replacingInfo.vertexIndex;\n\t\t\t\tpreviousTriangle = toBeReplaced;\n\t\t\t}\n\n\n\t\t\tlinkTipTriangles(removalList[0], previousTriangle);\n\t\t} else {\n\t\t\t// not enough triangles to fill the gaps, move stuff back\n\t\t\tlinkTipTriangles(removalList[0], previousTriangle);\n\n\n\n\t\t\t// The shape is entirely valid at this point, we just need to remove the triangles that are no longer part of it\n\n\t\t\tint resultingPolygonSize = shapeBuilder.triangleCount + newTriangleCount - removalCount;\n\n\t\t\tint replacingTriangleCursor = resultingPolygonSize;\n\n\t\t\tfor(int i = newTriangleCount; i < removalCount; i++) {\n\t\t\t\tint triangleToRemove = removalList[i];\n\n\t\t\t\tif(triangleToRemove < resultingPolygonSize) {\n\t\t\t\t\tfor(; replacingTriangleCursor < shapeBuilder.triangleCount; replacingTriangleCursor++) {\n\t\t\t\t\t\tif(!isRemoved(replacingTriangleCursor)) {\n\t\t\t\t\t\t\tmoveTriangle(shapeBuilder.triangleBuf, shapeBuilder.neighborBuf, replacingTriangleCursor, triangleToRemove);\n\t\t\t\t\t\t\treplacingTriangleCursor++;\n\t\t\t\t\t\t\tgoto nextTriangle;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthrow \"Bad state in convexShapeBuilder! could not find non removed triangle to fill the gap!\";\n\t\t\t\t}\n\t\t\t\tnextTriangle:;\n\t\t\t}\n\n\t\t\tshapeBuilder.triangleCount = resultingPolygonSize;\n\t\t}\n\t}\n};\n\nvoid ConvexShapeBuilder::addPoint(const Vec3f& point, int oldTriangleIndex) {\n\tcatchable_assert(isVecValid(point));\n\n\tConvexTriangleIterator iter(point, *this, this->removalBuffer, this->newTriangleBuffer);\n\n\tTriangleNeighbors neighbors = neighborBuf[oldTriangleIndex];\n\n\titer.markTriangleRemoved(oldTriangleIndex);\n\n\titer.recurseTriangle(neighbors[0], oldTriangleIndex, 0);\n\titer.recurseTriangle(neighbors[1], oldTriangleIndex, 1);\n\titer.recurseTriangle(neighbors[2], oldTriangleIndex, 2);\n\n\tvertexBuf[vertexCount++] = point;\n\titer.applyUpdates(vertexCount - 1);\n}\n\nbool ConvexShapeBuilder::addPoint(const Vec3f& point) {\n\tfor(int i = 0; i < triangleCount; i++) {\n\t\tif(isAbove(point, triangleBuf[i])) {\n\t\t\taddPoint(point, i);\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\n\n\nPolyhedron ConvexShapeBuilder::toPolyhedron() const {\n\treturn Polyhedron(stripUnusedVertices(vertexBuf, triangleBuf, vertexCount, triangleCount));\n}\nIndexedShape ConvexShapeBuilder::toIndexedShape() const {\n\treturn IndexedShape(this->toPolyhedron(), neighborBuf);\n}\n};"
  },
  {
    "path": "Physics3D/geometry/convexShapeBuilder.h",
    "content": "#pragma once\n\n#include \"indexedShape.h\"\n#include \"shapeBuilder.h\"\n#include \"../datastructures/sharedArray.h\"\n\nnamespace P3D {\n// used in building shape\nstruct EdgePiece {\n\tint vertexIndex;\n\tint edgeTriangle;\n\tint neighborIndexOfEdgeTriangle;\n};\n/*\n\tNo checks for capacity are done, make sure that vertBuf, triangleBuf and neighborBuf are large enough\n*/\nclass ConvexShapeBuilder {\npublic:\n\tVec3f* vertexBuf;\n\tTriangle* triangleBuf;\n\tint vertexCount;\n\tint triangleCount;\n\tTriangleNeighbors* neighborBuf;\n\n\t// temporary buffers\n\tint* removalBuffer;\n\tEdgePiece* newTriangleBuffer;\n\n\tConvexShapeBuilder(Vec3f* vertBuf, Triangle* triangleBuf, int vertexCount, int triangleCount, TriangleNeighbors* neighborBuf, int* removalBuffer, EdgePiece* newTriangleBuffer);\n\tConvexShapeBuilder(const Polyhedron& s, Vec3f* newVertBuf, Triangle* newTriangleBuf, TriangleNeighbors* neighborBuf, int* removalBuffer, EdgePiece* newTriangleBuffer);\n\n\tvoid addPoint(const Vec3f& point, int oldTriangleIndex);\n\t// returns true if successful\n\tbool addPoint(const Vec3f& point);\n\n\tvoid removeTriangle(int triangleIndex);\n\tbool isAbove(const Vec3f& point, Triangle t);\n\n\tPolyhedron toPolyhedron() const;\n\tIndexedShape toIndexedShape() const;\n};\n};\n"
  },
  {
    "path": "Physics3D/geometry/genericCollidable.h",
    "content": "#pragma once\n\n#include \"../math/linalg/vec.h\"\n\nnamespace P3D {\nstruct GenericCollidable {\n\tvirtual Vec3f furthestInDirection(const Vec3f& direction) const = 0;\n};\n};\n"
  },
  {
    "path": "Physics3D/geometry/genericIntersection.cpp",
    "content": "#include \"genericIntersection.h\"\n\n#include \"../math/linalg/vec.h\"\n#include \"convexShapeBuilder.h\"\n#include \"computationBuffer.h\"\n#include \"../math/utils.h\"\n#include \"../misc/debug.h\"\n#include \"../misc/physicsProfiler.h\"\n#include \"../misc/profiling.h\"\n#include \"polyhedron.h\"\n\n#include \"../misc/validityHelper.h\"\n#include \"../misc/catchable_assert.h\"\n\n#include <stdexcept>\n\n\n#define GJK_MAX_ITER 200\n#define EPA_MAX_ITER 200\n\nnamespace P3D {\ninline static void incDebugTally(HistoricTally<long long, IterationTime>& tally, int iterTime) {\n\tif(iterTime >= GJK_MAX_ITER) {\n\t\ttally.addToTally(IterationTime::LIMIT_REACHED, 1);\n\t} else if(iterTime >= 15) {\n\t\ttally.addToTally(IterationTime::TOOMANY, 1);\n\t} else {\n\t\ttally.addToTally(static_cast<IterationTime>(iterTime), 1);\n\t}\n}\n\nstatic Vec3f getNormalVec(Triangle t, Vec3f* vertices) {\n\tVec3f v0 = vertices[t[0]];\n\tVec3f v1 = vertices[t[1]];\n\tVec3f v2 = vertices[t[2]];\n\n\treturn (v1 - v0) % (v2 - v0);\n}\n\nstatic double getDistanceOfTriangleToOriginSquared(Triangle t, Vec3f* vertices) {\n\treturn pointToPlaneDistanceSquared(getNormalVec(t, vertices), vertices[t[0]]);\n}\n\nstruct NearestSurface {\n\tint triangleIndex;\n\tdouble distanceSquared;\n};\n\nstatic NearestSurface getNearestSurface(const ConvexShapeBuilder& builder) {\n\tint best = 0;\n\tdouble bestDistSq = getDistanceOfTriangleToOriginSquared(builder.triangleBuf[0], builder.vertexBuf);\n\n\tfor(int i = 1; i < builder.triangleCount; i++) {\n\t\tTriangle t = builder.triangleBuf[i];\n\n\t\tdouble distSq = getDistanceOfTriangleToOriginSquared(t, builder.vertexBuf);\n\n\t\tif(distSq < bestDistSq) {\n\t\t\tbest = i;\n\t\t\tbestDistSq = distSq;\n\t\t}\n\t}\n\n\treturn NearestSurface{best, bestDistSq};\n}\n\nstatic MinkPoint getSupport(const ColissionPair& info, const Vec3f& searchDirection) {\n\tVec3f furthest1 = info.scaleFirst * info.first.furthestInDirection(info.scaleFirst * searchDirection);  // in local space of first\n\tVec3f transformedSearchDirection = -info.transform.relativeToLocal(searchDirection);\n\tVec3f furthest2 = info.scaleSecond * info.second.furthestInDirection(info.scaleSecond * transformedSearchDirection);  // in local space of second\n\tVec3f secondVertex = info.transform.localToGlobal(furthest2);  // converted to local space of first\n\n\t/*catchable_assert(isVecValid(furthest1));\n\tcatchable_assert(isVecValid(transformedSearchDirection));\n\tcatchable_assert(isVecValid(furthest2));\n\tcatchable_assert(isVecValid(secondVertex));*/\n\n\treturn MinkPoint{ furthest1 - secondVertex, furthest1, secondVertex };  // local to first\n}\n\nstd::optional<Tetrahedron> runGJKTransformed(const ColissionPair& info, Vec3f searchDirection) {\n\tMinkPoint A(getSupport(info, searchDirection));\n\tMinkPoint B, C, D;\n\n\t// set new searchdirection to be straight at the origin\n\tsearchDirection = -A.p;\n\n\t// GJK 2\n\t// s.A is B.p\n\t// s.B is A.p\n\t// line segment, check if line, or either point closer\n\t// B can't be closer since we picked a point towards the origin\n\t// Just one test, to see if the line segment or A is closer\n\tB = getSupport(info, searchDirection);\n\tif (B.p * searchDirection < 0) {\n\t\tincDebugTally(GJKNoCollidesIterationStatistics, 0);\n\t\treturn std::optional<Tetrahedron>();\n\t}\n\n\tVec3f AO = -B.p;\n\tVec3f AB = A.p - B.p;\n\tsearchDirection = -(AO % AB) % AB;\n\n\tC = getSupport(info, searchDirection);\n\tif (C.p * searchDirection < 0) {\n\t\tincDebugTally(GJKNoCollidesIterationStatistics, 1);\n\t\treturn std::optional<Tetrahedron>();\n\t}\n\t// s.A is C.p  newest\n\t// s.B is B.p\n\t// s.C is A.p\n\t// triangle, check if closest to one of the edges, point, or face\n\tfor(int iter = 0; iter < GJK_MAX_ITER; iter++) {\n\t\tVec3f AO = -C.p;\n\t\tVec3f AB = B.p - C.p;\n\t\tVec3f AC = A.p - C.p;\n\t\tVec3f normal = AB % AC;\n\t\tVec3f nAB = AB % normal;\n\t\tVec3f nAC = normal % AC;\n\n\t\tif(AO * nAB > 0) {\n\t\t\t// edge of AB is closest, searchDirection perpendicular to AB towards O\n\t\t\tA = B;\n\t\t\tB = C;\n\t\t\tsearchDirection = -(AO % AB) % AB;\n\t\t\tC = getSupport(info, searchDirection);\n\t\t\tif(C.p * searchDirection < 0) {\n\t\t\t\tincDebugTally(GJKNoCollidesIterationStatistics, iter+2);\n\t\t\t\treturn std::optional<Tetrahedron>();\n\t\t\t}\n\t\t} else {\n\t\t\tif(AO*nAC > 0) {\n\t\t\t\t// edge of AC is closest, searchDirection perpendicular to AC towards O\n\t\t\t\tB = C;\n\t\t\t\tsearchDirection = -(AO % AC) % AC;\n\t\t\t\tC = getSupport(info, searchDirection);\n\t\t\t\tif(C.p * searchDirection < 0) {\n\t\t\t\t\tincDebugTally(GJKNoCollidesIterationStatistics, iter + 2);\n\t\t\t\t\treturn std::optional<Tetrahedron>();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// hurray! best shape is tetrahedron\n\t\t\t\t// just find which direction to look in\n\t\t\t\tif(normal * AO > 0) {\n\t\t\t\t\tsearchDirection = normal;\n\t\t\t\t} else {\n\t\t\t\t\tsearchDirection = -normal;\n\t\t\t\t\t// invert triangle\n\t\t\t\t\tMinkPoint tmp(A);\n\t\t\t\t\tA = B;\n\t\t\t\t\tB = tmp;\n\t\t\t\t}\n\n\t\t\t\t// GJK 4\n\t\t\t\t// s.A is D.p\n\t\t\t\t// s.B is C.p\n\t\t\t\t// s.C is B.p\n\t\t\t\t// s.D is A.p\n\t\t\t\tD = getSupport(info, searchDirection);\n\t\t\t\tif(D.p * searchDirection < 0) {\n\t\t\t\t\tincDebugTally(GJKNoCollidesIterationStatistics, iter + 2);\n\t\t\t\t\treturn std::optional<Tetrahedron>();\n\t\t\t\t}\n\t\t\t\tVec3f AO = -D.p;\n\t\t\t\t// A is new point, at the top of the tetrahedron\n\t\t\t\tVec3f AB = C.p - D.p;\n\t\t\t\tVec3f AC = B.p - D.p;\n\t\t\t\tVec3f AD = A.p - D.p;\n\t\t\t\tVec3f nABC = AB % AC;\n\t\t\t\tVec3f nACD = AC % AD;\n\t\t\t\tVec3f nADB = AD % AB;\n\n\t\t\t\tif(nACD * AO > 0) {\n\t\t\t\t\t// remove B and continue with triangle\n\t\t\t\t\t// s = Simplex(s.A, s.C, s.D, s.At, s.Ct, s.Dt);\n\t\t\t\t\tC = D;\n\t\t\t\t} else {\n\t\t\t\t\tif(nABC * AO > 0) {\n\t\t\t\t\t\t// remove D and continue with triangle\n\t\t\t\t\t\t// s = Simplex(s.A, s.B, s.C, s.At, s.Bt, s.Ct);\n\t\t\t\t\t\tA = B;\n\t\t\t\t\t\tB = C;\n\t\t\t\t\t\tC = D;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif(nADB * AO > 0) {\n\t\t\t\t\t\t\t// remove C and continue with triangle\n\t\t\t\t\t\t\t//s = Simplex(s.A, s.D, s.B, s.At, s.Dt, s.Bt);\n\t\t\t\t\t\t\tB = C;\n\t\t\t\t\t\t\tC = D;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// GOTCHA! TETRAHEDRON COVERS THE ORIGIN!\n\n\t\t\t\t\t\t\tincDebugTally(GJKCollidesIterationStatistics, iter + 2);\n\t\t\t\t\t\t\treturn std::optional<Tetrahedron>(Tetrahedron{D, C, B, A});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tDebug::logWarn(\"GJK iteration limit reached!\");\n\tincDebugTally(GJKNoCollidesIterationStatistics, GJK_MAX_ITER + 2);\n\treturn std::optional<Tetrahedron>();\n}\n\nvoid initializeBuffer(const Tetrahedron& s, ComputationBuffers& b) {\n\tb.vertBuf[0] = s.A.p;\n\tb.vertBuf[1] = s.B.p;\n\tb.vertBuf[2] = s.C.p;\n\tb.vertBuf[3] = s.D.p;\n\n\tb.triangleBuf[0] = {0,1,2};\n\tb.triangleBuf[1] = {0,2,3};\n\tb.triangleBuf[2] = {0,3,1};\n\tb.triangleBuf[3] = {3,2,1};\n\n\tb.knownVecs[0] = MinkowskiPointIndices{s.A.originFirst, s.A.originSecond};\n\tb.knownVecs[1] = MinkowskiPointIndices{s.B.originFirst, s.B.originSecond};\n\tb.knownVecs[2] = MinkowskiPointIndices{s.C.originFirst, s.C.originSecond};\n\tb.knownVecs[3] = MinkowskiPointIndices{s.D.originFirst, s.D.originSecond};\n}\n\nbool runEPATransformed(const ColissionPair& info, const Tetrahedron& s, Vec3f& intersection, Vec3f& exitVector, ComputationBuffers& bufs) {\n\tinitializeBuffer(s, bufs);\n\n\tConvexShapeBuilder builder(bufs.vertBuf, bufs.triangleBuf, 4, 4, bufs.neighborBuf, bufs.removalBuf, bufs.edgeBuf);\n\n\tfor(int iter = 0; iter < EPA_MAX_ITER; iter++) {\n\t\tNearestSurface ns = getNearestSurface(builder);\n\t\tint closestTriangleIndex = ns.triangleIndex;\n\t\tdouble distSq = ns.distanceSquared;\n\t\tTriangle closestTriangle = builder.triangleBuf[closestTriangleIndex];\n\t\tVec3f a = builder.vertexBuf[closestTriangle[0]];\n\t\tVec3f b = builder.vertexBuf[closestTriangle[1]];\n\t\tVec3f c = builder.vertexBuf[closestTriangle[2]];\n\n\t\tcatchable_assert(isVecValid(a));\n\t\tcatchable_assert(isVecValid(b));\n\t\tcatchable_assert(isVecValid(c));\n\n\t\tVec3f closestTriangleNormal = getNormalVec(closestTriangle, builder.vertexBuf);\n\n\t\tMinkPoint point(getSupport(info, closestTriangleNormal));\n\n\t\t\n\t\tcatchable_assert(isVecValid(point.p));\n\n\t\t// point is the new point to be added, check if it's past the current triangle\n\t\tdouble newPointDistSq = pow(point.p * closestTriangleNormal, 2) / lengthSquared(closestTriangleNormal);\n\n\t\tMinkowskiPointIndices curIndices{point.originFirst, point.originSecond};\n\n\t\t// Do not remove! The inversion catches NaN as well!\n\t\tif(!(newPointDistSq <= distSq * 1.01)) {\n\t\t\tbufs.knownVecs[builder.vertexCount] = curIndices;\n\t\t\tbuilder.addPoint(point.p, closestTriangleIndex);\n\t\t} else {\n\t\t\t// closestTriangle is an edge triangle, so our best direction is towards this triangle.\n\n\t\t\tRayIntersection<float> ri = rayTriangleIntersection(Vec3f(), closestTriangleNormal, a, b, c);\n\n\t\t\texitVector = ri.d * closestTriangleNormal;\n\n\t\t\tcatchable_assert(isVecValid(exitVector));\n\n\t\t\tMinkowskiPointIndices inds[3]{bufs.knownVecs[closestTriangle[0]], bufs.knownVecs[closestTriangle[1]], bufs.knownVecs[closestTriangle[2]]};\n\n\t\t\tVec3f v0 = b - a, v1 = c - a, v2 = exitVector - a;\n\n\t\t\tfloat d00 = v0 * v0;\n\t\t\tfloat d01 = v0 * v1;\n\t\t\tfloat d11 = v1 * v1;\n\t\t\tfloat d20 = v2 * v0;\n\t\t\tfloat d21 = v2 * v1;\n\t\t\tfloat denom = d00 * d11 - d01 * d01;\n\t\t\tfloat v = (d11 * d20 - d01 * d21) / denom;\n\t\t\tfloat w = (d00 * d21 - d01 * d20) / denom;\n\t\t\tfloat u = 1.0f - v - w;\n\n\t\t\tVec3f A0 = inds[0][0], A1 = inds[1][0], A2 = inds[2][0];\n\t\t\tVec3f B0 = inds[0][1], B1 = inds[1][1], B2 = inds[2][1];\n\t\t\t\n\t\t\tVec3f avgFirst = A0 * u + A1 * v + A2 * w;\n\t\t\tVec3f avgSecond = B0 * u + B1 * v + B2 * w;\n\n\t\t\t// intersection = (avgFirst + relativeCFrame.localToGlobal(avgSecond)) / 2;\n\t\t\tintersection = (avgFirst + avgSecond) * 0.5f;\n\t\t\tincDebugTally(EPAIterationStatistics, iter);\n\t\t\treturn true;\n\t\t}\n\t}\n\n\tDebug::logWarn(\"EPA iteration limit exceeded! \");\n\tincDebugTally(EPAIterationStatistics, EPA_MAX_ITER);\n\treturn false;\n}\n};\n"
  },
  {
    "path": "Physics3D/geometry/genericIntersection.h",
    "content": "#pragma once\n\n#include <optional>\n\n#include \"../math/linalg/vec.h\"\n#include \"../math/transform.h\"\n#include \"genericCollidable.h\"\n\nnamespace P3D {\nstruct ComputationBuffers;\nstruct Simplex;\n\nstruct MinkowskiPointIndices {\n\tVec3f indices[2];\n\n\tVec3f& operator[](int i) { return indices[i]; }\n};\n\nstruct Simplex {\n\tVec3 A, B, C, D;\n\tMinkowskiPointIndices At, Bt, Ct, Dt;\n\tint order;\n\tSimplex() = default;\n\tSimplex(Vec3 A, MinkowskiPointIndices At) : A(A), At(At), order(1) {}\n\tSimplex(Vec3 A, Vec3 B, MinkowskiPointIndices At, MinkowskiPointIndices Bt) : A(A), B(B), At(At), Bt(Bt), order(2) {}\n\tSimplex(Vec3 A, Vec3 B, Vec3 C, MinkowskiPointIndices At, MinkowskiPointIndices Bt, MinkowskiPointIndices Ct) : A(A), B(B), C(C), At(At), Bt(Bt), Ct(Ct), order(3) {}\n\tSimplex(Vec3 A, Vec3 B, Vec3 C, Vec3 D, MinkowskiPointIndices At, MinkowskiPointIndices Bt, MinkowskiPointIndices Ct, MinkowskiPointIndices Dt) : A(A), B(B), C(C), D(D), At(At), Bt(Bt), Ct(Ct), Dt(Dt), order(4) {}\n\tvoid insert(Vec3 newA, MinkowskiPointIndices newAt) {\n\t\tD = C;\n\t\tC = B;\n\t\tB = A;\n\t\tA = newA;\n\t\tDt = Ct;\n\t\tCt = Bt;\n\t\tBt = At;\n\t\tAt = newAt;\n\t\torder++;\n\t}\n};\n\nstruct MinkPoint {\n\tVec3f p;\n\tVec3f originFirst;\n\tVec3f originSecond;\n};\n\nstruct Tetrahedron {\n\tMinkPoint A, B, C, D;\n};\n\nstruct ColissionPair {\n\tconst GenericCollidable& first;\n\tconst GenericCollidable& second;\n\tCFramef transform;\n\tDiagonalMat3f scaleFirst;\n\tDiagonalMat3f scaleSecond;\n};\n\nstd::optional<Tetrahedron> runGJKTransformed(const ColissionPair& colissionPair, Vec3f initialSearchDirection);\nbool runEPATransformed(const ColissionPair& colissionPair, const Tetrahedron& s, Vec3f& intersection, Vec3f& exitVector, ComputationBuffers& bufs);\n};"
  },
  {
    "path": "Physics3D/geometry/indexedShape.cpp",
    "content": "#include \"indexedShape.h\"\n\n#include <stdexcept>\n#include \"../misc/validityHelper.h\"\n\nnamespace P3D {\nint& TriangleNeighbors::operator[](int index) {\n\treturn this->neighbors[index];\n}\n\nbool TriangleNeighbors::hasNeighbor(int triangleIndex) const {\n\treturn triangleIndex == neighbors[0] ||\n\t\ttriangleIndex == neighbors[1] ||\n\t\ttriangleIndex == neighbors[2];\n}\n\nint TriangleNeighbors::replaceNeighbor(int oldNeighbor, int newNeighbor) {\n\tfor(int i = 0; i < 3; i++) {\n\t\tif(neighbors[i] == oldNeighbor) {\n\t\t\tneighbors[i] = newNeighbor;\n\t\t\treturn i;\n\t\t}\n\t}\n\tthrow std::runtime_error(\"Neighbor not found in replaceNeighbor\");\n}\n\nint TriangleNeighbors::getNeighborIndex(int neighbor) {\n\tfor(int i = 0; i < 3; i++) {\n\t\tif(neighbors[i] == neighbor) {\n\t\t\treturn i;\n\t\t}\n\t}\n\tthrow std::runtime_error(\"Neighbor not found in getNeighborIndex\");\n}\n\nIndexedShape::IndexedShape(Polyhedron&& poly, TriangleNeighbors* neighborBuf) : Polyhedron(std::move(poly)), neighbors(neighborBuf) {}\nIndexedShape::IndexedShape(const Vec3f* vertices, const Triangle* triangles, int vertexCount, int triangleCount, TriangleNeighbors* neighborBuf) : Polyhedron(vertices, triangles, vertexCount, triangleCount), neighbors(neighborBuf) {}\n\nvoid fillNeighborBuf(const Triangle* triangles, int triangleCount, TriangleNeighbors* neighborBuf) {\n\tfor(int i = 0; i < triangleCount; i++) {\n\t\tfor(int j = i + 1; j < triangleCount; j++) {\n\t\t\tconst Triangle& ti = triangles[i];\n\t\t\tconst Triangle& tj = triangles[j];\n\t\t\tfor(int index1 = 0; index1 < 3; index1++) {\n\t\t\t\tfor(int index2 = 0; index2 < 3; index2++) {\n\t\t\t\t\tif(ti[index1] == tj[index2]) {\n\t\t\t\t\t\tif(ti[(index1 + 1) % 3] == tj[(index2 + 2) % 3]) {\n\t\t\t\t\t\t\t// Triangles are joined at edges: index1 - index1+1 <-> index2-1 - index2\n\n\t\t\t\t\t\t\tneighborBuf[i][(index1 + 2) % 3] = j;\n\t\t\t\t\t\t\tneighborBuf[j][(index2 + 1) % 3] = i;\n\n\t\t\t\t\t\t} else if(ti[(index1 + 2) % 3] == tj[(index2 + 1) % 3]) {\n\t\t\t\t\t\t\t// Triangles are joined at edges: index1-1 - index1 <-> index2 - index2+1\n\n\t\t\t\t\t\t\tneighborBuf[i][(index1 + 1) % 3] = j;\n\t\t\t\t\t\t\tneighborBuf[j][(index2 + 2) % 3] = i;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tgoto nextTriangle;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tnextTriangle:\n\t\t\tcontinue;\n\t\t}\n\t}\n}\n};\n\n\n"
  },
  {
    "path": "Physics3D/geometry/indexedShape.h",
    "content": "#pragma once\n\n#include \"polyhedron.h\"\n#include \"../datastructures/sharedArray.h\"\n\nnamespace P3D {\nstruct TriangleNeighbors {\n\tunion {\n\t\tstruct {\n\t\t\tint BC_Neighbor, CA_Neighbor, AB_Neighbor;\n\t\t};\n\t\tint neighbors[3];\n\t};\n\tint& operator[](int sideIndex);\n\tbool hasNeighbor(int triangleIndex) const;\n\t// replaces neighbor, returns index of replaced neighbor, throws BadNeighborException if not found\n\tint replaceNeighbor(int oldNeighbor, int newNeighbor);\n\tint getNeighborIndex(int neighbor);\n};\n\n/*struct TriangleIndex {\n\tTriangleNeighbors * neighbors;\n\n\tTriangleIndex(Triangle* triangles, int triangleCount, TriangleNeighbors * neighborBuf);\n};*/\n\nstruct IndexedShape : Polyhedron {\n\tTriangleNeighbors* neighbors;\n\n\tIndexedShape(Polyhedron&& poly, TriangleNeighbors* neighborBuf);\n\tIndexedShape(const Vec3f* vertices, const Triangle* triangles, int vertexCount, int triangleCount, TriangleNeighbors* neighborBuf);\n};\n\nvoid fillNeighborBuf(const Triangle* triangles, int triangleCount, TriangleNeighbors* neighborBuf);\n};"
  },
  {
    "path": "Physics3D/geometry/intersection.cpp",
    "content": "#include \"intersection.h\"\n\n#include \"genericIntersection.h\"\n#include \"../misc/physicsProfiler.h\"\n#include \"../misc/profiling.h\"\n#include \"computationBuffer.h\"\n\n#include \"shape.h\"\n#include \"polyhedron.h\"\n\n#include \"../misc/validityHelper.h\"\n#include \"shapeClass.h\"\n\n#include \"../misc/catchable_assert.h\"\n\n#include <algorithm>\n\nnamespace P3D {\nstd::optional<Intersection> intersectsTransformed(const Shape& first, const Shape& second, const CFrame& relativeTransform) {\n\treturn intersectsTransformed(*first.baseShape, *second.baseShape, relativeTransform, first.scale, second.scale);\n}\n\nthread_local ComputationBuffers buffers(1000, 2000);\n\nstd::optional<Intersection> intersectsTransformed(const GenericCollidable& first, const GenericCollidable& second, const CFrame& relativeTransform, const DiagonalMat3& scaleFirst, const DiagonalMat3& scaleSecond) {\n\tColissionPair info{first, second, relativeTransform, scaleFirst, scaleSecond};\n\tphysicsMeasure.mark(PhysicsProcess::GJK_COL);\n\tstd::optional collides = runGJKTransformed(info, -relativeTransform.position);\n\n\tif(collides) {\n\t\tTetrahedron& result = collides.value();\n\t\tphysicsMeasure.mark(PhysicsProcess::EPA);\n\t\tVec3f intersection;\n\t\tVec3f exitVector;\n\n\t\tif(!std::isfinite(result.A.p.x) || !std::isfinite(result.A.p.y) || !std::isfinite(result.A.p.z)) {\n\t\t\tintersection = Vec3f(0.0f, 0.0f, 0.0f);\n\t\t\tfloat minOfScaleFirst = float(std::min(scaleFirst[0], std::min(scaleFirst[1], scaleFirst[2])));\n\t\t\tfloat minOfScaleSecond = float(std::min(scaleSecond[0], std::min(scaleSecond[1], scaleSecond[2])));\n\t\t\texitVector = Vec3f(std::min(minOfScaleFirst, minOfScaleSecond), 0.0f, 0.0f);\n\n\t\t\treturn Intersection(intersection, exitVector);\n\t\t}\n\n\t\tcatchable_assert(isVecValid(result.A.p));\n\t\tcatchable_assert(isVecValid(result.A.originFirst));\n\t\tcatchable_assert(isVecValid(result.A.originSecond));\n\t\tcatchable_assert(isVecValid(result.B.p));\n\t\tcatchable_assert(isVecValid(result.B.originFirst));\n\t\tcatchable_assert(isVecValid(result.B.originSecond));\n\t\tcatchable_assert(isVecValid(result.C.p));\n\t\tcatchable_assert(isVecValid(result.C.originFirst));\n\t\tcatchable_assert(isVecValid(result.C.originSecond));\n\t\tcatchable_assert(isVecValid(result.D.p));\n\t\tcatchable_assert(isVecValid(result.D.originFirst));\n\t\tcatchable_assert(isVecValid(result.D.originSecond));\n\n\t\tbool epaResult = runEPATransformed(info, result, intersection, exitVector, buffers);\n\n\t\tcatchable_assert(isVecValid(exitVector));\n\t\tif(!epaResult) {\n\t\t\treturn std::optional<Intersection>();\n\t\t} else {\n\t\t\treturn std::optional<Intersection>(Intersection(intersection, exitVector));\n\t\t}\n\t} else {\n\t\tphysicsMeasure.mark(PhysicsProcess::OTHER, PhysicsProcess::GJK_NO_COL);\n\t\treturn std::optional<Intersection>();\n\t}\n}\n};\n"
  },
  {
    "path": "Physics3D/geometry/intersection.h",
    "content": "#pragma once\n\n#include <optional>\n\n#include \"../math/linalg/vec.h\"\n#include \"../math/cframe.h\"\n#include \"genericCollidable.h\"\n\nnamespace P3D {\nclass Shape;\nclass Polyhedron;\n\nstruct Intersection {\n\t// Local to first\n\tVec3 intersection;\n\t// Local to first\n\tVec3 exitVector;\n\n\tIntersection(const Vec3& intersection, const Vec3& exitVector) :\n\t\tintersection(intersection),\n\t\texitVector(exitVector) {}\n};\n\nstd::optional<Intersection> intersectsTransformed(const Shape& first, const Shape& second, const CFrame& relativeTransform);\nstd::optional<Intersection> intersectsTransformed(const GenericCollidable& first, const GenericCollidable& second, const CFrame& relativeTransform, const DiagonalMat3& scaleFirst, const DiagonalMat3& scaleSecond);\n};\n"
  },
  {
    "path": "Physics3D/geometry/polyhedron.cpp",
    "content": "#include \"polyhedron.h\"\n\n#include \"../math/linalg/vec.h\"\n#include \"../math/utils.h\"\n#include \"../misc/debug.h\"\n#include \"../misc/validityHelper.h\"\n\nnamespace P3D {\nPolyhedron::Polyhedron(const Vec3f* vertices, const Triangle* triangles, int vertexCount, int triangleCount) :\n\tTriangleMesh(vertexCount, triangleCount, vertices, triangles) {\n\tassert(isValid(*this));\n}\nPolyhedron::Polyhedron(const TriangleMesh& mesh) :\n\tTriangleMesh(mesh) {\n\tassert(isValid(*this));\n}\nPolyhedron::Polyhedron(TriangleMesh&& mesh) noexcept :\n\tTriangleMesh(std::move(mesh)) {\n\tassert(isValid(*this));\n}\nPolyhedron::Polyhedron(const MeshPrototype& mesh) :\n\tTriangleMesh(mesh) {\n\tassert(isValid(*this));\n}\nPolyhedron::Polyhedron(MeshPrototype&& mesh) noexcept :\n\tTriangleMesh(std::move(mesh)) {\n\tassert(isValid(*this));\n}\n\n\nPolyhedron Polyhedron::translated(Vec3f offset) const { return Polyhedron(TriangleMesh::translated(offset)); }\nPolyhedron Polyhedron::rotated(Rotationf rotation) const { return Polyhedron(TriangleMesh::rotated(rotation)); }\nPolyhedron Polyhedron::localToGlobal(CFramef frame) const { return Polyhedron(TriangleMesh::localToGlobal(frame)); }\nPolyhedron Polyhedron::globalToLocal(CFramef frame) const { return Polyhedron(TriangleMesh::globalToLocal(frame)); }\nPolyhedron Polyhedron::scaled(float scaleX, float scaleY, float scaleZ) const { return Polyhedron(TriangleMesh::scaled(scaleX, scaleY, scaleZ)); }\nPolyhedron Polyhedron::scaled(DiagonalMat3f scale) const { return Polyhedron(TriangleMesh::scaled(scale)); }\nPolyhedron Polyhedron::translatedAndScaled(Vec3f translation, DiagonalMat3f scale) const { return Polyhedron(TriangleMesh::translatedAndScaled(translation, scale)); }\n\n//TODO parallelize\nbool Polyhedron::containsPoint(Vec3f point) const {\n\tVec3f ray(1, 0, 0);\n\n\tbool isExiting = false;\n\tdouble bestD = std::numeric_limits<double>::infinity();\n\n\tfor(const Triangle& tri : iterTriangles()) {\n\t\tRayIntersection<float> r = rayTriangleIntersection(point, ray, this->getVertex(tri.firstIndex), this->getVertex(tri.secondIndex), this->getVertex(tri.thirdIndex));\n\t\tif(r.d >= 0 && r.lineIntersectsTriangle()) {\n\t\t\tif(r.d < bestD) {\n\t\t\t\tbestD = r.d;\n\t\t\t\tisExiting = (getNormalVecOfTriangle(tri) * ray >= 0);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn isExiting;\n}\n\ndouble Polyhedron::getVolume() const {\n\tdouble total = 0;\n\tfor(Triangle triangle : iterTriangles()) {\n\t\tVec3 v0 = this->getVertex(triangle.firstIndex);\n\t\tVec3 v1 = this->getVertex(triangle.secondIndex);\n\t\tVec3 v2 = this->getVertex(triangle.thirdIndex);\n\n\t\tdouble D1x = v1.x - v0.x;\n\t\tdouble D1y = v1.y - v0.y;\n\t\tdouble D2x = v2.x - v0.x;\n\t\tdouble D2y = v2.y - v0.y;\n\n\t\tdouble nz = D1x * D2y - D1y * D2x;\n\n\t\ttotal += nz * (v0.z + v1.z + v2.z);\n\t}\n\n\treturn total / 6;\n}\n\nVec3 Polyhedron::getCenterOfMass() const {\n\tVec3 total(0, 0, 0);\n\tfor(Triangle triangle : iterTriangles()) {\n\t\tVec3 v0 = this->getVertex(triangle.firstIndex);\n\t\tVec3 v1 = this->getVertex(triangle.secondIndex);\n\t\tVec3 v2 = this->getVertex(triangle.thirdIndex);\n\n\t\tVec3 normalVec = (v1 - v0) % (v2 - v0);\n\t\tVec3 vFactor = elementWiseSquare(v0) + elementWiseSquare(v1) + elementWiseSquare(v2) + elementWiseMul(v0, v1) + elementWiseMul(v1, v2) + elementWiseMul(v2, v0);\n\n\t\ttotal += elementWiseMul(normalVec, vFactor);\n\t}\n\n\treturn total / (24 * getVolume());\n}\n\n/*\n\tThe total inertial matrix is given by the integral over the volume of the shape of the following matrix:\n\t[[\n\t[y^2+z^2,    xy,    xz],\n\t[xy,    x^2+z^2,    yz],\n\t[xz,    yz,    x^2+y^2]\n\t]]\n\n\tThis has been reworked to a surface integral resulting in the given formulae\n\n\tThis function returns an intermediary step which can easily be converted to scaled versions of the inertial matrix\n*/\nScalableInertialMatrix Polyhedron::getScalableInertia(const CFrame& reference) const {\n\tVec3 totalDiagElementParts(0, 0, 0);\n\tVec3 totalOffDiag(0, 0, 0);\n\tfor(Triangle triangle : iterTriangles()) {\n\t\tVec3 v0 = reference.globalToLocal(Vec3(this->getVertex(triangle.firstIndex)));\n\t\tVec3 v1 = reference.globalToLocal(Vec3(this->getVertex(triangle.secondIndex)));\n\t\tVec3 v2 = reference.globalToLocal(Vec3(this->getVertex(triangle.thirdIndex)));\n\n\t\tVec3 normalVec = (v1 - v0) % (v2 - v0);  // scales x: sy*sz,  y:  sx*sz    z: sx*sy\n\n\t\t// Diagonal Elements      // sx*sx*sx,  sy*sy*sy,  sz*sz*sz\n\t\tVec3 squaredIntegral = elementWiseCube(v0) + elementWiseCube(v1) + elementWiseCube(v2) + elementWiseMul(elementWiseSquare(v0), v1 + v2) + elementWiseMul(elementWiseSquare(v1), v0 + v2) + elementWiseMul(elementWiseSquare(v2), v0 + v1) + elementWiseMul(elementWiseMul(v0, v1), v2);\n\t\tVec3 diagonalElementParts = elementWiseMul(normalVec, squaredIntegral); // (sx^3)*sy*sz, sx*(sy^3)*sz, sx*sy*(sz^3)\n\n\t\ttotalDiagElementParts += diagonalElementParts;\n\n\t\t//total[0][0] += diagonalElementParts.y + diagonalElementParts.z; // sx*sy*sz*(sy^2+sz^2)\n\t\t//total[1][1] += diagonalElementParts.z + diagonalElementParts.x; // sx*sy*sz*(sz^2+sx^2)\n\t\t//total[2][2] += diagonalElementParts.x + diagonalElementParts.y; // sx*sy*sz*(sx^2+sy^2)\n\n\t\t// Other Elements\n\t\tdouble selfProducts = v0.x * v0.y * v0.z + v1.x * v1.y * v1.z + v2.x * v2.y * v2.z;\n\t\tdouble twoSames = v0.x * v0.y * v1.z + v0.x * v1.y * v0.z + v0.x * v1.y * v1.z + v0.x * v0.y * v2.z + v0.x * v2.y * v0.z + v0.x * v2.y * v2.z +\n\t\t\tv1.x * v0.y * v0.z + v1.x * v1.y * v0.z + v1.x * v0.y * v1.z + v1.x * v1.y * v2.z + v1.x * v2.y * v1.z + v1.x * v2.y * v2.z +\n\t\t\tv2.x * v0.y * v0.z + v2.x * v1.y * v2.z + v2.x * v0.y * v2.z + v2.x * v1.y * v1.z + v2.x * v2.y * v0.z + v2.x * v2.y * v1.z;\n\t\tdouble allDifferents = v0.x * v1.y * v2.z + v0.x * v2.y * v1.z + v1.x * v0.y * v2.z + v1.x * v2.y * v0.z + v2.x * v0.y * v1.z + v2.x * v1.y * v0.z;\n\n\t\tdouble xyzIntegral = -(3.0 * selfProducts + twoSames + 0.5 * allDifferents); // scales linearly by sx*sy*sz\n\n\t\ttotalOffDiag += normalVec * xyzIntegral;\n\n\t\t//total[1][0] += dFactor.z * xyzIntegral; // sx*sy*sz* sx*sy\n\t\t//total[2][0] += dFactor.y * xyzIntegral; // sx*sy*sz* sx*sz\n\t\t//total[2][1] += dFactor.x * xyzIntegral; // sx*sy*sz* sz*sy\n\t}\n\n\treturn ScalableInertialMatrix(totalDiagElementParts * (1.0 / 60.0), totalOffDiag * (1.0 / 60.0));\n}\n\nScalableInertialMatrix Polyhedron::getScalableInertiaAroundCenterOfMass() const {\n\treturn getScalableInertia(CFrame(getCenterOfMass()));\n}\n\n/*\n\tThe total inertial matrix is given by the integral over the volume of the shape of the following matrix:\n\t[[\n\t[y^2+z^2,    xy,    xz],\n\t[xy,    x^2+z^2,    yz],\n\t[xz,    yz,    x^2+y^2]\n\t]]\n\n\tThis has been reworked to a surface integral resulting in the given formulae\n*/\nSymmetricMat3 Polyhedron::getInertia(const CFrame& reference) const {\n\treturn getScalableInertia(reference).toMatrix();\n}\n\nSymmetricMat3 Polyhedron::getInertiaAroundCenterOfMass() const {\n\treturn getScalableInertiaAroundCenterOfMass().toMatrix();\n}\n};"
  },
  {
    "path": "Physics3D/geometry/polyhedron.h",
    "content": "#pragma once\n\n#include \"../math/linalg/vec.h\"\n#include \"../math/linalg/mat.h\"\n#include \"../math/rotation.h\"\n#include \"../math/cframe.h\"\n#include \"scalableInertialMatrix.h\"\n\n#include \"triangleMesh.h\"\n\nnamespace P3D {\nclass Polyhedron : public TriangleMesh {\npublic:\n\tPolyhedron() : TriangleMesh() {}\n\texplicit Polyhedron(const TriangleMesh& mesh);\n\texplicit Polyhedron(TriangleMesh&& mesh) noexcept;\n\texplicit Polyhedron(const MeshPrototype& mesh);\n\texplicit Polyhedron(MeshPrototype&& mesh) noexcept;\n\tPolyhedron(const Vec3f* vertices, const Triangle* triangles, int vertexCount, int triangleCount);\n\n\tPolyhedron translated(Vec3f offset) const;\n\tPolyhedron rotated(Rotationf rotation) const;\n\tPolyhedron localToGlobal(CFramef frame) const;\n\tPolyhedron globalToLocal(CFramef frame) const;\n\tPolyhedron scaled(float scaleX, float scaleY, float scaleZ) const;\n\tPolyhedron scaled(DiagonalMat3f scale) const;\n\tPolyhedron translatedAndScaled(Vec3f translation, DiagonalMat3f scale) const;\n\n\tbool containsPoint(Vec3f point) const;\n\n\tdouble getVolume() const;\n\tVec3 getCenterOfMass() const;\n\tSymmetricMat3 getInertiaAroundCenterOfMass() const;\n\tSymmetricMat3 getInertia(const CFrame& reference) const;\n\tScalableInertialMatrix getScalableInertia(const CFrame& reference) const;\n\tScalableInertialMatrix getScalableInertiaAroundCenterOfMass() const;\n};\n};"
  },
  {
    "path": "Physics3D/geometry/scalableInertialMatrix.h",
    "content": "#pragma once\n\n#include \"../math/linalg/vec.h\"\n#include \"../math/linalg/mat.h\"\n\nnamespace P3D {\nclass ScalableInertialMatrix {\n\t// not the exact diagonal components, they must still be added like: m[0][0] = diagonal.y + diagonal.z\n\tVec3 diagonal; // scales (sx^3)*sy*sz, sx*(sy^3)*sz, sx*sy*(sz^3)\n\tVec3 offDiagonal;\n\t// scales z = sx*sy*sz* sx*sy\n\t// scales y = sx*sy*sz* sx*sz\n\t// scales x = sx*sy*sz* sz*sy\n\npublic:\n\tScalableInertialMatrix(Vec3 diagonalConstructors, Vec3 offDiagonal) : diagonal(diagonalConstructors), offDiagonal(offDiagonal) {}\n\n\tSymmetricMat3 toMatrix() const {\n\t\treturn SymmetricMat3{\n\t\t\tdiagonal.y + diagonal.z,\n\t\t\toffDiagonal.z, diagonal.x + diagonal.z,\n\t\t\toffDiagonal.y, offDiagonal.x, diagonal.x + diagonal.y\n\t\t};\n\t}\n\n\tSymmetricMat3 toMatrix(double scaleX, double scaleY, double scaleZ) const {\n\t\tdouble xyz = scaleX * scaleY * scaleZ;\n\t\tVec3 scaledDC = xyz * elementWiseMul(diagonal, Vec3(scaleX * scaleX, scaleY * scaleY, scaleZ * scaleZ));\n\t\tVec3 scaledOD = xyz * elementWiseMul(offDiagonal, Vec3(scaleY * scaleZ, scaleX * scaleZ, scaleX * scaleY));\n\n\t\treturn SymmetricMat3{\n\t\t\tscaledDC.y + scaledDC.z,\n\t\t\tscaledOD.z, scaledDC.x + scaledDC.z,\n\t\t\tscaledOD.y, scaledOD.x, scaledDC.x + scaledDC.y\n\t\t};\n\t}\n\n\tSymmetricMat3 toMatrix(DiagonalMat3 scale) const {\n\t\treturn toMatrix(scale[0], scale[1], scale[2]);\n\t}\n};\n};"
  },
  {
    "path": "Physics3D/geometry/shape.cpp",
    "content": "#include \"shape.h\"\n\n#include \"polyhedron.h\"\n#include \"shapeClass.h\"\n\nnamespace P3D {\nShape::Shape() : baseShape(nullptr), scale{1,1,1} {}\nShape::Shape(intrusive_ptr<const ShapeClass> baseShape, DiagonalMat3 scale) : \n\tbaseShape(std::move(baseShape)), scale(scale) {\n\tassert(this->baseShape);\n}\n\nShape::Shape(intrusive_ptr<const ShapeClass> baseShape) : \n\tbaseShape(std::move(baseShape)), scale{1,1,1} {\n\tassert(this->baseShape);\n}\n\nShape::Shape(intrusive_ptr<const ShapeClass> baseShape, double width, double height, double depth) :\n\tbaseShape(std::move(baseShape)), scale{width / 2, height / 2, depth / 2} {\n\tassert(this->baseShape);\n}\n\n// defined here so that ShapeClass destructor does not need to be called externally\nShape::~Shape() {}\n\nShape::Shape(Shape&&) = default;\nShape& Shape::operator=(Shape&&) = default;\nShape::Shape(const Shape&) = default;\nShape& Shape::operator=(const Shape&) = default;\n\nbool Shape::containsPoint(Vec3 point) const {\n\treturn baseShape->containsPoint(~scale * point);\n}\ndouble Shape::getIntersectionDistance(Vec3 origin, Vec3 direction) const {\n\treturn baseShape->getIntersectionDistance(~scale * origin, ~scale * direction);\n}\ndouble Shape::getVolume() const {\n\treturn baseShape->volume * det(scale);\n}\n\nShape Shape::scaled(const DiagonalMat3& scale) const {\n\treturn Shape(baseShape, this->scale * scale);\n}\nShape Shape::scaled(double scaleX, double scaleY, double scaleZ) const {\n\treturn Shape(baseShape, scale * DiagonalMat3{scaleX, scaleY, scaleZ});\n}\nBoundingBox Shape::getBounds() const {\n\treturn BoundingBox{-scale[0], -scale[1], -scale[2], scale[0], scale[1], scale[2]};\n}\nBoundingBox Shape::getBounds(const Rotation& referenceFrame) const {\n\treturn baseShape->getBounds(referenceFrame, scale);\n}\nVec3 Shape::getCenterOfMass() const {\n\treturn scale * baseShape->centerOfMass;\n}\nSymmetricMat3 Shape::getInertia() const {\n\treturn baseShape->inertia.toMatrix(scale);\n}\ndouble Shape::getMaxRadius() const {\n\treturn baseShape->getScaledMaxRadius(scale);\n}\ndouble Shape::getMaxRadiusSq() const {\n\treturn baseShape->getScaledMaxRadiusSq(scale);\n}\nVec3f Shape::furthestInDirection(const Vec3f& direction) const {\n\treturn baseShape->furthestInDirection(direction);\n}\n\nPolyhedron Shape::asPolyhedron() const {\n\treturn baseShape->asPolyhedron().scaled(scale);\n}\n\nvoid Shape::setWidth(double newWidth) {\n\tbaseShape->setScaleX(newWidth / 2, scale);\n}\nvoid Shape::setHeight(double newHeight) {\n\tbaseShape->setScaleY(newHeight / 2, scale);\n}\nvoid Shape::setDepth(double newDepth) {\n\tbaseShape->setScaleZ(newDepth / 2, scale);\n}\n};\n"
  },
  {
    "path": "Physics3D/geometry/shape.h",
    "content": "#pragma once\n\n\n#include \"../math/boundingBox.h\"\n#include \"../math/linalg/vec.h\"\n#include \"../math/linalg/mat.h\"\n#include \"../math/cframe.h\"\n#include \"../math/transform.h\"\n#include \"../datastructures/smartPointers.h\"\n\nnamespace P3D {\nclass ShapeClass;\nclass Polyhedron;\n\nclass Shape {\npublic:\n\tintrusive_ptr<const ShapeClass> baseShape;\n\tDiagonalMat3 scale;\n\n\tShape();\n\tShape(intrusive_ptr<const ShapeClass> baseShape);\n\tShape(intrusive_ptr<const ShapeClass> baseShape, DiagonalMat3 scale);\n\tShape(intrusive_ptr<const ShapeClass> baseShape, double width, double height, double depth);\n\t~Shape();\n\n\tShape(Shape&&);\n\tShape& operator=(Shape&&);\n\tShape(const Shape&);\n\tShape& operator=(const Shape&);\n\n\t[[nodiscard]] bool containsPoint(Vec3 point) const;\n\t[[nodiscard]] double getIntersectionDistance(Vec3 origin, Vec3 direction) const;\n\t[[nodiscard]] double getVolume() const;\n\n\t[[nodiscard]] double getWidth() const { return scale[0] * 2; }\n\t[[nodiscard]] double getHeight() const { return scale[1] * 2; }\n\t[[nodiscard]] double getDepth() const { return scale[2] * 2; }\n\n\tvoid setWidth(double newWidth);\n\tvoid setHeight(double newHeight);\n\tvoid setDepth(double newDepth);\n\n\t[[nodiscard]] Shape scaled(const DiagonalMat3& scale) const;\n\t[[nodiscard]] Shape scaled(double scaleX, double scaleY, double scaleZ) const;\n\n\t[[nodiscard]] BoundingBox getBounds() const;\n\t[[nodiscard]] BoundingBox getBounds(const Rotation& referenceFrame) const;\n\t[[nodiscard]] Vec3 getCenterOfMass() const;\n\t// defined around the object's Center Of Mass\n\t[[nodiscard]] SymmetricMat3 getInertia() const;\n\t[[nodiscard]] double getMaxRadius() const;\n\t[[nodiscard]] double getMaxRadiusSq() const;\n\n\t[[nodiscard]] Vec3f furthestInDirection(const Vec3f& direction) const;\n\n\t[[nodiscard]] Polyhedron asPolyhedron() const;\n};\n};\n\n"
  },
  {
    "path": "Physics3D/geometry/shapeBuilder.cpp",
    "content": "#include \"shapeBuilder.h\"\n\nnamespace P3D {\nShapeBuilder::ShapeBuilder(Vec3f* vertBuf, Triangle* triangleBuf, int vertexCount, int triangleCount, TriangleNeighbors* neighborBuf)\n\t: vertexBuf(vertBuf), triangleBuf(triangleBuf), vertexCount(vertexCount), triangleCount(triangleCount), neighborBuf(neighborBuf) {\n\tfillNeighborBuf(triangleBuf, triangleCount, neighborBuf);\n}\n\n\nvoid ShapeBuilder::addPoint(Vec3f point, int oldTriangleIndex) {\n\t/* To add point:\n\tAdd point to vertex buffer\n\tRemove triangle that point replaces\n\tAdd 3 new triangles connecting point to oldTriangle's neighbors\n\t\t- ABP\n\t\t- BCP\n\t\t- CAP\n\t\tWith ABC the old triangle and P the new point\n\tupdate neighbors\n\t*/\n\n\tint newPointIndex = vertexCount;\n\n\t// add extra point\n\tvertexBuf[newPointIndex] = point;\n\n\tint t0Index = oldTriangleIndex;\n\tint t1Index = triangleCount;\n\tint t2Index = triangleCount + 1;\n\n\tTriangle oldT = triangleBuf[oldTriangleIndex];\n\tTriangleNeighbors oldNeighbors = neighborBuf[oldTriangleIndex];\n\n\ttriangleBuf[t0Index] = Triangle{oldT[0], oldT[1], newPointIndex};\n\ttriangleBuf[t1Index] = Triangle{oldT[1], oldT[2], newPointIndex};\n\ttriangleBuf[t2Index] = Triangle{oldT[2], oldT[0], newPointIndex};\n\n\tvertexCount++;\n\ttriangleCount += 2;\n\n\tneighborBuf[t0Index].BC_Neighbor = t1Index; neighborBuf[t1Index].CA_Neighbor = t0Index;\n\tneighborBuf[t1Index].BC_Neighbor = t2Index; neighborBuf[t2Index].CA_Neighbor = t1Index;\n\tneighborBuf[t2Index].BC_Neighbor = t0Index; neighborBuf[t0Index].CA_Neighbor = t2Index;\n\n\tneighborBuf[t0Index].AB_Neighbor = oldNeighbors.AB_Neighbor;\n\tneighborBuf[t1Index].AB_Neighbor = oldNeighbors.BC_Neighbor;\n\tneighborBuf[t2Index].AB_Neighbor = oldNeighbors.CA_Neighbor;\n\n\t// update neighbors next to replaced triangle\n\tneighborBuf[oldNeighbors.AB_Neighbor].replaceNeighbor(oldTriangleIndex, t0Index);\n\tneighborBuf[oldNeighbors.BC_Neighbor].replaceNeighbor(oldTriangleIndex, t1Index);\n\tneighborBuf[oldNeighbors.CA_Neighbor].replaceNeighbor(oldTriangleIndex, t2Index);\n\n}\n\nPolyhedron ShapeBuilder::toPolyhedron() const {\n\treturn Polyhedron(vertexBuf, triangleBuf, vertexCount, triangleCount);\n}\n\nIndexedShape ShapeBuilder::toIndexedShape() const {\n\treturn IndexedShape(vertexBuf, triangleBuf, vertexCount, triangleCount, neighborBuf);\n}\n};"
  },
  {
    "path": "Physics3D/geometry/shapeBuilder.h",
    "content": "#pragma once\n\n#include \"shape.h\"\n#include \"indexedShape.h\"\n\nnamespace P3D {\nclass ShapeBuilder {\n\tVec3f* vertexBuf;\n\tTriangle* triangleBuf;\n\tint vertexCount;\n\tint triangleCount;\n\tTriangleNeighbors* neighborBuf;\n\npublic:\n\tShapeBuilder(Vec3f* vertBuf, Triangle* triangleBuf, int vertexCount, int triangleCount, TriangleNeighbors* neighborBuf);\n\n\tvoid addPoint(Vec3f point, int replacingTriangleIndex);\n\n\tPolyhedron toPolyhedron() const;\n\tIndexedShape toIndexedShape() const;\n};\n};\n"
  },
  {
    "path": "Physics3D/geometry/shapeClass.cpp",
    "content": "#include \"shapeClass.h\"\n\nnamespace P3D {\nShapeClass::ShapeClass(double volume, Vec3 centerOfMass, ScalableInertialMatrix inertia, std::size_t intersectionClassID) :\n\tvolume(volume),\n\tcenterOfMass(centerOfMass),\n\tinertia(inertia),\n\tintersectionClassID(intersectionClassID),\n\trefCount(0) {}\n\nShapeClass::~ShapeClass() {}\n\ndouble ShapeClass::getScaledMaxRadius(DiagonalMat3 scale) const {\n\treturn sqrt(this->getScaledMaxRadiusSq(scale));\n}\n\nvoid ShapeClass::setScaleX(double newX, DiagonalMat3& scale) const {\n\tscale[0] = newX;\n}\nvoid ShapeClass::setScaleY(double newY, DiagonalMat3& scale) const {\n\tscale[1] = newY;\n}\nvoid ShapeClass::setScaleZ(double newZ, DiagonalMat3& scale) const {\n\tscale[2] = newZ;\n}\n};\n"
  },
  {
    "path": "Physics3D/geometry/shapeClass.h",
    "content": "#pragma once\n\n#include \"../math/linalg/vec.h\"\n#include \"../math/linalg/mat.h\"\n#include \"../math/rotation.h\"\n#include \"../math/boundingBox.h\"\n#include \"genericCollidable.h\"\n#include \"scalableInertialMatrix.h\"\n\n#include <atomic>\n\nnamespace P3D {\nclass Polyhedron;\n\n// a ShapeClass is defined as a shape with dimentions -1..1 in all axes. All functions work on scaled versions of the shape. \n// examples include: \n//    Sphere of radius=1\n//    Cylinder of radius=1, height=2\n//    Cube of 2x2x2\n//    Custom polygon bounded by a 2x2x2 box\nclass ShapeClass : public GenericCollidable {\npublic:\n\t// For intrusive_ptr. MUST be named refCount, see datastructures/smartPointers.h\n\tmutable std::atomic<std::size_t> refCount;\n\t\n\tstd::size_t intersectionClassID;\n\tdouble volume;\n\tVec3 centerOfMass;\n\tScalableInertialMatrix inertia;\n\n\n\n\tShapeClass(double volume, Vec3 centerOfMass, ScalableInertialMatrix inertia, std::size_t intersectionClassID);\n\tvirtual ~ShapeClass();\n\n\tvirtual bool containsPoint(Vec3 point) const = 0;\n\tvirtual double getIntersectionDistance(Vec3 origin, Vec3 direction) const = 0;\n\n\tvirtual BoundingBox getBounds(const Rotation& referenceFrame, const DiagonalMat3& scale) const = 0;\n\n\tvirtual double getScaledMaxRadius(DiagonalMat3 scale) const;\n\tvirtual double getScaledMaxRadiusSq(DiagonalMat3 scale) const = 0;\n\n\t/*\n\t\tThis must return a valid Vec3f on the surface of the shape, even for 0,0,0\n\t\tDoes not need to take account of NaN or infinities in the input argument\n\t*/\n\tvirtual Vec3f furthestInDirection(const Vec3f& direction) const = 0;\n\n\tvirtual Polyhedron asPolyhedron() const = 0;\n\n\t// these functions determine the relations between the axes, for example, for Sphere, all axes must be equal\n\tvirtual void setScaleX(double newX, DiagonalMat3& scale) const;\n\tvirtual void setScaleY(double newY, DiagonalMat3& scale) const;\n\tvirtual void setScaleZ(double newZ, DiagonalMat3& scale) const;\n};\n};"
  },
  {
    "path": "Physics3D/geometry/shapeCreation.cpp",
    "content": "#include \"shapeCreation.h\"\n\n#include \"shapeClass.h\"\n#include \"polyhedron.h\"\n#include \"builtinShapeClasses.h\"\n\n#include \"../misc/cpuid.h\"\n\n#include \"../datastructures/smartPointers.h\"\n\nnamespace P3D {\nShape boxShape(double width, double height, double depth) {\n\treturn Shape(intrusive_ptr<const ShapeClass>(&CubeClass::instance), width, height, depth);\n}\n\nShape wedgeShape(double width, double height, double depth) {\n\treturn Shape(intrusive_ptr<const ShapeClass>(&WedgeClass::instance), width, height, depth);\n}\n\nShape cornerShape(double width, double height, double depth) {\n\treturn Shape(intrusive_ptr<const ShapeClass>(&CornerClass::instance), width, height, depth);\n}\n\nShape sphereShape(double radius) {\n\treturn Shape(intrusive_ptr<const ShapeClass>(&SphereClass::instance), radius * 2, radius * 2, radius * 2);\n}\n\nShape cylinderShape(double radius, double height) {\n\treturn Shape(intrusive_ptr<const ShapeClass>(&CylinderClass::instance), radius * 2, radius * 2, height);\n}\n\n\nShape polyhedronShape(const Polyhedron& poly) {\n\tBoundingBox bounds = poly.getBounds();\n\tVec3 center = bounds.getCenter();\n\tDiagonalMat3 scale{2 / bounds.getWidth(), 2 / bounds.getHeight(), 2 / bounds.getDepth()};\n\n\tPolyhedronShapeClass* shapeClass;\n\n\tif(CPUIDCheck::hasTechnology(CPUIDCheck::AVX | CPUIDCheck::AVX2 | CPUIDCheck::FMA)) {\n\t\tshapeClass = new PolyhedronShapeClassAVX(poly.translatedAndScaled(-center, scale));\n\t} else if(CPUIDCheck::hasTechnology(CPUIDCheck::SSE | CPUIDCheck::SSE2)) {\n\t\tif(CPUIDCheck::hasTechnology(CPUIDCheck::SSE4_1)) {\n\t\t\tshapeClass = new PolyhedronShapeClassSSE4(poly.translatedAndScaled(-center, scale));\n\t\t} else {\n\t\t\tshapeClass = new PolyhedronShapeClassSSE(poly.translatedAndScaled(-center, scale));\n\t\t}\n\t} else {\n\t\tshapeClass = new PolyhedronShapeClassFallback(poly.translatedAndScaled(-center, scale));\n\t}\n\n\treturn Shape(intrusive_ptr<const ShapeClass>(shapeClass), bounds.getWidth(), bounds.getHeight(), bounds.getDepth());\n}\n};"
  },
  {
    "path": "Physics3D/geometry/shapeCreation.h",
    "content": "#pragma once\n\n#include \"shape.h\"\n\nnamespace P3D {\nclass Polyhedron;\n\nShape boxShape(double width, double height, double depth);\nShape wedgeShape(double width, double height, double depth);\nShape cornerShape(double width, double height, double depth);\nShape sphereShape(double radius);\nShape cylinderShape(double radius, double height);\nShape polyhedronShape(const Polyhedron& poly);\n}"
  },
  {
    "path": "Physics3D/geometry/shapeLibrary.cpp",
    "content": "#include \"shapeLibrary.h\"\n\n#include <utility>\n#include <map>\n\n#include \"../datastructures/buffers.h\"\n\n#include \"../math/linalg/trigonometry.h\"\n#include \"../math/constants.h\"\n\nnamespace P3D::ShapeLibrary {\n\nVec3f octahedronVertices[]{\n\tVec3f(-1.0, 0.0, 0.0), Vec3f(1.0, 0.0, 0.0),\n\tVec3f(0.0, -1.0, 0.0), Vec3f(0.0, 1.0, 0.0),\n\tVec3f(0.0, 0.0, -1.0), Vec3f(0.0, 0.0, 1.0),\n};\n\nTriangle octahedronTriangles[]{\n\t{1,2,4},\n\t{1,3,5},\n\t{1,4,3},\n\t{1,5,2},\n\t{0,2,5},\n\t{0,3,4},\n\t{0,4,2},\n\t{0,5,3}\n};\n\nVec3f icosahedronVertices[]{\n\tVec3f(0, 0.5, g<float>() / 2), Vec3f(0, 0.5, -g<float>() / 2), Vec3f(0, -0.5, -g<float>() / 2), Vec3f(0, -0.5, g<float>() / 2),\n\tVec3f(0.5, g<float>() / 2, 0), Vec3f(0.5, -g<float>() / 2, 0), Vec3f(-0.5, -g<float>() / 2, 0), Vec3f(-0.5, g<float>() / 2, 0),\n\tVec3f(g<float>() / 2, 0, 0.5), Vec3f(-g<float>() / 2, 0, 0.5), Vec3f(-g<float>() / 2, 0, -0.5), Vec3f(g<float>() / 2, 0, -0.5),\n};\n\nTriangle icosahedronTriangles[]{\n\t{0 , 3 , 8}, {0 , 8, 4 }, {0, 4 , 7}, {0, 7 , 9}, {0, 9, 3 },\n\t{2 , 10, 1}, {2 , 1, 11}, {2, 11, 5}, {2, 5 , 6}, {2, 6, 10},\n\t{8 , 3 , 5}, {8 , 5, 11}, {8, 11, 4}, {4, 11, 1}, {4, 1, 7 },\n\t{10, 7 , 1}, {10, 9, 7 }, {9, 10, 6}, {9, 6 , 3}, {3, 6, 5 },\n};\n\nVec3f tetrahedronVertices[]{\n\tVec3f(1.0f, 1.0f, 1.0f),\n\tVec3f(1.0f, -1.0f, -1.0f),\n\tVec3f(-1.0f, -1.0f, 1.0f),\n\tVec3f(-1.0f, 1.0f, -1.0f)\n};\n\nTriangle tetrahedronTriangles[]{\n\t{0, 2, 1}, \n\t{0, 3, 2}, \n\t{0, 1, 3}, \n\t{1, 2, 3}\n};\n\nVec3f trianglePyramidVertices[]{\n\tVec3f(0.0f, 0.0f, 0.0f),\n\tVec3f(1.0f, 0.0f, 0.0f),\n\tVec3f(0.0f, 1.0f, 0.0f),\n\tVec3f(0.0f, 0.0f, 1.0f)\n};\n\nVec3f houseVertices[]{\n\tVec3f(-0.5f, 0.0f, -0.5f), Vec3f(-0.5f, 0.0f, 0.5f), Vec3f(0.5f, 0.0f, 0.5f), Vec3f(0.5f, 0.0f, -0.5f),\n\tVec3f(-0.5f, 1.0f, -0.5f), Vec3f(-0.5f, 1.0f, 0.5f), Vec3f(0.5f, 1.0f, 0.5f), Vec3f(0.5f, 1.0f, -0.5f),\n\tVec3f(0.0f, 1.5f, -5.0f), Vec3f(0.0f, 1.5f, 0.5f)\n};\n\nTriangle houseTriangles[]{\n\t{0, 1, 4}, {5, 4, 1}, // left\n\t{0, 2, 1}, {0, 3, 2}, // bottom\n\t{0, 4, 3}, {3, 4, 7}, // front\n\t{3, 7, 2}, {2, 7, 6}, // right\n\t{1, 2, 5}, {5, 2, 6}, // back\n\t{7, 4, 8}, {5, 6, 9}, // roof\n\t{4, 5, 9}, {4, 9, 8}, {7, 8, 9}, {7, 9, 6} //roof2\n};\n\nVec3f cornerVertices[]{\n\tVec3f(-1.0f, -1.0f, -1.0f), Vec3f(-1.0f, -1.0f, 1.0f), \n\tVec3f(-1.0f, 1.0f, -1.0f), Vec3f(1.0f, -1.0f, -1.0f)\n};\n\nTriangle cornerTriangles[]{\n\t{0, 1, 2},\n\t{2, 3, 0},\n\t{0, 3, 1},\n\t{2, 1, 3}\n};\n\nVec3f wedgeVertices[]{\n\tVec3f(-1.0f, -1.0f, -1.0f), Vec3f(-1.0f, -1.0f, 1.0f), Vec3f(1.0f, -1.0f, 1.0f), Vec3f(1.0f, -1.0f, -1.0f),\n\tVec3f(-1.0f,  1.0f, -1.0f), Vec3f(-1.0f,  1.0f, 1.0f)\n};\n\nTriangle wedgeTriangles[]{\n\t{0, 2, 1}, {0, 3, 2}, // bottom face\n\t{0, 5, 4}, {0, 1, 5}, // back face\n\t{0, 4, 3}, // left face\n\t{1, 2, 5}, // right face\n\t{2, 3, 4}, {2, 4, 5} // diagonal face\n};\n\nTriangle boxTriangles[12] = {\n\t{1,0,2},{3,2,0}, // BOTTOM\n\t{1,5,0},{4,0,5}, // FRONT\n\t{1,2,5},{6,5,2}, // RIGHT\n\t{6,2,7},{3,7,2}, // BACK\n\t{3,0,7},{4,7,0}, // LEFT\n\t{4,5,7},{6,7,5}, // TOP\n};\n\nconst int wedgeVertexCount = 6;\nconst int cornerVertexCount = 4;\nconst Polyhedron tetrahedron(tetrahedronVertices, tetrahedronTriangles, 4, 4);\nconst Polyhedron octahedron(octahedronVertices, octahedronTriangles, 6, 8);\nconst Polyhedron icosahedron(icosahedronVertices, icosahedronTriangles, 12, 20);\nconst Polyhedron trianglePyramid(trianglePyramidVertices, tetrahedronTriangles, 4, 4);\nconst Polyhedron house(houseVertices, houseTriangles, 10, 16);\nconst Polyhedron wedge{wedgeVertices, wedgeTriangles, wedgeVertexCount, 8};\nconst Polyhedron corner{cornerVertices, cornerTriangles, cornerVertexCount, 4};\n\n\nPolyhedron createBox(float width, float height, float depth) {\n\tfloat dx = float(width / 2.0);\n\tfloat dy = float(height / 2.0);\n\tfloat dz = float(depth / 2.0);\n\n\tVec3f vertBuf[8]{\n\t\tVec3f(-dx, -dy, -dz),\n\t\tVec3f(+dx, -dy, -dz),\n\t\tVec3f(+dx, +dy, -dz),\n\t\tVec3f(-dx, +dy, -dz),\n\t\tVec3f(-dx, -dy, +dz),\n\t\tVec3f(+dx, -dy, +dz),\n\t\tVec3f(+dx, +dy, +dz),\n\t\tVec3f(-dx, +dy, +dz)\n\t};\n\treturn Polyhedron(vertBuf, boxTriangles, 8, 12);\n}\n\nPolyhedron createCube(float side) {\n\treturn createBox(side, side, side);\n}\n\nstatic void createTriangleRing(int ring1Start, int ring2Start, int size, EditableMesh& mesh, int offset) {\n\tfor(int i = 0; i < size - 1; i++) {\n\t\tmesh.setTriangle(offset + i * 2, ring1Start + i, ring1Start + i + 1, ring2Start + i);\n\t\tmesh.setTriangle(offset + i * 2 + 1, ring1Start + i + 1, ring2Start + i + 1, ring2Start + i);\n\t}\n\tint last = size - 1;\n\tmesh.setTriangle(offset + last * 2, ring1Start + last, ring1Start, ring2Start + last);\n\tmesh.setTriangle(offset + last * 2 + 1, ring1Start, ring2Start, ring2Start + last);\n}\n\nstatic void createTriangleRingReverse(int ring1Start, int ring2Start, int size, EditableMesh& mesh, int offset) {\n\tfor(int i = 0; i < size - 1; i++) {\n\t\tmesh.setTriangle(offset + i * 2, ring1Start + i + 1, ring1Start + i, ring2Start + i);\n\t\tmesh.setTriangle(offset + i * 2 + 1, ring1Start + i + 1, ring2Start + i, ring2Start + i + 1);\n\t}\n\tint last = size - 1;\n\tmesh.setTriangle(offset + last * 2, ring1Start, ring1Start + last, ring2Start + last);\n\tmesh.setTriangle(offset + last * 2 + 1, ring1Start, ring2Start + last, ring2Start);\n}\n\nstatic void createTriangleFan(int topIndex, int startFan, int size, EditableMesh& mesh, int offset) {\n\tfor(int i = 0; i < size - 1; i++) {\n\t\tmesh.setTriangle(offset + i, topIndex, startFan + i, startFan + i + 1);\n\t}\n}\n\nstatic void createTriangleFanReverse(int topIndex, int startFan, int size, EditableMesh& mesh, int offset) {\n\tfor(int i = 0; i < size - 1; i++) {\n\t\tmesh.setTriangle(offset + i, topIndex, startFan + i + 1, startFan + i);\n\t}\n}\n\nstatic void createTriangleCone(int topIndex, int startFan, int size, EditableMesh& mesh, int offset) {\n\tcreateTriangleFan(topIndex, startFan, size, mesh, offset);\n\tmesh.setTriangle(offset + size - 1, topIndex, startFan + size - 1, startFan);\n}\n\nstatic void createTriangleConeReverse(int topIndex, int startFan, int size, EditableMesh& mesh, int offset) {\n\tcreateTriangleFanReverse(topIndex, startFan, size, mesh, offset);\n\tmesh.setTriangle(offset + size - 1, topIndex, startFan, startFan + size - 1);\n}\n\nstatic void createFlatSurface(int startFan, int size, EditableMesh& mesh, int offset) {\n\tcreateTriangleFan(startFan, startFan + 1, size - 1, mesh, offset);\n}\n\nstatic void createFlatSurfaceReverse(int startFan, int size, EditableMesh& mesh, int offset) {\n\tcreateTriangleFanReverse(startFan, startFan + 1, size - 1, mesh, offset);\n}\n\nPolyhedron createPrism(int sides, float radius, float height) {\n\tEditableMesh result(sides * 2, (sides - 1) * 4);\n\n\t// vertices\n\tfor(int i = 0; i < sides; i++) {\n\t\tfloat angle = i * pi<float>() * 2 / sides;\n\t\tfloat h = height / 2;\n\t\tfloat cr = cos(angle) * radius;\n\t\tfloat sr = sin(angle) * radius;\n\t\tresult.setVertex(i * 2, cr, sr, h);\n\t\tresult.setVertex(i * 2 + 1, cr, sr, -h);\n\t}\n\n\t// triangles\n\t// sides\n\tfor(int i = 0; i < sides; i++) {\n\t\tint botLeft = i * 2;\n\t\tint botRight = ((i + 1) % sides) * 2;\n\t\tresult.setTriangle(i * 2, botLeft, botLeft + 1, botRight); // botLeft, botRight, topLeft\n\t\tresult.setTriangle(i * 2 + 1, botRight + 1, botRight, botLeft + 1); // topRight, topLeft, botRight\n\t}\n\n\t// top and bottom\n\tfor(int i = 0; i < sides - 2; i++) { // common corner is i=0\n\t\tresult.setTriangle(i + sides * 2, 0, (i + 1) * 2, (i + 2) * 2);\n\t\tresult.setTriangle(i + (sides - 2) + sides * 2, 1, (i + 2) * 2 + 1, (i + 1) * 2 + 1);\n\t}\n\treturn Polyhedron(std::move(result));\n}\n\nPolyhedron createPointyPrism(int sides, float radius, float height, float topOffset, float bottomOffset) {\n\tEditableMesh result(sides * 2 + 2, sides * 4);\n\n\t// vertices\n\tfor(int i = 0; i < sides; i++) {\n\t\tfloat angle = i * pi<float>() * 2 / sides;\n\t\tresult.setVertex(i * 2, cos(angle) * radius, -height / 2, sin(angle) * radius);\n\t\tresult.setVertex(i * 2 + 1, cos(angle) * radius, height / 2, sin(angle) * radius);\n\t}\n\n\tint bottomIndex = sides * 2;\n\tint topIndex = sides * 2 + 1;\n\n\tresult.setVertex(bottomIndex, 0, -height / 2 - bottomOffset, 0);\n\tresult.setVertex(topIndex, 0, height / 2 + topOffset, 0);\n\n\t// triangles\n\t// sides\n\tfor(int i = 0; i < sides; i++) {\n\t\tint botLeft = i * 2;\n\t\tint botRight = ((i + 1) % sides) * 2;\n\t\tresult.setTriangle(i * 2, botLeft, botLeft + 1, botRight); // botLeft, botRight, topLeft\n\t\tresult.setTriangle(i * 2 + 1, botRight + 1, botRight, botLeft + 1); // topRight, topLeft, botRight\n\t}\n\n\t// top and bottom\n\tfor(int i = 0; i < sides; i++) { // common corner is i=0\n\t\tresult.setTriangle(i + sides * 2, bottomIndex, i * 2, ((i + 1) % sides) * 2);\n\t\tresult.setTriangle(i + sides + sides * 2, topIndex, ((i + 1) % sides) * 2 + 1, i * 2 + 1);\n\t}\n\n\treturn Polyhedron(std::move(result));\n}\n\n// divides every triangle into 4 smaller triangles\nstatic std::pair<Vec3f*, Triangle*> tesselate(Vec3f* vecBuf, Triangle* triangleBuf, int vertexCount, int triangleCount) {\n\tassert(triangleCount % 2 == 0);\n\tint newVecBufSize = vertexCount + triangleCount * 3 / 2;\n\tint newTriIndex = triangleCount * 4;\n\n\tint curMapIndex = vertexCount;\n\n\tstd::map<std::pair<int, int>, int> newPoints;\n\n\n\n\tfor(int i = triangleCount; i-- > 0;) {\n\t\t// first collect the 6 new points\n\n\t\tTriangle& curT = triangleBuf[i];\n\n\t\tTriangle newCenterTriangle;\n\n\t\tfor(int j = 0; j < 3; j++) {\n\t\t\tint a = curT[j];\n\t\t\tint b = curT[(j + 1) % 3];\n\n\t\t\tif(b > a) { std::swap(a, b); }\n\n\t\t\tstd::pair<int, int> edge(a, b);\n\n\t\t\tauto result = newPoints.find(edge);\n\n\t\t\tint index;\n\n\t\t\tif(result == newPoints.end()) {\n\t\t\t\tindex = curMapIndex++;\n\t\t\t\tnewPoints[edge] = index;\n\t\t\t\tvecBuf[index] = (vecBuf[a] + vecBuf[b]) * 0.5f;\n\t\t\t} else {\n\t\t\t\tindex = newPoints[edge];\n\t\t\t}\n\n\t\t\tnewCenterTriangle[j] = index;\n\t\t}\n\n\t\ttriangleBuf[--newTriIndex] = Triangle{newCenterTriangle[1], newCenterTriangle[0], curT[1]};\n\t\ttriangleBuf[--newTriIndex] = Triangle{newCenterTriangle[2], newCenterTriangle[1], curT[2]};\n\t\ttriangleBuf[--newTriIndex] = Triangle{newCenterTriangle[0], newCenterTriangle[2], curT[0]};\n\t\ttriangleBuf[--newTriIndex] = newCenterTriangle;\n\t}\n\tassert(curMapIndex == newVecBufSize);\n\treturn std::pair<Vec3f*, Triangle*>(vecBuf, triangleBuf);\n}\n\nPolyhedron createSphere(float radius, int steps) {\n\n\tint vertices = 12;\n\tint triangles = 20;\n\n\tfor(int i = 0; i < steps; i++) {\n\t\tvertices = vertices + triangles * 3 / 2;\n\t\ttriangles = triangles * 4;\n\t}\n\n\tPolyhedron curSphere = icosahedron;\n\tVec3f* vecBuf = new Vec3f[vertices];\n\tTriangle* triBuf = new Triangle[triangles];\n\n\tcurSphere.getVertices(vecBuf);\n\tcurSphere.getTriangles(triBuf);\n\n\tvertices = 12;\n\ttriangles = 20;\n\tfor(int i = 0; i < steps; i++) {\n\t\ttesselate(vecBuf, triBuf, vertices, triangles);\n\t\tvertices = vertices + triangles * 3 / 2;\n\t\ttriangles = triangles * 4;\n\t}\n\n\t// size 42 x 80\n\t// size 162 x 320\n\t// size 642 x 1280\n\n\tfor(int i = 0; i < vertices; i++) {\n\t\tvecBuf[i] = normalize(vecBuf[i]) * radius;\n\t}\n\n\tPolyhedron poly(vecBuf, triBuf, vertices, triangles);\n\n\n\n\t//Polyhedron poly(vecBuf, triBuf, 12, 20);\n\n\tdelete[] vecBuf;\n\tdelete[] triBuf;\n\n\treturn poly;\n}\n\nPolyhedron createSpikeBall(float internalRadius, float spikeRadius, int steps, int spikeSteps) {\n\n\tint vertices = 12;\n\tint triangles = 20;\n\n\tfor(int i = 0; i < steps; i++) {\n\t\tvertices = vertices + triangles * 3 / 2;\n\t\ttriangles = triangles * 4;\n\t}\n\n\tPolyhedron curSphere = icosahedron;\n\tVec3f* vecBuf = new Vec3f[vertices];\n\tTriangle* triBuf = new Triangle[triangles];\n\n\tcurSphere.getVertices(vecBuf);\n\tcurSphere.getTriangles(triBuf);\n\n\tvertices = 12;\n\ttriangles = 20;\n\tfor(int i = 0; i < steps; i++) {\n\t\ttesselate(vecBuf, triBuf, vertices, triangles);\n\t\tvertices = vertices + triangles * 3 / 2;\n\t\ttriangles = triangles * 4;\n\t}\n\n\t// size 42 x 80\n\t// size 162 x 320\n\t// size 642 x 1280\n\n\tint spikeVerts = 12;\n\tint spikeTris = 20;\n\tfor(int i = 0; i < spikeSteps; i++) {\n\t\tspikeVerts = spikeVerts + spikeTris * 3 / 2;\n\t\tspikeTris = spikeTris * 4;\n\t}\n\n\tfor(int i = 0; i < spikeVerts; i++) {\n\t\tvecBuf[i] = normalize(vecBuf[i]) * spikeRadius;\n\t}\n\tfor(int i = spikeVerts; i < vertices; i++) {\n\t\tvecBuf[i] = normalize(vecBuf[i]) * internalRadius;\n\t}\n\n\tPolyhedron poly(vecBuf, triBuf, vertices, triangles);\n\n\n\n\t//Polyhedron poly(vecBuf, triBuf, 12, 20);\n\n\tdelete[] vecBuf;\n\tdelete[] triBuf;\n\n\treturn poly;\n}\n\nPolyhedron createTorus(float ringRadius, float radiusOfTube, int radialFidelity, int tubeFidelity) {\n\tEditableMesh result(radialFidelity * tubeFidelity, 2 * radialFidelity * tubeFidelity);\n\n\tfor(int segment = 0; segment < radialFidelity; segment++) {\n\t\tfloat angle = (2 * pi<float>() * segment) / radialFidelity;\n\t\tfloat s = sin(angle);\n\t\tfloat c = cos(angle);\n\n\t\tfor(int partInSegment = 0; partInSegment < tubeFidelity; partInSegment++) {\n\t\t\tfloat tubeAngle = (2 * pi<float>() * partInSegment) / tubeFidelity;\n\n\t\t\tfloat height = radiusOfTube * sin(tubeAngle);\n\t\t\tfloat radius = ringRadius + radiusOfTube * cos(tubeAngle);\n\n\t\t\tresult.setVertex(segment * tubeFidelity + partInSegment, Vec3f(s * radius, c * radius, height));\n\t\t}\n\t}\n\n\t// triangles\n\tfor(int segment = 0; segment < radialFidelity - 1; segment++) {\n\t\tcreateTriangleRing(segment * tubeFidelity, (segment + 1) * tubeFidelity, tubeFidelity, result, 2 * segment * tubeFidelity);\n\t}\n\tcreateTriangleRing((radialFidelity - 1) * tubeFidelity, 0, tubeFidelity, result, 2 * (radialFidelity - 1) * tubeFidelity);\n\n\treturn Polyhedron(std::move(result));\n}\n\nPolyhedron createRevolvedShape(float startZ, Vec2f* inbetweenPoints, int inbetweenPointCount, float endZ, int segmentCount) {\n\tEditableMesh result(segmentCount * inbetweenPointCount + 2, segmentCount * 2 * (inbetweenPointCount));\n\n\tresult.setVertex(0, 0.0f, 0.0f, startZ);\n\tint lastVertex = segmentCount * inbetweenPointCount + 1;\n\tresult.setVertex(lastVertex, 0.0f, 0.0f, endZ);\n\tfor(int segmentI = 0; segmentI < segmentCount; segmentI++) {\n\t\tfloat angle = (2 * pi<float>() * segmentI) / segmentCount;\n\t\tfloat s = sin(angle);\n\t\tfloat c = cos(angle);\n\n\t\tfor(int inbetweenI = 0; inbetweenI < inbetweenPointCount; inbetweenI++) {\n\t\t\tfloat zValue = inbetweenPoints[inbetweenI].x;\n\t\t\tfloat radius = inbetweenPoints[inbetweenI].y;\n\t\t\tresult.setVertex(inbetweenI * segmentCount + segmentI + 1, -s * radius, c * radius, zValue);\n\t\t}\n\t}\n\n\t// triangles\n\tcreateTriangleConeReverse(0, 1, segmentCount, result, 0);\n\tfor(int inbetweenI = 0; inbetweenI < inbetweenPointCount - 1; inbetweenI++) {\n\t\tcreateTriangleRing(1 + segmentCount * inbetweenI, 1 + segmentCount * (inbetweenI + 1), segmentCount, result, segmentCount + 2 * segmentCount * inbetweenI);\n\t}\n\tcreateTriangleCone(lastVertex, 1 + segmentCount * (inbetweenPointCount - 1), segmentCount, result, segmentCount + 2 * segmentCount * (inbetweenPointCount - 1));\n\n\treturn Polyhedron(std::move(result));\n}\n}\n"
  },
  {
    "path": "Physics3D/geometry/shapeLibrary.h",
    "content": "#pragma once\n\n#include \"../geometry/polyhedron.h\"\n\nnamespace P3D::ShapeLibrary {\nextern const Polyhedron tetrahedron;\nextern const Polyhedron octahedron;\nextern const Polyhedron icosahedron;\nextern const Polyhedron trianglePyramid;\nextern const Polyhedron house;\nextern const Polyhedron wedge;\nextern const Polyhedron corner;\nextern Vec3f wedgeVertices[6];\nextern Vec3f cornerVertices[4];\nextern const int wedgeVertexCount;\nextern const int cornerVertexCount;\n\nPolyhedron createBox(float width, float height, float depth);\nPolyhedron createCube(float side);\n\n/*\nCreates a prism oriented along the Z axis with the given number of sides\nresult.vertices will contain all the corners, grouped 2 by 2 rotating counterclockwise as seen from the top\nresult.triangles will contain all the triangles:\n- sides*2 triangles for the sides\n- (sides - 2) triangles for the top cap\n- (sides - 2) triangles for the bottom cap\n\nsides must be >= 3\n*/\nPolyhedron createPrism(int sides, float radius, float height);\n\n\n/*\nCreates a pointed prism oriented along the Y axis with the given number of sides\nresult.vertices will contain all the corners:\n- vertices grouped 2 by 2 rotating counterclockwise as seen from the top\n- top vertex\n- bottom vertex\n\nresult.triangles will contain all the triangles:\n- sides*2 triangles for the sides\n- sides triangles for the top point\n- sides triangles for the bottom point\n\nsides must be >= 3\n*/\nPolyhedron createPointyPrism(int sides, float radius, float height, float topOffset, float bottomOffset);\n\n\nPolyhedron createSphere(float radius, int steps = 1);\nPolyhedron createSpikeBall(float internalRadius, float spikeRadius, int steps, int spikeSteps);\n\n/*\n\tCreates a torus around the z axis. The tube will have a diameter of 2xradiusOfTube\n\tringRadius gives the radius of the centerline of the ring\n\tradialFidelity is the number of segments\n\ttubeFidelity is the number of vertices that make up each segment\n*/\nPolyhedron createTorus(float ringRadius, float radiusOfTube, int radialFidelity, int tubeFidelity);\n\n/*\n\tCreates a swept shape around the z axis, where it meets in two points on the axis. \n\n\tstartZ denotes the starting z-coordinate, a triangle fan will be made starting from this index\n\tendZ denotes the ending z-coordinate\n\n\tinbetweenPoints is a list of length inbetweenPointsCount, which contains the 2D outline to be swept around. \n\tThe x-value denotes the z-position alogn the axis, the y value is the radius at that point\n\n\tsweepFidelity denotes the number of steps of rotation. \n\n\tThe triangles are structured as follows:\n\t[0 .. sweepFidelity-1] is the triangleFan for startZ\n\t[sweepFidelity .. sweepFidelity + 2*(inbetweenPointCount-1)*sweepFidelity-1] are the rings comprising the inbetweenPoints. Each of these rings is 2*sweepFidelity triangles\n\t[sweepFidelity + 2*(inbetweenPointCount-1)*sweepFidelity .. 2*inbetweenPointCount*sweepFidelity - 1] is the triangleFan for endZ\n*/\nPolyhedron createRevolvedShape(float startZ, Vec2f* inbetweenPoints, int inbetweenPointCount, float endZ, int sweepFidelity);\n};\n"
  },
  {
    "path": "Physics3D/geometry/triangleMesh.cpp",
    "content": "#include \"triangleMesh.h\"\n\n#include \"../misc/validityHelper.h\"\n#include \"../misc/cpuid.h\"\n\n#include <cstdio>\n#include <math.h>\n#include <vector>\n#include <set>\n#include <cmath>\n#include <string.h>\n\nnamespace P3D {\n#pragma region bufManagement\nstatic size_t getOffset(size_t size) {\n        return (size + 7) & 0xFFFFFFFFFFFFFFF8;\n \n\n}\nstatic UniqueAlignedPointer<float> createParallelVecBuf(size_t size) {\n\treturn UniqueAlignedPointer<float>(getOffset(size) * 3, 32);\n}\nstatic UniqueAlignedPointer<int> createParallelTriangleBuf(size_t size) {\n\treturn UniqueAlignedPointer<int>(getOffset(size) * 3, 32);\n}\n\ntemplate<typename T>\nstatic UniqueAlignedPointer<T> copy(const UniqueAlignedPointer<T>& buf, size_t size) {\n\tsize_t totalBufSize = getOffset(size) * 3;\n\tUniqueAlignedPointer<T> result(totalBufSize, 32);\n\n\n\tmemcpy(result.get(), buf, sizeof(T) * totalBufSize);\n\n\n\treturn result;\n}\n\ntemplate<typename T>\nstatic void fixFinalBlock(T* buf, size_t size) {\n\t\n\tunsigned int totalValues = getOffset(size) * 3;\n\tunsigned int unusableValues_n = ((getOffset(size) * 3 - size * 3) / 3);\n\t\n\tunsigned int offset = totalValues -  unusableValues_n;\n\n\tT* xValues = buf + offset - 8 * 2;\n\tT* yValues = buf + offset - 8;\n\tT* zValues = buf + offset;\n\n\tunsigned int index = 0;\n\n\tfor(size_t i = index; i < unusableValues_n; i++) {\n\t\txValues[i] = xValues[-1];\n\t\tyValues[i] = yValues[-1];\n        zValues[i] = zValues[-1];\n\t}\n}\n#pragma endregion\n\n#pragma region triangle\nbool Triangle::sharesEdgeWith(Triangle other) const {\n\treturn firstIndex == other.secondIndex && secondIndex == other.firstIndex ||\n\t\tfirstIndex == other.thirdIndex && secondIndex == other.secondIndex ||\n\t\tfirstIndex == other.firstIndex && secondIndex == other.thirdIndex ||\n\n\t\tsecondIndex == other.secondIndex && thirdIndex == other.firstIndex ||\n\t\tsecondIndex == other.thirdIndex && thirdIndex == other.secondIndex ||\n\t\tsecondIndex == other.firstIndex && thirdIndex == other.thirdIndex ||\n\n\t\tthirdIndex == other.secondIndex && firstIndex == other.firstIndex ||\n\t\tthirdIndex == other.thirdIndex && firstIndex == other.secondIndex ||\n\t\tthirdIndex == other.firstIndex && firstIndex == other.thirdIndex;\n}\n\nbool Triangle::operator==(const Triangle& other) const {\n\treturn firstIndex == other.firstIndex && secondIndex == other.secondIndex && thirdIndex == other.thirdIndex ||\n\t\tfirstIndex == other.secondIndex && secondIndex == other.thirdIndex && thirdIndex == other.firstIndex ||\n\t\tfirstIndex == other.thirdIndex && secondIndex == other.firstIndex && thirdIndex == other.secondIndex;\n}\n#pragma endregion\n\n#pragma region MeshPrototype\nMeshPrototype::MeshPrototype(const MeshPrototype& mesh) :\n\tvertices(copy(mesh.vertices, mesh.vertexCount)),\n\ttriangles(copy(mesh.triangles, mesh.triangleCount)),\n\tvertexCount(mesh.vertexCount),\n\ttriangleCount(mesh.triangleCount) {\n\n}\n\nMeshPrototype& MeshPrototype::operator=(const MeshPrototype& mesh) {\n\tthis->vertices = copy(mesh.vertices, mesh.vertexCount);\n\tthis->triangles = copy(mesh.triangles, mesh.triangleCount);\n\tthis->vertexCount = mesh.vertexCount;\n\tthis->triangleCount = mesh.triangleCount;\n\n\treturn *this;\n}\n\nMeshPrototype::MeshPrototype() :\n\tvertices(),\n\ttriangles(),\n\tvertexCount(0),\n\ttriangleCount(0) {}\n\nMeshPrototype::MeshPrototype(int vertexCount, int triangleCount) :\n    vertices(getOffset(vertexCount) * 3, 32),\n\ttriangles(getOffset(triangleCount) * 3, 32),\n\tvertexCount(vertexCount),\n\ttriangleCount(triangleCount) {}\n\nMeshPrototype::MeshPrototype(int vertexCount, int triangleCount, UniqueAlignedPointer<int>&& triangles) :\n\tvertices(getOffset(vertexCount) * 3, 32),\n\ttriangles(std::move(triangles)),\n\tvertexCount(vertexCount),\n\ttriangleCount(triangleCount) {}\n\nMeshPrototype::MeshPrototype(int vertexCount, int triangleCount, UniqueAlignedPointer<float>&& vertices, UniqueAlignedPointer<int>&& triangles) :\n\tvertices(std::move(vertices)),\n\ttriangles(std::move(triangles)),\n\tvertexCount(vertexCount),\n\ttriangleCount(triangleCount) {}\n\nVec3f MeshPrototype::getVertex(int index) const {\n\t// assert(index >= 0 && index < vertexCount);\n\tsize_t currect_index = (index / BLOCK_WIDTH) * BLOCK_WIDTH * 2 + index;\n\treturn Vec3f(this->vertices[currect_index], this->vertices[currect_index + BLOCK_WIDTH], this->vertices[currect_index + BLOCK_WIDTH * 2]);\n}\n\nTriangle MeshPrototype::getTriangle(int index) const {\n\tassert(index >= 0 && index < triangleCount);\n\tsize_t currect_index = (index / BLOCK_WIDTH) * BLOCK_WIDTH * 2 + index;\n\treturn Triangle{triangles[currect_index], triangles[currect_index + BLOCK_WIDTH], triangles[currect_index + BLOCK_WIDTH * 2]};\n}\n#pragma endregion\n\n#pragma region EditableMesh\nEditableMesh::EditableMesh(int vertexCount, int triangleCount) :\n\tMeshPrototype(vertexCount, triangleCount) {}\nEditableMesh::EditableMesh(int vertexCount, int triangleCount, const UniqueAlignedPointer<int>& triangles) :\n\tMeshPrototype(vertexCount, triangleCount, copy(triangles, triangleCount)) {}\nEditableMesh::EditableMesh(int vertexCount, int triangleCount, UniqueAlignedPointer<int>&& triangles) :\n\tMeshPrototype(vertexCount, triangleCount, std::move(triangles)) {}\n\nEditableMesh::EditableMesh(const MeshPrototype& mesh) : MeshPrototype(mesh) {}\nEditableMesh::EditableMesh(MeshPrototype&& mesh) noexcept : MeshPrototype(std::move(mesh)) {}\n\nvoid EditableMesh::setVertex(int index, Vec3f newVertex) {\n\tassert(index >= 0 && index < vertexCount);\n\tsize_t correct_index = (index / BLOCK_WIDTH) * BLOCK_WIDTH * 2 + index;\n\tthis->vertices[correct_index] = newVertex.x;\n\tthis->vertices[correct_index + BLOCK_WIDTH] = newVertex.y;\n\tthis->vertices[correct_index + 2 * BLOCK_WIDTH] = newVertex.z;\n}\nvoid EditableMesh::setVertex(int index, float x, float y, float z) {\n\tassert(index >= 0 && index < vertexCount);\n\tsize_t correct_index = (index / BLOCK_WIDTH) * BLOCK_WIDTH * 2 + index;\n\tthis->vertices[correct_index] = x;\n\tthis->vertices[correct_index + BLOCK_WIDTH] = y;\n\tthis->vertices[correct_index + 2 * BLOCK_WIDTH] = z;\n}\nvoid EditableMesh::setTriangle(int index, Triangle newTriangle) {\n\tassert(index >= 0 && index < triangleCount);\n\tassert(isValidTriangle(newTriangle, vertexCount));\n\n\tsize_t correct_index = (index / BLOCK_WIDTH) * BLOCK_WIDTH * 2 + index;\n\tthis->triangles[correct_index] = newTriangle.firstIndex;\n\tthis->triangles[correct_index + BLOCK_WIDTH] = newTriangle.secondIndex;\n\tthis->triangles[correct_index + 2 * BLOCK_WIDTH] = newTriangle.thirdIndex;\n}\nvoid EditableMesh::setTriangle(int index, int a, int b, int c) {\n\tassert(index >= 0 && index < triangleCount);\n\tassert(isValidTriangle(Triangle{a,b,c}, vertexCount));\n\n\tsize_t correct_index = (index / BLOCK_WIDTH) * BLOCK_WIDTH * 2 + index;\n\tthis->triangles[correct_index] = a;\n\tthis->triangles[correct_index + BLOCK_WIDTH] = b;\n\tthis->triangles[correct_index + 2 * BLOCK_WIDTH] = c;\n}\n#pragma endregion\n\n#pragma region TriangleMesh\nTriangleMesh::TriangleMesh(UniqueAlignedPointer<float>&& vertices, UniqueAlignedPointer<int>&& triangles, int vertexCount, int triangleCount) :\n\tMeshPrototype(vertexCount, triangleCount, std::move(vertices), std::move(triangles)) {\n\tassert(isValid(*this));\n}\n\nTriangleMesh::TriangleMesh(int vertexCount, int triangleCount, const Vec3f* vertices, const Triangle* triangles) :\n\tMeshPrototype(vertexCount, triangleCount) {\n\n    \n\tfloat* xValues = this->vertices.get();\n\tfloat* yValues = xValues + BLOCK_WIDTH;\n\tfloat* zValues = yValues + BLOCK_WIDTH;\n\n\tunsigned int index = 0;\n\tfor(size_t i = 0; i < vertexCount; i++) {\n\t    xValues[index] = vertices[i].x;\n\t    yValues[index] = vertices[i].y;\n\t    zValues[index] = vertices[i].z;\n\t    index++;\n\t\tif((index % BLOCK_WIDTH) == 0)\n\t    \tindex += BLOCK_WIDTH * 2;\n\t    \n\t}\n\n\tif((index % BLOCK_WIDTH) == 0)\n\t\tindex -= BLOCK_WIDTH * 2;\n\n\tunsigned int lastIndex = index - 1;\n\tunsigned int sizeLeft = (getOffset(vertexCount) * 3 - vertexCount * 3) / 3;\n    for(unsigned int i = index; i < index + sizeLeft; i++){\n\t  xValues[i] = xValues[lastIndex];\n\t  yValues[i] = yValues[lastIndex];\n\t  zValues[i] = zValues[lastIndex];\n    }\n\t\n\t\n\t\n\tint* aValues = this->triangles.get();\n\tint* bValues = aValues + BLOCK_WIDTH;\n\tint* cValues = bValues + BLOCK_WIDTH;\n\n\tindex = 0;\n\tfor(size_t i = 0; i < triangleCount; i++) {\n \t\taValues[index] = triangles[i].firstIndex;\n\t\tbValues[index] = triangles[i].secondIndex;\n\t\tcValues[index] = triangles[i].thirdIndex;\n\t\tindex++;\n\t\tif((index % BLOCK_WIDTH) == 0)\n\t\t\tindex += BLOCK_WIDTH * 2;\n    }\n\n\tif((index % BLOCK_WIDTH) == 0)\n\t\tindex -= BLOCK_WIDTH * 2;\n\t\n\tlastIndex = index - 1;\n\tsizeLeft =  (getOffset(triangleCount) * 3 - triangleCount * 3) / 3;\n\t\n\tfor(unsigned int i=index; i < index + sizeLeft; i++){\n\t  aValues[i] = aValues[lastIndex];\n\t  bValues[i] = bValues[lastIndex];\n\t  cValues[i] = cValues[lastIndex];\n\t}\n\t\t\n    \n\tassert(isValid(*this));\n}\n\nTriangleMesh::TriangleMesh(const MeshPrototype& mesh) :\n\tMeshPrototype(mesh) {\n\tfixFinalBlock(this->vertices.get(), vertexCount);\n\tfixFinalBlock(this->triangles.get(), triangleCount);\n\tassert(isValid(*this));\n}\n\nTriangleMesh::TriangleMesh(MeshPrototype&& mesh) noexcept :\n\tMeshPrototype(std::move(mesh)) {\n\tfixFinalBlock(this->vertices.get(), vertexCount);\n\tfixFinalBlock(this->triangles.get(), triangleCount);\n\tassert(isValid(*this));\n}\n\nIteratorFactory<ShapeVertexIter> TriangleMesh::iterVertices() const {\n\n\tunsigned int totalVertices = getOffset(vertexCount) * 3;\n\tunsigned int unusableVertices_n = ((getOffset(vertexCount) * 3 - vertexCount * 3) / 3);\n\tbool isMulOfBlockWidth = (vertexCount % BLOCK_WIDTH == 0);\n  return IteratorFactory<ShapeVertexIter>(ShapeVertexIter{vertices, 0},\n\t\t\t\t\t  ShapeVertexIter{&vertices[totalVertices - unusableVertices_n - BLOCK_WIDTH * 2 + BLOCK_WIDTH * 2 * isMulOfBlockWidth], 0});\n}\nIteratorFactory<ShapeTriangleIter> TriangleMesh::iterTriangles() const {\n\n\tunsigned int totalTriangles = getOffset(triangleCount) * 3;\n\tunsigned int unusableTriangles_n = ((getOffset(triangleCount) * 3 - triangleCount * 3) / 3);\n\tbool isMulOfBlockWidth = (triangleCount % BLOCK_WIDTH == 0);\n  return IteratorFactory<ShapeTriangleIter>(ShapeTriangleIter{triangles, 0},\n\t\t\t\t\t    ShapeTriangleIter{&triangles[totalTriangles - unusableTriangles_n - BLOCK_WIDTH * 2 +\n\t\t\t\t\t\t BLOCK_WIDTH * 2 * isMulOfBlockWidth], 0});\n}\n\nvoid TriangleMesh::getTriangles(Triangle* triangleBuf) const {\n\tsize_t i = 0;\n\tfor(Triangle triangle : iterTriangles()) {\n\t\ttriangleBuf[i++] = triangle;\n\t}\n}\nvoid TriangleMesh::getVertices(Vec3f* vertexBuf) const {\n\tsize_t i = 0;\n\tfor(Vec3f vertex : iterVertices()) {\n\t\tvertexBuf[i++] = vertex;\n\t}\n}\n\n\nTriangleMesh TriangleMesh::translated(Vec3f offset) const {\n\tEditableMesh result(this->vertexCount, this->triangleCount, this->triangles);\n\tfor(int i = 0; i < this->vertexCount; i++) {\n\t\tresult.setVertex(i, this->getVertex(i) + offset);\n\t}\n\treturn TriangleMesh(std::move(result));\n}\n\nTriangleMesh TriangleMesh::rotated(Rotationf rotation) const {\n\tEditableMesh result(this->vertexCount, this->triangleCount, this->triangles);\n\tfor(int i = 0; i < this->vertexCount; i++) {\n\t\tresult.setVertex(i, rotation * this->getVertex(i));\n\t}\n\treturn TriangleMesh(std::move(result));\n}\n\nTriangleMesh TriangleMesh::localToGlobal(CFramef frame) const {\n\tEditableMesh result(this->vertexCount, this->triangleCount, this->triangles);\n\tfor(int i = 0; i < this->vertexCount; i++) {\n\t\tresult.setVertex(i, frame.localToGlobal(this->getVertex(i)));\n\t}\n\treturn TriangleMesh(std::move(result));\n}\n\nTriangleMesh TriangleMesh::globalToLocal(CFramef frame) const {\n\tEditableMesh result(this->vertexCount, this->triangleCount, this->triangles);\n\tfor(int i = 0; i < this->vertexCount; i++) {\n\t\tresult.setVertex(i, frame.globalToLocal(this->getVertex(i)));\n\t}\n\treturn TriangleMesh(std::move(result));\n}\nTriangleMesh TriangleMesh::scaled(float scaleX, float scaleY, float scaleZ) const {\n\tEditableMesh result(this->vertexCount, this->triangleCount, this->triangles);\n\tfor(int i = 0; i < this->vertexCount; i++) {\n\t\tVec3f v = this->getVertex(i);\n\t\tresult.setVertex(i, Vec3f(scaleX * v.x, scaleY * v.y, scaleZ * v.z));\n\t}\n\treturn TriangleMesh(std::move(result));\n}\nTriangleMesh TriangleMesh::scaled(DiagonalMat3f scale) const {\n\treturn scaled(scale[0], scale[1], scale[2]);\n}\n\nTriangleMesh TriangleMesh::translatedAndScaled(Vec3f translation, DiagonalMat3f scale) const {\n\tEditableMesh result(this->vertexCount, this->triangleCount, this->triangles);\n\tfor(int i = 0; i < this->vertexCount; i++) {\n\t\tVec3f cur = this->getVertex(i);\n\t\tresult.setVertex(i, scale * (cur + translation));\n\t}\n\treturn TriangleMesh(std::move(result));\n}\n\n\nVec3f TriangleMesh::getNormalVecOfTriangle(Triangle triangle) const {\n\tVec3f v0 = this->getVertex(triangle.firstIndex);\n\treturn (this->getVertex(triangle.secondIndex) - v0) % (this->getVertex(triangle.thirdIndex) - v0);\n}\n\nvoid TriangleMesh::computeNormals(Vec3f* buffer) const {\n\t// TODO parallelize\n\tfor (Triangle triangle : iterTriangles()) {\n\t\tVec3f v0 = this->getVertex(triangle.firstIndex);\n\t\tVec3f v1 = this->getVertex(triangle.secondIndex);\n\t\tVec3f v2 = this->getVertex(triangle.thirdIndex);\n\n\t\tVec3f D10 = normalize(v1 - v0);\n\t\tVec3f D20 = normalize(v2 - v0);\n\t\tVec3f D21 = normalize(v2 - v1);\n\n\t\tbuffer[triangle.firstIndex] += D10 % D20;\n\t\tbuffer[triangle.secondIndex] += D10 % D21;\n\t\tbuffer[triangle.thirdIndex] += D20 % D21;\n\t}\n\n\tfor (int i = 0; i < vertexCount; i++) {\n\t\tbuffer[i] = normalize(buffer[i]);\n\t}\n}\n\n\nCircumscribingSphere TriangleMesh::getCircumscribingSphere() const {\n\tBoundingBox bounds = getBounds();\n\tVec3 center = bounds.getCenter();\n\tdouble radius = getMaxRadius(center);\n\treturn CircumscribingSphere{center, radius};\n}\n\ndouble TriangleMesh::getMaxRadiusSq() const {\n\tdouble bestDistSq = 0;\n\tfor(Vec3f vertex : iterVertices()) {\n\t\tdouble distSq = lengthSquared(vertex);\n\t\tif(distSq > bestDistSq) {\n\t\t\tbestDistSq = distSq;\n\t\t}\n\t}\n\treturn bestDistSq;\n}\n\ndouble TriangleMesh::getMaxRadiusSq(Vec3f reference) const {\n\tdouble bestDistSq = 0;\n\tfor(Vec3f vertex : iterVertices()) {\n\t\tdouble distSq = lengthSquared(vertex - reference);\n\t\tif(distSq > bestDistSq) {\n\t\t\tbestDistSq = distSq;\n\t\t}\n\t}\n\treturn bestDistSq;\n}\n\ndouble TriangleMesh::getMaxRadius() const {\n\treturn sqrt(getMaxRadiusSq());\n}\n\ndouble TriangleMesh::getMaxRadius(Vec3f reference) const {\n\treturn sqrt(getMaxRadiusSq(reference));\n}\n\n\ndouble TriangleMesh::getScaledMaxRadiusSq(DiagonalMat3 scale) const {\n\tdouble bestDistSq = 0;\n\tfor(Vec3f vertex : iterVertices()) {\n\t\tdouble distSq = lengthSquared(scale * Vec3(vertex));\n\t\tif(distSq > bestDistSq) {\n\t\t\tbestDistSq = distSq;\n\t\t}\n\t}\n\treturn bestDistSq;\n}\ndouble TriangleMesh::getScaledMaxRadius(DiagonalMat3 scale) const {\n\treturn sqrt(getScaledMaxRadiusSq(scale));\n}\n\ndouble TriangleMesh::getIntersectionDistance(const Vec3& origin, const Vec3& direction) const {\n\tconst double EPSILON = 0.0000001;\n\tdouble t = std::numeric_limits<double>::max();\n\tfor(Triangle triangle : iterTriangles()) {\n\t\tVec3 v0 = this->getVertex(triangle.firstIndex);\n\t\tVec3 v1 = this->getVertex(triangle.secondIndex);\n\t\tVec3 v2 = this->getVertex(triangle.thirdIndex);\n\n\t\tVec3 edge1 = v1 - v0;\n\t\tVec3 edge2 = v2 - v0;\n\t\tVec3 h = direction % edge2;\n\n\t\tdouble a = edge1 * h;\n\t\tif(a > -EPSILON && a < EPSILON)\n\t\t\tcontinue;\n\n\t\tVec3 s = origin - v0;\n\t\tdouble f = 1.0 / a;\n\t\tdouble u = f * (s * h);\n\n\t\tif(u < 0.0 || u > 1.0)\n\t\t\tcontinue;\n\n\t\tVec3 q = s % edge1;\n\t\tdouble v = direction * f * q;\n\n\t\tif(v < 0.0 || u + v > 1.0)\n\t\t\tcontinue;\n\n\t\tdouble r = edge2 * f * q;\n\t\tif(r > EPSILON) {\n\t\t\tif(r < t)\n\t\t\t\tt = r;\n\t\t} else {\n\t\t\t//Log::debug(\"Line intersection but not a ray intersection\");\n\t\t\tcontinue;\n\t\t}\n\t}\n\n\treturn t;\n}\n\n\nTriangleMesh stripUnusedVertices(const Vec3f* vertices, const Triangle* triangles, int vertexCount, int triangleCount) {\n\tbool* vertexIsReferenced = new bool[vertexCount];\n\tfor(int i = 0; i < vertexCount; i++) { vertexIsReferenced[i] = false; }\n\tfor(int i = 0; i < triangleCount; i++) {\n\t\tTriangle t = triangles[i];\n\t\tvertexIsReferenced[t.firstIndex] = true;\n\t\tvertexIsReferenced[t.secondIndex] = true;\n\t\tvertexIsReferenced[t.thirdIndex] = true;\n\t}\n\tint totalUnReferencedCount = 0;\n\tfor(int i = 0; i < vertexCount; i++) {\n\t\tif(vertexIsReferenced[i] == false) {\n\t\t\ttotalUnReferencedCount++;\n\t\t}\n\t}\n\tint lastValidVertex = vertexCount - 1;\n\twhile(vertexIsReferenced[lastValidVertex] == false) {\n\t\tlastValidVertex--;\n\t}\n\tstd::vector<std::pair<int, int>> substitutions(totalUnReferencedCount); // substitute first with second in triangles\n\tEditableMesh result(vertexCount - totalUnReferencedCount, triangleCount);\n\t// fix vertices\n\tfor(int i = 0; i <= lastValidVertex; i++) {\n\t\tif(vertexIsReferenced[i] == false) {\n\t\t\tresult.setVertex(i, vertices[lastValidVertex]);\n\t\t\tsubstitutions.push_back(std::make_pair(lastValidVertex, i));\n\t\t\tdo {\n\t\t\t\tlastValidVertex--;\n\t\t\t} while(vertexIsReferenced[lastValidVertex] == false && lastValidVertex > i); // the second condition is for the case that the first n vertices are all invalid, which would make lastValidVertex run off 0\n\t\t} else {\n\t\t\tresult.setVertex(i, vertices[i]);\n\t\t}\n\t}\n\tdelete[] vertexIsReferenced;\n\tfor(int i = 0; i < triangleCount; i++) {\n\t\tTriangle t = triangles[i];\n\t\tfor(std::pair<int, int>& sub : substitutions) {\n\t\t\tif(t.firstIndex == sub.first) t.firstIndex = sub.second;\n\t\t\tif(t.secondIndex == sub.first) t.secondIndex = sub.second;\n\t\t\tif(t.thirdIndex == sub.first) t.thirdIndex = sub.second;\n\t\t}\n\t\tresult.setTriangle(i, t);\n\t}\n\treturn TriangleMesh(std::move(result));\n}\n\nint TriangleMesh::furthestIndexInDirectionFallback(const Vec3f& direction) const {\n\tfloat bestDot = this->getVertex(0) * direction;\n\tint bestVertexIndex = 0;\n\tfor(int i = 1; i < vertexCount; i++) {\n\t\tfloat newD = this->getVertex(i) * direction;\n\t\tif(newD > bestDot) {\n\t\t\tbestDot = newD;\n\t\t\tbestVertexIndex = i;\n\t\t}\n\t}\n\n\treturn bestVertexIndex;\n}\n\nVec3f TriangleMesh::furthestInDirectionFallback(const Vec3f& direction) const {\n\tfloat bestDot = this->getVertex(0) * direction;\n\tVec3f bestVertex = this->getVertex(0);\n\tfor(int i = 1; i < vertexCount; i++) {\n\t\tfloat newD = this->getVertex(i) * direction;\n\t\tif(newD > bestDot) {\n\t\t\tbestDot = newD;\n\t\t\tbestVertex = this->getVertex(i);\n\t\t}\n\t}\n\n\treturn bestVertex;\n}\n\n\nBoundingBox TriangleMesh::getBoundsFallback() const {\n\tdouble xmin = this->getVertex(0).x, xmax = this->getVertex(0).x;\n\tdouble ymin = this->getVertex(0).y, ymax = this->getVertex(0).y;\n\tdouble zmin = this->getVertex(0).z, zmax = this->getVertex(0).z;\n\n\tfor(int i = 1; i < vertexCount; i++) {\n\t\tconst Vec3f current = this->getVertex(i);\n\n\t\tif(current.x < xmin) xmin = current.x;\n\t\tif(current.x > xmax) xmax = current.x;\n\t\tif(current.y < ymin) ymin = current.y;\n\t\tif(current.y > ymax) ymax = current.y;\n\t\tif(current.z < zmin) zmin = current.z;\n\t\tif(current.z > zmax) zmax = current.z;\n\t}\n\n\treturn BoundingBox{xmin, ymin, zmin, xmax, ymax, zmax};\n}\n\nBoundingBox TriangleMesh::getBoundsFallback(const Mat3f& referenceFrame) const {\n\tMat3f transp = referenceFrame.transpose();\n\tdouble xmax = (referenceFrame * this->furthestInDirection(transp * Vec3f(1, 0, 0))).x;\n\tdouble xmin = (referenceFrame * this->furthestInDirection(transp * Vec3f(-1, 0, 0))).x;\n\tdouble ymax = (referenceFrame * this->furthestInDirection(transp * Vec3f(0, 1, 0))).y;\n\tdouble ymin = (referenceFrame * this->furthestInDirection(transp * Vec3f(0, -1, 0))).y;\n\tdouble zmax = (referenceFrame * this->furthestInDirection(transp * Vec3f(0, 0, 1))).z;\n\tdouble zmin = (referenceFrame * this->furthestInDirection(transp * Vec3f(0, 0, -1))).z;\n\n\treturn BoundingBox(xmin, ymin, zmin, xmax, ymax, zmax);\n}\n\nint TriangleMesh::furthestIndexInDirection(const Vec3f& direction) const {\n\tif(CPUIDCheck::hasTechnology(CPUIDCheck::AVX | CPUIDCheck::AVX2 | CPUIDCheck::FMA)) {\n\t\treturn furthestIndexInDirectionAVX(direction);\n\t} else if(CPUIDCheck::hasTechnology(CPUIDCheck::SSE | CPUIDCheck::SSE2)) {\n\t\tif(CPUIDCheck::hasTechnology(CPUIDCheck::SSE4_1)) {\n\t\t\treturn furthestIndexInDirectionSSE4(direction);\n\t\t} else {\n\t\t\treturn furthestIndexInDirectionSSE(direction);\n\t\t}\n\t} else {\n\t\treturn furthestIndexInDirectionFallback(direction);\n\t}\n}\n\nVec3f TriangleMesh::furthestInDirection(const Vec3f& direction) const {\n\tif(CPUIDCheck::hasTechnology(CPUIDCheck::AVX | CPUIDCheck::AVX2 | CPUIDCheck::FMA)) {\n\t\treturn furthestInDirectionAVX(direction);\n\t} else if(CPUIDCheck::hasTechnology(CPUIDCheck::SSE | CPUIDCheck::SSE2)) {\n\t\tif(CPUIDCheck::hasTechnology(CPUIDCheck::SSE4_1)) {\n\t\t\treturn furthestInDirectionSSE4(direction);\n\t\t} else {\n\t\t\treturn furthestInDirectionSSE(direction);\n\t\t}\n\t} else {\n\t\treturn furthestInDirectionFallback(direction);\n\t}\n}\n\nBoundingBox TriangleMesh::getBounds() const {\n\tif(CPUIDCheck::hasTechnology(CPUIDCheck::AVX | CPUIDCheck::AVX2 | CPUIDCheck::FMA)) {\n\t\treturn getBoundsAVX();\n\t} else if(CPUIDCheck::hasTechnology(CPUIDCheck::SSE | CPUIDCheck::SSE2)) {\n\t\treturn getBoundsSSE();\n\t} else {\n\t\treturn getBoundsFallback();\n\t}\n}\n\nBoundingBox TriangleMesh::getBounds(const Mat3f& referenceFrame) const {\n\tif(CPUIDCheck::hasTechnology(CPUIDCheck::AVX | CPUIDCheck::AVX2 | CPUIDCheck::FMA)) {\n\t\treturn getBoundsAVX(referenceFrame);\n\t} else if(CPUIDCheck::hasTechnology(CPUIDCheck::SSE | CPUIDCheck::SSE2)) {\n\t\treturn getBoundsSSE(referenceFrame);\n\t} else {\n\t\treturn getBoundsFallback(referenceFrame);\n\t}\n}\n\n#pragma endregion\n};\n"
  },
  {
    "path": "Physics3D/geometry/triangleMesh.h",
    "content": "#pragma once\n\n#define BLOCK_WIDTH 8\n\n#include \"../math/linalg/vec.h\"\n#include \"../math/cframe.h\"\n#include \"../math/boundingBox.h\"\n#include \"../datastructures/alignedPtr.h\"\n#include \"../datastructures/iteratorFactory.h\"\n#include <stdint.h>\nnamespace P3D {\nstruct Triangle {\n\tunion {\n\t\tstruct {\n\t\t\tint firstIndex, secondIndex, thirdIndex;\n\t\t};\n\t\tint indexes[3];\n\t};\n\n\t[[nodiscard]] bool sharesEdgeWith(Triangle other) const;\n\t[[nodiscard]] Triangle rightShift() const { return Triangle{thirdIndex, firstIndex, secondIndex}; }\n\t[[nodiscard]] Triangle leftShift() const { return Triangle{secondIndex, thirdIndex, firstIndex}; }\n\tTriangle operator~() const { return Triangle{firstIndex, thirdIndex, secondIndex}; }\n\tbool operator==(const Triangle& other) const;\n\tint& operator[](int i) { return indexes[i]; }\n\tconst int& operator[](int i) const { return indexes[i]; }\n};\n  \nstruct ShapeVertexIter {\n\tfloat* curVertex;\n\tsize_t index;\n\tVec3f operator*() const {\n\t\treturn Vec3f{curVertex[index], (curVertex[index + BLOCK_WIDTH]), (curVertex[index + 2 * BLOCK_WIDTH])};\n\t}\n\tvoid operator++() {\n\t  index++;\n\t  if((index % BLOCK_WIDTH) == 0)\n\t  \tindex += BLOCK_WIDTH * 2;\n\t}\n\tbool operator!=(const ShapeVertexIter& other) const {\n\t  // size_t correct_index =  (index/offset)*offset+8*2+index;\n\t  return &curVertex[index] != other.curVertex;\n\t}\n};\n\nstruct ShapeTriangleIter {\n\tint* curTriangle;\n\tsize_t index;\n\tTriangle operator*() const {\n\t  return Triangle{curTriangle[index], (curTriangle[index + BLOCK_WIDTH]), (curTriangle[index + 2 * BLOCK_WIDTH])};\n\t}\n\tvoid operator++() {\n\t  index++;\n\t  if((index % BLOCK_WIDTH) == 0)\n\t  \tindex += BLOCK_WIDTH * 2;\n    }\n\tbool operator!=(const ShapeTriangleIter& other) const {\n\t  //size_t correct_index =  (index/offset)*offset*2+index;\n\t\treturn &curTriangle[index] != other.curTriangle;\n\t}\n\tbool operator==(const ShapeTriangleIter& other) const {\n\t  // size_t correct_index =  (index/offset)*offset*2+index;\n\t  return &curTriangle[index] == other.curTriangle;\n\t}\n};\n\nclass TriangleMesh;\n\nclass MeshPrototype {\nprotected:\n\tUniqueAlignedPointer<float> vertices;\n\tUniqueAlignedPointer<int> triangles;\npublic:\n\tint vertexCount;\n\tint triangleCount;\n\tMeshPrototype();\n\tMeshPrototype(int vertexCount, int triangleCount);\n\tMeshPrototype(int vertexCount, int triangleCount, UniqueAlignedPointer<int>&& triangles);\n\tMeshPrototype(int vertexCount, int triangleCount, UniqueAlignedPointer<float>&& vertices, UniqueAlignedPointer<int>&& triangles);\n\n\tMeshPrototype(const MeshPrototype& mesh);\n\tMeshPrototype& operator=(const MeshPrototype& mesh);\n\tMeshPrototype(MeshPrototype&&) noexcept = default;\n\tMeshPrototype& operator=(MeshPrototype&&) noexcept = default;\n\n\t[[nodiscard]] Vec3f getVertex(int index) const;\n\t[[nodiscard]] Triangle getTriangle(int index) const;\n};\n\nclass EditableMesh : public MeshPrototype {\npublic:\n\tEditableMesh(int vertexCount, int triangleCount);\n\tEditableMesh(int vertexCount, int triangleCount, const UniqueAlignedPointer<int>& triangles);\n\tEditableMesh(int vertexCount, int triangleCount, UniqueAlignedPointer<int>&& triangles);\n\n\texplicit EditableMesh(const MeshPrototype& mesh);\n\texplicit EditableMesh(MeshPrototype&&) noexcept;\n\n\tvoid setVertex(int index, Vec3f vertex);\n\tvoid setVertex(int index, float x, float y, float z);\n\tvoid setTriangle(int index, Triangle triangle);\n\tvoid setTriangle(int index, int a, int b, int c);\n};\n\nclass TriangleMesh : public MeshPrototype {\nprotected:\n\tTriangleMesh(UniqueAlignedPointer<float>&& vertices, UniqueAlignedPointer<int>&& triangles, int vertexCount, int triangleCount);\n\npublic:\n\tTriangleMesh() = default;\n\tTriangleMesh(int vertexCount, int triangleCount, const Vec3f* vertices, const Triangle* triangles);\n\n\t~TriangleMesh() = default;\n\tTriangleMesh(TriangleMesh&&) noexcept = default;\n\tTriangleMesh& operator=(TriangleMesh&&) noexcept = default;\n\tTriangleMesh(const TriangleMesh&) = default;\n\tTriangleMesh& operator=(const TriangleMesh&) = default;\n\n\texplicit TriangleMesh(MeshPrototype&& mesh) noexcept;\n\texplicit TriangleMesh(const MeshPrototype& mesh);\n\n\t[[nodiscard]] IteratorFactory<ShapeVertexIter> iterVertices() const;\n\t[[nodiscard]] IteratorFactory<ShapeTriangleIter> iterTriangles() const;\n\n\tvoid getTriangles(Triangle* triangleBuf) const;\n\tvoid getVertices(Vec3f* vertexBuf) const;\n\n\t[[nodiscard]] TriangleMesh translated(Vec3f offset) const;\n\t[[nodiscard]] TriangleMesh rotated(Rotationf rotation) const;\n\t[[nodiscard]] TriangleMesh localToGlobal(CFramef frame) const;\n\t[[nodiscard]] TriangleMesh globalToLocal(CFramef frame) const;\n\t[[nodiscard]] TriangleMesh scaled(float scaleX, float scaleY, float scaleZ) const;\n\t[[nodiscard]] TriangleMesh scaled(DiagonalMat3f scale) const;\n\t[[nodiscard]] TriangleMesh translatedAndScaled(Vec3f translation, DiagonalMat3f scale) const;\n\n\t[[nodiscard]] Vec3f getNormalVecOfTriangle(Triangle triangle) const;\n\tvoid computeNormals(Vec3f* buffer) const;\n\n\t[[nodiscard]] CircumscribingSphere getCircumscribingSphere() const;\n\t[[nodiscard]] double getMaxRadius() const;\n\t[[nodiscard]] double getMaxRadius(Vec3f reference) const;\n\t[[nodiscard]] double getMaxRadiusSq() const;\n\t[[nodiscard]] double getMaxRadiusSq(Vec3f reference) const;\n\t[[nodiscard]] double getScaledMaxRadius(DiagonalMat3 scale) const;\n\t[[nodiscard]] double getScaledMaxRadiusSq(DiagonalMat3 scale) const;\n\n\n\t[[nodiscard]] BoundingBox getBoundsFallback() const;\n\t[[nodiscard]] BoundingBox getBoundsFallback(const Mat3f& referenceFrame) const;\n\t[[nodiscard]] int furthestIndexInDirectionFallback(const Vec3f& direction) const;\n\t[[nodiscard]] Vec3f furthestInDirectionFallback(const Vec3f& direction) const;\n\n\t[[nodiscard]] BoundingBox getBoundsSSE() const;\n\t[[nodiscard]] BoundingBox getBoundsSSE(const Mat3f& referenceFrame) const;\n\t[[nodiscard]] int furthestIndexInDirectionSSE(const Vec3f& direction) const;\n\t[[nodiscard]] Vec3f furthestInDirectionSSE(const Vec3f& direction) const;\n\n\t[[nodiscard]] int furthestIndexInDirectionSSE4(const Vec3f& direction) const;\n\t[[nodiscard]] Vec3f furthestInDirectionSSE4(const Vec3f& direction) const;\n\n\t[[nodiscard]] BoundingBox getBoundsAVX() const;\n\t[[nodiscard]] BoundingBox getBoundsAVX(const Mat3f& referenceFrame) const;\n\t[[nodiscard]] int furthestIndexInDirectionAVX(const Vec3f& direction) const;\n\t[[nodiscard]] Vec3f furthestInDirectionAVX(const Vec3f& direction) const;\n\n\t[[nodiscard]] BoundingBox getBounds() const;\n\t[[nodiscard]] BoundingBox getBounds(const Mat3f& referenceFrame) const;\n\t[[nodiscard]] int furthestIndexInDirection(const Vec3f& direction) const;\n\t[[nodiscard]] Vec3f furthestInDirection(const Vec3f& direction) const;\n\n\t[[nodiscard]] double getIntersectionDistance(const Vec3& origin, const Vec3& direction) const;\n};\n\nTriangleMesh stripUnusedVertices(const Vec3f* vertices, const Triangle* triangles, int vertexCount, int triangleCount);\n};\n"
  },
  {
    "path": "Physics3D/geometry/triangleMeshAVX.cpp",
    "content": "#include \"triangleMesh.h\"\n#include \"triangleMeshCommon.h\"\n\n#include <immintrin.h>\n\n// AVX2 implementation for TriangleMesh functions\nnamespace P3D {\ninline __m256i _mm256_blendv_epi32(__m256i a, __m256i b, __m256 mask) {\n\treturn _mm256_castps_si256(\n\t\t_mm256_blendv_ps(\n\t\t_mm256_castsi256_ps(a),\n\t\t_mm256_castsi256_ps(b),\n\t\tmask\n\t)\n\t);\n}\n\ninline uint32_t mm256_extract_epi32_var_indx(__m256i vec, int i) {\n\t__m128i indx = _mm_cvtsi32_si128(i);\n\t__m256i val = _mm256_permutevar8x32_epi32(vec, _mm256_castsi128_si256(indx));\n\treturn         _mm_cvtsi128_si32(_mm256_castsi256_si128(val));\n}\n\nint TriangleMesh::furthestIndexInDirectionAVX(const Vec3f& direction) const {\n\tsize_t vertexCount = this->vertexCount;\n\n\t__m256 dx = _mm256_set1_ps(direction.x);\n\t__m256 dy = _mm256_set1_ps(direction.y);\n\t__m256 dz = _mm256_set1_ps(direction.z);\n\n\tsize_t offset = getOffset(vertexCount);\n\tconst float* xValues = this->vertices;\n\tconst float* yValues = this->vertices + 8;\n\tconst float* zValues = this->vertices + 2 * 8;\n\n\t__m256 bestDot = _mm256_fmadd_ps(dz, _mm256_load_ps(zValues), _mm256_fmadd_ps(dy, _mm256_load_ps(yValues), _mm256_mul_ps(dx, _mm256_load_ps(xValues))));\n\n\t__m256i bestIndices = _mm256_set1_epi32(0);\n\n\tfor(size_t blockI = 1; blockI < (vertexCount + 7) / 8; blockI++) {\n\t\t__m256i indices = _mm256_set1_epi32(int(blockI));\n\n\t\t__m256 dot = _mm256_fmadd_ps(dz, _mm256_load_ps(zValues + blockI * 24), _mm256_fmadd_ps(dy, _mm256_load_ps(yValues + blockI * 24), _mm256_mul_ps(dx, _mm256_load_ps(xValues + blockI * 24))));\n\n\t\t__m256 whichAreMax = _mm256_cmp_ps(dot, bestDot, _CMP_GT_OQ); // Greater than, false if dot == NaN\n\t\tbestDot = _mm256_blendv_ps(bestDot, dot, whichAreMax);\n\t\tbestIndices = _mm256_blendv_epi32(bestIndices, indices, whichAreMax); // TODO convert to _mm256_blendv_epi8\n\t}\n\t// find max of our 8 left candidates\n\t__m256 swap4x4 = _mm256_permute2f128_ps(bestDot, bestDot, 1);\n\t__m256 bestDotInternalMax = _mm256_max_ps(bestDot, swap4x4);\n\t__m256 swap2x2 = _mm256_permute_ps(bestDotInternalMax, SWAP_2x2);\n\tbestDotInternalMax = _mm256_max_ps(bestDotInternalMax, swap2x2);\n\t__m256 swap1x1 = _mm256_permute_ps(bestDotInternalMax, SWAP_1x1);\n\tbestDotInternalMax = _mm256_max_ps(bestDotInternalMax, swap1x1);\n\n\t__m256 compare = _mm256_cmp_ps(bestDotInternalMax, bestDot, _CMP_EQ_UQ);\n\tuint32_t mask = _mm256_movemask_ps(compare);\n\n\tassert(mask != 0);\n\n\tuint32_t index = countZeros(mask);\n\tuint32_t block = mm256_extract_epi32_var_indx(bestIndices, index);\n\treturn block * 8 + index;\n}\n\nVec3f TriangleMesh::furthestInDirectionAVX(const Vec3f& direction) const {\n\tsize_t vertexCount = this->vertexCount;\n\n\t__m256 dx = _mm256_set1_ps(direction.x);\n\t__m256 dy = _mm256_set1_ps(direction.y);\n\t__m256 dz = _mm256_set1_ps(direction.z);\n\n\tsize_t offset = getOffset(vertexCount);\n\tconst float* xValues = this->vertices;\n\tconst float* yValues = this->vertices + 8;\n\tconst float* zValues = this->vertices + 16;\n\n\t__m256 bestX = _mm256_load_ps(xValues);\n\t__m256 bestY = _mm256_load_ps(yValues);\n\t__m256 bestZ = _mm256_load_ps(zValues);\n\n\t__m256 bestDot = _mm256_fmadd_ps(dz, bestZ, _mm256_fmadd_ps(dy, bestY, _mm256_mul_ps(dx, bestX)));\n\n\t\n\tfor(size_t blockI = 1; blockI < (vertexCount + 7) / 8; blockI++) {\n\t  //__m256i indices = _mm256_set1_epi32(int(blockI));\n\t  __m256 xVal = _mm256_load_ps(xValues + blockI * 24);\n\t  __m256 yVal = _mm256_load_ps(yValues + blockI * 24);\n\t  __m256 zVal = _mm256_load_ps(zValues + blockI * 24);\n\t  \n\t  __m256 dot = _mm256_fmadd_ps(dz, zVal, _mm256_fmadd_ps(dy, yVal, _mm256_mul_ps(dx, xVal))); \n\t  \n\t  __m256 whichAreMax = _mm256_cmp_ps(bestDot, dot, _CMP_GT_OQ); // Greater than, false if dot == NaN\n\t\n\t  bestDot = _mm256_blendv_ps(dot, bestDot, whichAreMax);\n\t  bestX = _mm256_blendv_ps(xVal, bestX, whichAreMax);\n\t  bestY = _mm256_blendv_ps(yVal, bestY, whichAreMax);\n\t  bestZ = _mm256_blendv_ps(zVal, bestZ, whichAreMax);\n\t \n\t}\n\n\t// now we find the max of the remaining 8 elements\n\t__m256 swap4x4 = _mm256_permute2f128_ps(bestDot, bestDot, 1);\n\t__m256 bestDotInternalMax = _mm256_max_ps(bestDot, swap4x4);\n\t__m256 swap2x2 = _mm256_permute_ps(bestDotInternalMax, SWAP_2x2);\n\tbestDotInternalMax = _mm256_max_ps(bestDotInternalMax, swap2x2);\n\t__m256 swap1x1 = _mm256_permute_ps(bestDotInternalMax, SWAP_1x1);\n\tbestDotInternalMax = _mm256_max_ps(bestDotInternalMax, swap1x1);\n\n\t__m256 compare = _mm256_cmp_ps(bestDotInternalMax, bestDot, _CMP_EQ_UQ);\n\tuint32_t mask = _mm256_movemask_ps(compare);\n\n\tassert(mask != 0);\n\n\tuint32_t index = countZeros(mask);\n\n\t// a bug occurs here, when mask == 0 the resulting index is undefined\n\n\treturn Vec3f(GET_AVX_ELEM(bestX, index), GET_AVX_ELEM(bestY, index), GET_AVX_ELEM(bestZ, index));\n}\n\n// compare the remaining 8 elements\ninline static BoundingBox toBounds(__m256 xMin, __m256 xMax, __m256 yMin, __m256 yMax, __m256 zMin, __m256 zMax) {\n\t// now we compare the remaining 8 elements\n\t__m256 xyMin = _mm256_min_ps(_mm256_permute2f128_ps(xMin, yMin, 0x20), _mm256_permute2f128_ps(xMin, yMin, 0x31));\n\t__m256 xyMax = _mm256_max_ps(_mm256_permute2f128_ps(xMax, yMax, 0x20), _mm256_permute2f128_ps(xMax, yMax, 0x31));\n\tzMin = _mm256_min_ps(zMin, _mm256_permute2f128_ps(zMin, zMin, 1));\n\tzMax = _mm256_max_ps(zMax, _mm256_permute2f128_ps(zMax, zMax, 1));\n\n\txyMin = _mm256_min_ps(xyMin, _mm256_permute_ps(xyMin, SWAP_2x2));\n\txyMax = _mm256_max_ps(xyMax, _mm256_permute_ps(xyMax, SWAP_2x2));\n\n\tzMin = _mm256_min_ps(zMin, _mm256_permute_ps(zMin, SWAP_2x2));\n\tzMax = _mm256_max_ps(zMax, _mm256_permute_ps(zMax, SWAP_2x2));\n\n\n\t__m256 zxzyMin = _mm256_blend_ps(xyMin, zMin, 0b00110011); // stored as xxyyzzzz\n\tzxzyMin = _mm256_min_ps(zxzyMin, _mm256_permute_ps(zxzyMin, SWAP_1x1));\n\n\t__m256 zxzyMax = _mm256_blend_ps(xyMax, zMax, 0b00110011);\n\tzxzyMax = _mm256_max_ps(zxzyMax, _mm256_permute_ps(zxzyMax, SWAP_1x1));\n\t// reg structure zzxxzzyy\n\n\treturn BoundingBox{GET_AVX_ELEM(zxzyMin,2), GET_AVX_ELEM(zxzyMin, 6), GET_AVX_ELEM(zxzyMin, 0), GET_AVX_ELEM(zxzyMax, 2), GET_AVX_ELEM(zxzyMax, 6), GET_AVX_ELEM(zxzyMax, 0)};\n}\n\nBoundingBox TriangleMesh::getBoundsAVX() const {\n\tsize_t vertexCount = this->vertexCount;\n\n\tsize_t offset = getOffset(vertexCount);\n\tconst float* xValues = this->vertices;\n\tconst float* yValues = this->vertices + 8;\n\tconst float* zValues = this->vertices + 2 * 8;\n\n\t__m256 xMax = _mm256_load_ps(xValues);\n\t__m256 xMin = xMax;\n\t__m256 yMax = _mm256_load_ps(yValues);\n\t__m256 yMin = yMax;\n\t__m256 zMax = _mm256_load_ps(zValues);\n\t__m256 zMin = zMax;\n\n\tfor(size_t blockI = 1; blockI < (vertexCount + 7) / 8; blockI++) {\n\n\t\t__m256 xVal = _mm256_load_ps(xValues + blockI * 24);\n\t\t__m256 yVal = _mm256_load_ps(yValues + blockI * 24);\n\t\t__m256 zVal = _mm256_load_ps(zValues + blockI * 24);\n\n\t\txMax = _mm256_max_ps(xMax, xVal);\n\t\tyMax = _mm256_max_ps(yMax, yVal);\n\t\tzMax = _mm256_max_ps(zMax, zVal);\n\n\t\txMin = _mm256_min_ps(xMin, xVal);\n\t\tyMin = _mm256_min_ps(yMin, yVal);\n\t\tzMin = _mm256_min_ps(zMin, zVal);\n\t}\n\n\treturn toBounds(xMin, xMax, yMin, yMax, zMin, zMax);\n}\n\nBoundingBox TriangleMesh::getBoundsAVX(const Mat3f& referenceFrame) const {\n\tsize_t vertexCount = this->vertexCount;\n\n\tsize_t offset = getOffset(vertexCount);\n\tconst float* xValues = this->vertices;\n\tconst float* yValues = this->vertices + 8;\n\tconst float* zValues = this->vertices + 2 * 8;\n\n\tfloat mxx = referenceFrame(0, 0);\n\tfloat mxy = referenceFrame(0, 1);\n\tfloat mxz = referenceFrame(0, 2);\n\tfloat myx = referenceFrame(1, 0);\n\tfloat myy = referenceFrame(1, 1);\n\tfloat myz = referenceFrame(1, 2);\n\tfloat mzx = referenceFrame(2, 0);\n\tfloat mzy = referenceFrame(2, 1);\n\tfloat mzz = referenceFrame(2, 2);\n\n\t__m256 xVal = _mm256_load_ps(xValues);\n\t__m256 yVal = _mm256_load_ps(yValues);\n\t__m256 zVal = _mm256_load_ps(zValues);\n\n\t__m256 xMin = _mm256_fmadd_ps(_mm256_set1_ps(mxz), zVal, _mm256_fmadd_ps(_mm256_set1_ps(mxy), yVal, _mm256_mul_ps(_mm256_set1_ps(mxx), xVal)));\n\t__m256 yMin = _mm256_fmadd_ps(_mm256_set1_ps(myz), zVal, _mm256_fmadd_ps(_mm256_set1_ps(myy), yVal, _mm256_mul_ps(_mm256_set1_ps(myx), xVal)));\n\t__m256 zMin = _mm256_fmadd_ps(_mm256_set1_ps(mzz), zVal, _mm256_fmadd_ps(_mm256_set1_ps(mzy), yVal, _mm256_mul_ps(_mm256_set1_ps(mzx), xVal)));\n\n\t__m256 xMax = xMin;\n\t__m256 yMax = yMin;\n\t__m256 zMax = zMin;\n\n\tfor(size_t blockI = 1; blockI < (vertexCount + 7) / 8; blockI++) {\n\t\t__m256 xVal = _mm256_load_ps(xValues + blockI * 24);\n\t\t__m256 yVal = _mm256_load_ps(yValues + blockI * 24);\n\t\t__m256 zVal = _mm256_load_ps(zValues + blockI * 24);\n\n\t\t__m256 dotX = _mm256_fmadd_ps(_mm256_set1_ps(mxz), zVal, _mm256_fmadd_ps(_mm256_set1_ps(mxy), yVal, _mm256_mul_ps(_mm256_set1_ps(mxx), xVal)));\n\t\txMin = _mm256_min_ps(xMin, dotX);\n\t\txMax = _mm256_max_ps(xMax, dotX);\n\t\t__m256 dotY = _mm256_fmadd_ps(_mm256_set1_ps(myz), zVal, _mm256_fmadd_ps(_mm256_set1_ps(myy), yVal, _mm256_mul_ps(_mm256_set1_ps(myx), xVal)));\n\t\tyMin = _mm256_min_ps(yMin, dotY);\n\t\tyMax = _mm256_max_ps(yMax, dotY);\n\t\t__m256 dotZ = _mm256_fmadd_ps(_mm256_set1_ps(mzz), zVal, _mm256_fmadd_ps(_mm256_set1_ps(mzy), yVal, _mm256_mul_ps(_mm256_set1_ps(mzx), xVal)));\n\t\tzMin = _mm256_min_ps(zMin, dotZ);\n\t\tzMax = _mm256_max_ps(zMax, dotZ);\n\t}\n\n\treturn toBounds(xMin, xMax, yMin, yMax, zMin, zMax);\n}\n};\n"
  },
  {
    "path": "Physics3D/geometry/triangleMeshCommon.h",
    "content": "#pragma once\n\n#include \"triangleMesh.h\"\n#include <immintrin.h>\n\nnamespace P3D {\n#ifdef _MSC_VER\n#define GET_SSE_ELEM(reg, index) reg.m128_f32[index]\n#define GET_SSE_ELEMi(reg, index) reg.m128i_i32[index]\n#define GET_AVX_ELEM(reg, index) reg.m256_f32[index]\n#else\n#define GET_SSE_ELEM(reg, index) reg[index]\n#define GET_AVX_ELEM(reg, index) reg[index]\n\ninline static int mm_extractv_epi32(__m128i a, int b) {\n\talignas(16) int buf[4];\n\t_mm_storeu_si128(reinterpret_cast<__m128i*>(buf), a);\n\treturn buf[b];\n}\n\n#define GET_SSE_ELEMi(reg, index) mm_extractv_epi32(reg, index)\n#endif\n\n#define SWAP_2x2 0b01001110\n#define SWAP_1x1 0b10110001\n\ninline static size_t getOffset(size_t size) {\n\treturn (size + 7) & 0xFFFFFFFFFFFFFFF8;\n}\n\n#ifdef _MSC_VER\ninline static uint32_t countZeros(uint32_t mask) {\n\tunsigned long ret = 0;\n\t_BitScanForward(&ret, mask);\n\treturn static_cast<int>(ret);\n}\n#else\ninline static uint32_t countZeros(uint32_t mask) {\n\treturn __builtin_ctz(mask);\n}\n#endif\n\n\nstatic __m128 custom_fmadd_ps(__m128 a, __m128 b, __m128 c) {\n\treturn  _mm_add_ps(_mm_mul_ps(a, b), c);\n}\n};\n"
  },
  {
    "path": "Physics3D/geometry/triangleMeshSSE.cpp",
    "content": "#include \"triangleMesh.h\"\n#include \"triangleMeshCommon.h\"\n\n#include <immintrin.h>\n\n// SSE2 implementation for TriangleMesh functions\nnamespace P3D {\n\n// used if SSE4_1 is not available, emulates _mm_blendv_ps\nstatic __m128 custom_blendv_ps(__m128 a, __m128 b, __m128 mask) {\n\treturn  _mm_or_ps(_mm_andnot_ps(mask, a), _mm_and_ps(mask, b));\n}\n\n// used if SSE4_1 is not available, emulates _mm_blendv_epi32\nstatic __m128i custom_blendv_epi32(__m128i a, __m128i b, __m128i mask) {\n\treturn _mm_or_si128(_mm_andnot_si128(mask, a), _mm_and_si128(mask, b));\n}\n\nstatic BoundingBox toBounds(__m128 xMin, __m128 xMax, __m128 yMin, __m128 yMax, __m128 zMin, __m128 zMax) {\n\n\tfor(int i = 0; i < 3; i++) {\n\t\t__m128 xShuf = _mm_shuffle_ps(xMax, xMax, 0x93);\n\t\txMax = _mm_max_ps(xMax, xShuf);\n\t}\n\tfor(int i = 0; i < 3; i++) {\n\t\t__m128 yShuf = _mm_shuffle_ps(yMax, yMax, 0x93);\n\t\tyMax = _mm_max_ps(yMax, yShuf);\n\t}\n\tfor(int i = 0; i < 3; i++) {\n\t\t__m128 zShuf = _mm_shuffle_ps(zMax, zMax, 0x93);\n\t\tzMax = _mm_max_ps(zMax, zShuf);\n\t}\n\n\n\tfor(int i = 0; i < 3; i++) {\n\t\t__m128 xShuf = _mm_shuffle_ps(xMin, xMin, 0x93);\n\t\txMin = _mm_min_ps(xMin, xShuf);\n\t}\n\tfor(int i = 0; i < 3; i++) {\n\t\t__m128 yShuf = _mm_shuffle_ps(yMin, yMin, 0x93);\n\t\tyMin = _mm_min_ps(yMin, yShuf);\n\t}\n\tfor(int i = 0; i < 3; i++) {\n\t\t__m128 zShuf = _mm_shuffle_ps(zMin, zMin, 0x93);\n\t\tzMin = _mm_min_ps(zMin, zShuf);\n\t}\n\n\treturn BoundingBox{GET_SSE_ELEM(xMin, 0), GET_SSE_ELEM(yMin, 0), GET_SSE_ELEM(zMin, 0), GET_SSE_ELEM(xMax, 0), GET_SSE_ELEM(yMax, 0), GET_SSE_ELEM(zMax, 0)};\n}\n\nBoundingBox TriangleMesh::getBoundsSSE() const {\n\tsize_t vertexCount = this->vertexCount;\n\n\tsize_t offset = getOffset(vertexCount);\n\tconst float* xValues = this->vertices;\n\n\t__m128 xMax = _mm_load_ps(xValues);\n\t__m128 xMin = xMax;\n\t__m128 yMax = _mm_load_ps(xValues + BLOCK_WIDTH);\n\t__m128 yMin = yMax;\n\t__m128 zMax = _mm_load_ps(xValues + BLOCK_WIDTH * 2);\n\t__m128 zMin = zMax;\n\n\t\n\t\n\t__m128 xVal = _mm_load_ps(xValues + 4);\n\t__m128 yVal = _mm_load_ps(xValues + BLOCK_WIDTH + 4);\n\t__m128 zVal = _mm_load_ps(xValues + BLOCK_WIDTH * 2 + 4);\n\n\txMax = _mm_max_ps(xMax, xVal);\n\tyMax = _mm_max_ps(yMax, yVal);\n\tzMax = _mm_max_ps(zMax, zVal);\n\n\txMin = _mm_min_ps(xMin, xVal);\n\tyMin = _mm_min_ps(yMin, yVal);\n\tzMin = _mm_min_ps(zMin, zVal);\n\t\n\n\n\tconst float *verticesEnd = xValues + offset * 3;\n\n\tfor(const float *verticesPointer = xValues + BLOCK_WIDTH * 3;\n\t \tverticesPointer != verticesEnd;\n\t  \tverticesPointer += BLOCK_WIDTH * 3) {\n\t\t\n\t\n\t\t__m128 xVal = _mm_load_ps(verticesPointer);\n\t\t__m128 yVal = _mm_load_ps(verticesPointer + BLOCK_WIDTH);\n\t\t__m128 zVal = _mm_load_ps(verticesPointer + BLOCK_WIDTH * 2);\n\n\t\txMax = _mm_max_ps(xMax, xVal);\n\t\tyMax = _mm_max_ps(yMax, yVal);\n\t\tzMax = _mm_max_ps(zMax, zVal);\n\n\t\txMin = _mm_min_ps(xMin, xVal);\n\t\tyMin = _mm_min_ps(yMin, yVal);\n\t\tzMin = _mm_min_ps(zMin, zVal);\n\t\n\n\t\txVal = _mm_load_ps(verticesPointer + 4);\n\t\tyVal = _mm_load_ps(verticesPointer + BLOCK_WIDTH + 4);\n\t\tzVal = _mm_load_ps(verticesPointer + BLOCK_WIDTH * 2 + 4);\n\n\t\txMax = _mm_max_ps(xMax, xVal);\n\t\tyMax = _mm_max_ps(yMax, yVal);\n\t\tzMax = _mm_max_ps(zMax, zVal);\n\n\t\txMin = _mm_min_ps(xMin, xVal);\n\t\tyMin = _mm_min_ps(yMin, yVal);\n\t\tzMin = _mm_min_ps(zMin, zVal);\n\t}\n\treturn toBounds(xMin, xMax, yMin, yMax, zMin, zMax);\n}\n\nBoundingBox TriangleMesh::getBoundsSSE(const Mat3f& referenceFrame) const {\n\tsize_t vertexCount = this->vertexCount;\n\n\tsize_t offset = getOffset(vertexCount);\n\tconst float* xValues = this->vertices;\n\n\tfloat mxx = referenceFrame(0, 0);\n\tfloat mxy = referenceFrame(0, 1);\n\tfloat mxz = referenceFrame(0, 2);\n\tfloat myx = referenceFrame(1, 0);\n\tfloat myy = referenceFrame(1, 1);\n\tfloat myz = referenceFrame(1, 2);\n\tfloat mzx = referenceFrame(2, 0);\n\tfloat mzy = referenceFrame(2, 1);\n\tfloat mzz = referenceFrame(2, 2);\n\n\t__m128 xVal = _mm_load_ps(xValues);\n\t__m128 yVal = _mm_load_ps(xValues + BLOCK_WIDTH);\n\t__m128 zVal = _mm_load_ps(xValues + BLOCK_WIDTH * 2);\n\n\t__m128 xMin = custom_fmadd_ps(_mm_set1_ps(mxz), zVal, custom_fmadd_ps(_mm_set1_ps(mxy), yVal, _mm_mul_ps(_mm_set1_ps(mxx), xVal)));\n\t__m128 yMin = custom_fmadd_ps(_mm_set1_ps(myz), zVal, custom_fmadd_ps(_mm_set1_ps(myy), yVal, _mm_mul_ps(_mm_set1_ps(myx), xVal)));\n\t__m128 zMin = custom_fmadd_ps(_mm_set1_ps(mzz), zVal, custom_fmadd_ps(_mm_set1_ps(mzy), yVal, _mm_mul_ps(_mm_set1_ps(mzx), xVal)));\n\n\t__m128 xMax = xMin;\n\t__m128 yMax = yMin;\n\t__m128 zMax = zMin;\n\n\t\t\n\txVal = _mm_load_ps(xValues + 4);\n\tyVal = _mm_load_ps(xValues + BLOCK_WIDTH + 4);\n\tzVal = _mm_load_ps(xValues + BLOCK_WIDTH * 2 + 4);\n\n\t__m128 dotX = custom_fmadd_ps(_mm_set1_ps(mxz), zVal, custom_fmadd_ps(_mm_set1_ps(mxy), yVal, _mm_mul_ps(_mm_set1_ps(mxx), xVal)));\n\txMin = _mm_min_ps(xMin, dotX);\n\txMax = _mm_max_ps(xMax, dotX);\n\t__m128 dotY = custom_fmadd_ps(_mm_set1_ps(myz), zVal, custom_fmadd_ps(_mm_set1_ps(myy), yVal, _mm_mul_ps(_mm_set1_ps(myx), xVal)));\n\tyMin = _mm_min_ps(yMin, dotY);\n\tyMax = _mm_max_ps(yMax, dotY);\n\t__m128 dotZ = custom_fmadd_ps(_mm_set1_ps(mzz), zVal, custom_fmadd_ps(_mm_set1_ps(mzy), yVal, _mm_mul_ps(_mm_set1_ps(mzx), xVal)));\n\tzMin = _mm_min_ps(zMin, dotZ);\n\tzMax = _mm_max_ps(zMax, dotZ);\n\n\n\tconst float *verticesEnd = xValues + offset * 3;\n\n\tfor(const float *verticesPointer = xValues + BLOCK_WIDTH * 3;\n\t \tverticesPointer != verticesEnd;\n\t  \tverticesPointer += BLOCK_WIDTH * 3) {\n\t\t\n\n\t\t__m128 xVal = _mm_load_ps(verticesPointer);\n\t\t__m128 yVal = _mm_load_ps(verticesPointer + BLOCK_WIDTH);\n\t\t__m128 zVal = _mm_load_ps(verticesPointer + BLOCK_WIDTH * 2);\n\n\t\t__m128 dotX = custom_fmadd_ps(_mm_set1_ps(mxz), zVal, custom_fmadd_ps(_mm_set1_ps(mxy), yVal, _mm_mul_ps(_mm_set1_ps(mxx), xVal)));\n\t\txMin = _mm_min_ps(xMin, dotX);\n\t\txMax = _mm_max_ps(xMax, dotX);\n\t\t__m128 dotY = custom_fmadd_ps(_mm_set1_ps(myz), zVal, custom_fmadd_ps(_mm_set1_ps(myy), yVal, _mm_mul_ps(_mm_set1_ps(myx), xVal)));\n\t\tyMin = _mm_min_ps(yMin, dotY);\n\t\tyMax = _mm_max_ps(yMax, dotY);\n\t\t__m128 dotZ = custom_fmadd_ps(_mm_set1_ps(mzz), zVal, custom_fmadd_ps(_mm_set1_ps(mzy), yVal, _mm_mul_ps(_mm_set1_ps(mzx), xVal)));\n\t\tzMin = _mm_min_ps(zMin, dotZ);\n\t\tzMax = _mm_max_ps(zMax, dotZ);\n\n\n\n\t\txVal = _mm_load_ps(verticesPointer + 4);\n\t\tyVal = _mm_load_ps(verticesPointer + BLOCK_WIDTH + 4);\n\t\tzVal = _mm_load_ps(verticesPointer + BLOCK_WIDTH * 2 + 4);\n\n\t\tdotX = custom_fmadd_ps(_mm_set1_ps(mxz), zVal, custom_fmadd_ps(_mm_set1_ps(mxy), yVal, _mm_mul_ps(_mm_set1_ps(mxx), xVal)));\n\t\txMin = _mm_min_ps(xMin, dotX);\n\t\txMax = _mm_max_ps(xMax, dotX);\n\t\tdotY = custom_fmadd_ps(_mm_set1_ps(myz), zVal, custom_fmadd_ps(_mm_set1_ps(myy), yVal, _mm_mul_ps(_mm_set1_ps(myx), xVal)));\n\t\tyMin = _mm_min_ps(yMin, dotY);\n\t\tyMax = _mm_max_ps(yMax, dotY);\n\t\tdotZ = custom_fmadd_ps(_mm_set1_ps(mzz), zVal, custom_fmadd_ps(_mm_set1_ps(mzy), yVal, _mm_mul_ps(_mm_set1_ps(mzx), xVal)));\n\t\tzMin = _mm_min_ps(zMin, dotZ);\n\t\tzMax = _mm_max_ps(zMax, dotZ);\n\t}\n\n\treturn toBounds(xMin, xMax, yMin, yMax, zMin, zMax);\n}\n\nint TriangleMesh::furthestIndexInDirectionSSE(const Vec3f& direction) const {\n\tsize_t vertexCount = this->vertexCount;\n\n\t__m128 dx = _mm_set1_ps(direction.x);\n\t__m128 dy = _mm_set1_ps(direction.y);\n\t__m128 dz = _mm_set1_ps(direction.z);\n\n\tsize_t offset = getOffset(vertexCount);\n\n\tconst float* xValues = this->vertices;\n\t\n\t__m128 bestDot = custom_fmadd_ps(dz, _mm_load_ps(xValues + BLOCK_WIDTH * 2), custom_fmadd_ps(dy, _mm_load_ps(xValues + BLOCK_WIDTH), _mm_mul_ps(dx, _mm_load_ps(xValues))));\n\n\t__m128i bestIndices = _mm_set1_epi32(0);\n\n\tunsigned int blockI = 1;\n\t\n\t__m128i indices = _mm_set1_epi32(static_cast<int>(blockI));\n\n\t__m128 dot = custom_fmadd_ps(dz, _mm_load_ps(xValues + BLOCK_WIDTH * 2 + 4), custom_fmadd_ps(dy, _mm_load_ps(xValues + BLOCK_WIDTH + 4), _mm_mul_ps(dx, _mm_load_ps(xValues + 4))));\n\n\t\t//Compare greater than, returns false if either operand is NaN.\n\t__m128 whichAreMax = _mm_cmpgt_ps(dot, bestDot);\n\n\tbestDot = custom_blendv_ps(bestDot, dot, whichAreMax);\n\tbestIndices = custom_blendv_epi32(bestIndices, indices, _mm_castps_si128(whichAreMax));\n\n\tblockI++;\n\n\n\n\tconst float *verticesEnd = xValues + offset * 3;\n\t\n\tfor(const float *verticesPointer = xValues + BLOCK_WIDTH * 3;\n\t \tverticesPointer != verticesEnd;\n\t  \tverticesPointer += BLOCK_WIDTH * 3) {\n\n\n\t\t__m128i indices = _mm_set1_epi32(static_cast<int>(blockI));\n\n\t\t__m128 dot = custom_fmadd_ps(dz, _mm_load_ps(verticesPointer + BLOCK_WIDTH * 2), custom_fmadd_ps(dy, _mm_load_ps(verticesPointer + BLOCK_WIDTH), _mm_mul_ps(dx, _mm_load_ps(verticesPointer))));\n\n\t\t//Compare greater than, returns false if either operand is NaN.\n\t\t__m128 whichAreMax = _mm_cmpgt_ps(dot, bestDot);\n\n\t\tbestDot = custom_blendv_ps(bestDot, dot, whichAreMax);\n\t\tbestIndices = custom_blendv_epi32(bestIndices, indices, _mm_castps_si128(whichAreMax));\n\n\t\tblockI++;\n\n\n\t\tindices = _mm_set1_epi32(static_cast<int>(blockI));\n\n\t\tdot = custom_fmadd_ps(dz, _mm_load_ps(verticesPointer + BLOCK_WIDTH * 2 + 4), custom_fmadd_ps(dy, _mm_load_ps(verticesPointer + BLOCK_WIDTH + 4), _mm_mul_ps(dx, _mm_load_ps(verticesPointer + 4))));\n\n\t\t//Compare greater than, returns false if either operand is NaN.\n\t\twhichAreMax = _mm_cmpgt_ps(dot, bestDot);\n\n\t\tbestDot = custom_blendv_ps(bestDot, dot, whichAreMax);\n\t\tbestIndices = custom_blendv_epi32(bestIndices, indices, _mm_castps_si128(whichAreMax));\n\n\t\tblockI++;\n\n\t}\n\t__m128 swap4x4 = _mm_shuffle_ps(bestDot, bestDot, 1);\n\t__m128 bestDotInternalMax = _mm_max_ps(bestDot, swap4x4);\n\t__m128 swap2x2 = _mm_shuffle_ps(bestDotInternalMax, bestDotInternalMax, SWAP_2x2);\n\tbestDotInternalMax = _mm_max_ps(bestDotInternalMax, swap2x2);\n\t__m128 swap1x1 = _mm_shuffle_ps(bestDotInternalMax, bestDotInternalMax, SWAP_1x1);\n\tbestDotInternalMax = _mm_max_ps(bestDotInternalMax, swap1x1);\n\n\t//Compare equality, returns true if either operand is NaN.\n\t__m128 compare = _mm_cmpeq_ps(bestDotInternalMax, bestDot);\n\tcompare = _mm_cmpunord_ps(compare, compare);\n\n\tuint32_t mask = _mm_movemask_ps(compare);\n\tassert(mask != 0);\n\tuint32_t index = countZeros(mask);\n\tauto block = GET_SSE_ELEMi(bestIndices, index);\n\treturn block * 4 + index;\n}\n\nVec3f TriangleMesh::furthestInDirectionSSE(const Vec3f& direction) const {\n\tsize_t vertexCount = this->vertexCount;\n\n\t__m128 dx = _mm_set1_ps(direction.x);\n\t__m128 dy = _mm_set1_ps(direction.y);\n\t__m128 dz = _mm_set1_ps(direction.z);\n\n\tsize_t offset = getOffset(vertexCount);\n\tconst float* xValues = this->vertices;\n\t__m128 bestX1 = _mm_load_ps(xValues);\n\t__m128 bestY1 = _mm_load_ps(xValues + BLOCK_WIDTH);\n\t__m128 bestZ1 = _mm_load_ps(xValues + BLOCK_WIDTH * 2);\n\n\t__m128 bestX2 = bestX1;\n\t__m128 bestY2 = bestY1;\n\t__m128 bestZ2 = bestZ1;\n\n\t__m128 bestDot1 = custom_fmadd_ps(dz, bestZ1, custom_fmadd_ps(dy, bestY1, _mm_mul_ps(dx, bestX1)));\n\n\t__m128 bestDot2 = bestDot1;\n\n\n\n\t__m128 xVal1 = _mm_load_ps(xValues + 4);\n\t__m128 yVal1 = _mm_load_ps(xValues + BLOCK_WIDTH + 4);\n\t__m128 zVal1 = _mm_load_ps(xValues + BLOCK_WIDTH * 2 + 4);\n\n\t__m128 xVal2 = xVal1;\n\t__m128 yVal2 = yVal1;\n\t__m128 zVal2 = zVal1;\n\n\t__m128 dot1 = custom_fmadd_ps(dz, zVal1, custom_fmadd_ps(dy, yVal1, _mm_mul_ps(dx, xVal1)));\n\n\t__m128 dot2 = dot1;\n\n\t\t//Compare greater than, returns false if either operand is NaN.\n\t__m128 whichAreMax1 = _mm_cmpgt_ps(dot1, bestDot1);\n\n\t\t//Compare greater than, returns false if either operand is NaN.\n\t__m128 whichAreMax2 = whichAreMax1;\n\n\tbestDot1 = custom_blendv_ps(bestDot1, dot1, whichAreMax1);\n\tbestX1 = custom_blendv_ps(bestX1, xVal1, whichAreMax1);\n\tbestY1 = custom_blendv_ps(bestY1, yVal1, whichAreMax1);\n\tbestZ1 = custom_blendv_ps(bestZ1, zVal1, whichAreMax1);\n\n\n\tconst float *verteciesEnd = xValues + offset * 3;\n\n\tfor(const float *verticesPointer = xValues + BLOCK_WIDTH * 3;\n\t\tverticesPointer != verteciesEnd;\n\t\tverticesPointer += BLOCK_WIDTH * 3) {\n\t\t//__m128i indices = _mm_set1_epi32(static_cast<int>(blockI));\n\n\t\txVal1 = _mm_load_ps(verticesPointer);\n\t\tyVal1 = _mm_load_ps(verticesPointer + BLOCK_WIDTH);\n\t\tzVal1 = _mm_load_ps(verticesPointer + BLOCK_WIDTH * 2);\n\n\t\txVal2 = _mm_load_ps(verticesPointer + 4);\n\t\tyVal2 = _mm_load_ps(verticesPointer + BLOCK_WIDTH + 4);\n\t\tzVal2 = _mm_load_ps(verticesPointer + BLOCK_WIDTH * 2 + 4);\n\n\n\t\tdot1 = custom_fmadd_ps(dz, zVal1, custom_fmadd_ps(dy, yVal1, _mm_mul_ps(dx, xVal1)));\n\n\t\tdot2 = custom_fmadd_ps(dz, zVal2, custom_fmadd_ps(dy, yVal2, _mm_mul_ps(dx, xVal2)));\n\n\t\t//Compare greater than, returns false if either operand is NaN.\n\t\twhichAreMax1 = _mm_cmpgt_ps(bestDot1, dot1);\n\t\twhichAreMax2 = _mm_cmpgt_ps(bestDot2, dot2);\n\n\t\tbestDot1 = custom_blendv_ps(dot1, bestDot1, whichAreMax1);\n\t\tbestDot2 = custom_blendv_ps(dot2, bestDot2, whichAreMax2);\n\t\tbestX1 = custom_blendv_ps(xVal1, bestX1, whichAreMax1);\n\t\tbestX2 = custom_blendv_ps(xVal2, bestX2, whichAreMax2);\n\t\tbestY1 = custom_blendv_ps(yVal1, bestY1, whichAreMax1);\n\t\tbestY2 = custom_blendv_ps(yVal2, bestY2, whichAreMax2);\n\t\tbestZ1 = custom_blendv_ps(zVal1, bestZ1, whichAreMax1);\n\t\tbestZ2 = custom_blendv_ps(zVal2, bestZ2, whichAreMax2);\n\n\n\n\t}\n\n\t\t\t//Compare greater than, returns false if either operand is NaN.\n\t\t__m128 whichAreMax = _mm_cmpgt_ps(bestDot1, bestDot2);\n\n\t\t__m128 bestDot = custom_blendv_ps(bestDot2, bestDot1, whichAreMax);\n\t\t__m128 bestX = custom_blendv_ps(bestX2, bestX1, whichAreMax);\n\t\t__m128 bestY = custom_blendv_ps(bestY2, bestY1, whichAreMax);\n\t\t__m128 bestZ = custom_blendv_ps(bestZ2, bestZ1, whichAreMax);\n\n\n\t__m128 swap4x4 = _mm_shuffle_ps(bestDot, bestDot, 1);\n\t__m128 bestDotInternalMax = _mm_max_ps(bestDot, swap4x4);\n\t__m128 swap2x2 = _mm_shuffle_ps(bestDotInternalMax, bestDotInternalMax, SWAP_2x2);\n\tbestDotInternalMax = _mm_max_ps(bestDotInternalMax, swap2x2);\n\t__m128 swap1x1 = _mm_shuffle_ps(bestDotInternalMax, bestDotInternalMax, SWAP_1x1);\n\tbestDotInternalMax = _mm_max_ps(bestDotInternalMax, swap1x1);\n\n\t//Compare equality, return true if either operand is NaN.\n\t__m128 compare = _mm_cmpeq_ps(bestDotInternalMax, bestDot);\n\tcompare = _mm_cmpunord_ps(compare, compare);\n\n\tuint32_t mask = _mm_movemask_ps(compare);\n\tassert(mask != 0);\n\tuint32_t index = countZeros(mask);\n\treturn Vec3f(GET_SSE_ELEM(bestX, index), GET_SSE_ELEM(bestY, index), GET_SSE_ELEM(bestZ, index));\n}\n\n};"
  },
  {
    "path": "Physics3D/geometry/triangleMeshSSE4.cpp",
    "content": "#include \"triangleMesh.h\"\n#include \"triangleMeshCommon.h\"\n\n#include <immintrin.h>\n\n// SSE2 implementation for TriangleMesh functions\nnamespace P3D {\n// SSE4-specific implementation, the _mm_blendv_ps instruction was the bottleneck\n\nint TriangleMesh::furthestIndexInDirectionSSE4(const Vec3f& direction) const {\n\tsize_t vertexCount = this->vertexCount;\n\n\t__m128 dx = _mm_set1_ps(direction.x);\n\t__m128 dy = _mm_set1_ps(direction.y);\n\t__m128 dz = _mm_set1_ps(direction.z);\n\n\tsize_t offset = getOffset(vertexCount);\n\n\tconst float* xValues = this->vertices;\n\n\t__m128 bestDot = custom_fmadd_ps(dz, _mm_load_ps(xValues + BLOCK_WIDTH * 2), custom_fmadd_ps(dy, _mm_load_ps(xValues + BLOCK_WIDTH), _mm_mul_ps(dx, _mm_load_ps(xValues))));\n\n\t__m128i bestIndices = _mm_set1_epi32(0);\n\n\n\tunsigned int blockI = 1;\n\n\n\t__m128i indices = _mm_set1_epi32(static_cast<int>(blockI));\n\n\t__m128 dot = custom_fmadd_ps(dz, _mm_load_ps(xValues + BLOCK_WIDTH * 2 + 4), custom_fmadd_ps(dy, _mm_load_ps(xValues + BLOCK_WIDTH + 4), _mm_mul_ps(dx, _mm_load_ps(xValues + 4))));\n\n\t//Compare greater than, returns false if either operand is NaN.\n\t__m128 whichAreMax = _mm_cmpgt_ps(dot, bestDot);\n\n\tbestDot = _mm_blendv_ps(bestDot, dot, whichAreMax);\n\tbestIndices = _mm_blendv_epi8(bestIndices, indices, _mm_castps_si128(whichAreMax));\n\t\n\tblockI++;\n\n\n\n\tconst float *verticesEnd = xValues + offset * 3;\n\n\tfor(const float *verticesPointer = xValues + BLOCK_WIDTH * 3;\n\t \tverticesPointer != verticesEnd;\n\t  \tverticesPointer += BLOCK_WIDTH * 3) {\n\t\t__m128i indices = _mm_set1_epi32(static_cast<int>(blockI));\n\n\t\t__m128 dot = custom_fmadd_ps(dz, _mm_load_ps(verticesPointer + BLOCK_WIDTH * 2), custom_fmadd_ps(dy, _mm_load_ps(verticesPointer + BLOCK_WIDTH), _mm_mul_ps(dx, _mm_load_ps(verticesPointer))));\n\n\t\t//Compare greater than, returns false if either operand is NaN.\n\t\t__m128 whichAreMax = _mm_cmpgt_ps(dot, bestDot);\n\n\t\tbestDot = _mm_blendv_ps(bestDot, dot, whichAreMax);\n\t\tbestIndices = _mm_blendv_epi8(bestIndices, indices, _mm_castps_si128(whichAreMax));\n\t\n\t\tblockI++;\n\n\n\t\tindices = _mm_set1_epi32(static_cast<int>(blockI));\n\n\t\tdot = custom_fmadd_ps(dz, _mm_load_ps(verticesPointer + BLOCK_WIDTH * 2 + 4), custom_fmadd_ps(dy, _mm_load_ps(verticesPointer + BLOCK_WIDTH + 4), _mm_mul_ps(dx, _mm_load_ps(verticesPointer + 4))));\n\n\t\t//Compare greater than, returns false if either operand is NaN.\n\t\twhichAreMax = _mm_cmpgt_ps(dot, bestDot);\n\n\t\tbestDot = _mm_blendv_ps(bestDot, dot, whichAreMax);\n\t\tbestIndices = _mm_blendv_epi8(bestIndices, indices, _mm_castps_si128(whichAreMax));\n\t\n\t\tblockI++;\n\n\n\t\t\n\t}\n\t__m128 swap4x4 = _mm_shuffle_ps(bestDot, bestDot, 1);\n\t__m128 bestDotInternalMax = _mm_max_ps(bestDot, swap4x4);\n\t__m128 swap2x2 = _mm_shuffle_ps(bestDotInternalMax, bestDotInternalMax, SWAP_2x2);\n\tbestDotInternalMax = _mm_max_ps(bestDotInternalMax, swap2x2);\n\t__m128 swap1x1 = _mm_shuffle_ps(bestDotInternalMax, bestDotInternalMax, SWAP_1x1);\n\tbestDotInternalMax = _mm_max_ps(bestDotInternalMax, swap1x1);\n\n\t//Compare equality, returns true if either operand is NaN.\n\t__m128 compare = _mm_cmpeq_ps(bestDotInternalMax, bestDot);\n\tcompare = _mm_cmpunord_ps(compare, compare);\n\n\tuint32_t mask = _mm_movemask_ps(compare);\n\tassert(mask != 0);\n\tuint32_t index = countZeros(mask);\n\tauto block = GET_SSE_ELEMi(bestIndices, index);\n\treturn block * 4 + index;\n}\n\nVec3f TriangleMesh::furthestInDirectionSSE4(const Vec3f& direction) const {\n\tsize_t vertexCount = this->vertexCount;\n\n\t__m128 dx = _mm_set1_ps(direction.x);\n\t__m128 dy = _mm_set1_ps(direction.y);\n\t__m128 dz = _mm_set1_ps(direction.z);\n\n\tsize_t offset = getOffset(vertexCount);\n\tconst float* xValues = this->vertices;\n\n\t__m128 bestX1 = _mm_load_ps(xValues);\n\t__m128 bestY1 = _mm_load_ps(xValues + BLOCK_WIDTH);\n\t__m128 bestZ1 = _mm_load_ps(xValues + BLOCK_WIDTH * 2);\n\n\t__m128 bestX2 = bestX1;\n\t__m128 bestY2 = bestY1;\n\t__m128 bestZ2 = bestZ1;\n\n\t__m128 bestDot1 = custom_fmadd_ps(dz, bestZ1, custom_fmadd_ps(dy, bestY1, _mm_mul_ps(dx, bestX1)));\n\n\t__m128 bestDot2 = bestDot1;\n\n\t__m128 xVal1 = _mm_load_ps(xValues + 4);\n\t__m128 yVal1 = _mm_load_ps(xValues + BLOCK_WIDTH + 4);\n\t__m128 zVal1 = _mm_load_ps(xValues + BLOCK_WIDTH * 2 + 4);\n\n\t__m128 dot1 = custom_fmadd_ps(dz, zVal1, custom_fmadd_ps(dy, yVal1, _mm_mul_ps(dx, xVal1)));\n\n\t__m128 dot2 = dot1;\n\n\t//Compare greater than, returns false if either operand is NaN.\n\t__m128 whichAreMax1 = _mm_cmpgt_ps(bestDot1, dot1);\n\n\t//Compare greater than, returns false if either operand is NaN.\n\t__m128 whichAreMax2 = whichAreMax1;\n\n\tbestDot1 = _mm_blendv_ps(dot1, bestDot1, whichAreMax1);\n\tbestX1 = _mm_blendv_ps(xVal1, bestX1, whichAreMax1);\n\tbestY1 = _mm_blendv_ps(yVal1, bestY1, whichAreMax1);\n\tbestZ1 = _mm_blendv_ps(zVal1, bestZ1, whichAreMax1); \n\t\n\n\tconst float *verticesEnd = xValues + offset * 3;\n\n\tfor(const float *verticesPointer = xValues + BLOCK_WIDTH * 3;\n\t \tverticesPointer != verticesEnd;\n\t  \tverticesPointer += BLOCK_WIDTH * 3) {\n\t\t//__m128i indices = _mm_set1_epi32(static_cast<int>(blockI));\n\n\t\t__m128 xVal1 = _mm_load_ps(verticesPointer);\n\t\t__m128 yVal1 = _mm_load_ps(verticesPointer + BLOCK_WIDTH);\n\t\t__m128 zVal1 = _mm_load_ps(verticesPointer + BLOCK_WIDTH * 2);\n\n\t\t__m128 xVal2 = _mm_load_ps(verticesPointer + 4);\n\t\t__m128 yVal2 = _mm_load_ps(verticesPointer + BLOCK_WIDTH + 4);\n\t\t__m128 zVal2 = _mm_load_ps(verticesPointer + BLOCK_WIDTH * 2 + 4);\n\n\n\t\tdot1 = custom_fmadd_ps(dz, zVal1, custom_fmadd_ps(dy, yVal1, _mm_mul_ps(dx, xVal1)));\n\t\tdot2 = custom_fmadd_ps(dz, zVal2, custom_fmadd_ps(dy, yVal2, _mm_mul_ps(dx, xVal2)));\n\t\n\t\t//Compare greater than, returns false if either operand is NaN.\n\t\twhichAreMax1 = _mm_cmpgt_ps(bestDot1, dot1);\n\t\t//Compare greater than, returns false if either operand is NaN.\n\t\twhichAreMax2 = _mm_cmpgt_ps(bestDot2, dot2);\n\n\n\t\tbestDot1 = _mm_blendv_ps(dot1, bestDot1, whichAreMax1);\n\t\tbestDot2 = _mm_blendv_ps(dot2, bestDot2, whichAreMax2);\n\t\tbestX1 = _mm_blendv_ps(xVal1, bestX1, whichAreMax1);\n\t\tbestX2 = _mm_blendv_ps(xVal2, bestX2, whichAreMax2);\n\t\tbestY1 = _mm_blendv_ps(yVal1, bestY1, whichAreMax1);\n\t\tbestY2 = _mm_blendv_ps(yVal2, bestY2, whichAreMax2);\n\t\tbestZ1 = _mm_blendv_ps(zVal1, bestZ1, whichAreMax1);\n\t\tbestZ2 = _mm_blendv_ps(zVal2, bestZ2, whichAreMax2);\n\t\n\t\n\t}\n\n\t\t//Compare greater than, returns false if either operand is NaN.\n\t\t__m128 whichAreMax = _mm_cmpgt_ps(bestDot1, bestDot2);\n\n\n\t\t__m128 bestDot = _mm_blendv_ps(bestDot2, bestDot1, whichAreMax);\n\t\t__m128 bestX = _mm_blendv_ps(bestX2, bestX1, whichAreMax);\n\t\t__m128 bestY = _mm_blendv_ps(bestY2, bestY1, whichAreMax);\n\t\t__m128 bestZ = _mm_blendv_ps(bestZ2, bestZ1, whichAreMax);\n\t\t\n\n\t__m128 swap4x4 = _mm_shuffle_ps(bestDot, bestDot, 1);\n\t__m128 bestDotInternalMax = _mm_max_ps(bestDot, swap4x4);\n\t__m128 swap2x2 = _mm_shuffle_ps(bestDotInternalMax, bestDotInternalMax, SWAP_2x2);\n\tbestDotInternalMax = _mm_max_ps(bestDotInternalMax, swap2x2);\n\t__m128 swap1x1 = _mm_shuffle_ps(bestDotInternalMax, bestDotInternalMax, SWAP_1x1);\n\tbestDotInternalMax = _mm_max_ps(bestDotInternalMax, swap1x1);\n\n\t//Compare equality, return true if either operand is NaN.\n\t__m128 compare = _mm_cmpeq_ps(bestDotInternalMax, bestDot);\n\tcompare = _mm_cmpunord_ps(compare, compare);\n\n\tuint32_t mask = _mm_movemask_ps(compare);\n\tassert(mask != 0);\n\tuint32_t index = countZeros(mask);\n\treturn Vec3f(GET_SSE_ELEM(bestX, index), GET_SSE_ELEM(bestY, index), GET_SSE_ELEM(bestZ, index));\n}\n};"
  },
  {
    "path": "Physics3D/hardconstraints/constraintTemplates.h",
    "content": "#pragma once\n\n#include \"hardConstraint.h\"\n\n/*\n\tRequires a SpeedController argument, this object must provide the following methods:\n\n\tvoid update(double deltaT);\n\tdouble getValue() const;  // returns the current speed of the motor\n\tFullTaylor<double> getFullTaylorExpansion() const; // returns the current speed and it's derivatives, being acceleration, jerk etc\n*/\nnamespace P3D {\ntemplate<typename SpeedController>\nclass MotorConstraintTemplate : public HardConstraint, public SpeedController {\npublic:\n\tusing SpeedController::SpeedController;\n\n\tvirtual void update(double deltaT) override { SpeedController::update(deltaT); }\n\n\tvirtual CFrame getRelativeCFrame() const override {\n\t\treturn CFrame(Rotation::rotZ(SpeedController::getValue()));\n\t}\n\tvirtual RelativeMotion getRelativeMotion() const override {\n\t\tFullTaylor<double> speedDerivatives = SpeedController::getFullTaylorExpansion();\n\t\tRotationalMotion rotationMotion(speedDerivatives.getDerivatives().transform([](double v) {return Vec3(0, 0, v); }));\n\t\treturn RelativeMotion(Motion(TranslationalMotion(), rotationMotion), CFrame(Rotation::rotZ(speedDerivatives.getConstantValue())));\n\t}\n\n\tvirtual ~MotorConstraintTemplate() override {}\n};\n\n/*\n\tRequires a LengthController argument, this object must provide the following methods:\n\n\tvoid update(double deltaT);\n\tdouble getValue() const; // The current length of the piston\n\tFullTaylor<double> getFullTaylorExpansion() const; // The current length and its derivatives of the piston\n*/\ntemplate<typename LengthController>\nclass PistonConstraintTemplate : public HardConstraint, public LengthController {\npublic:\n\tusing LengthController::LengthController;\n\n\tvirtual void update(double deltaT) override { LengthController::update(deltaT); }\n\n\tvirtual CFrame getRelativeCFrame() const override {\n\t\treturn CFrame(0.0, 0.0, LengthController::getValue());\n\t}\n\tvirtual RelativeMotion getRelativeMotion() const override {\n\t\tFullTaylor<double> speedDerivatives = LengthController::getFullTaylorExpansion();\n\t\tTranslationalMotion translationMotion(speedDerivatives.getDerivatives().transform([](double v) {return Vec3(0, 0, v); }));\n\t\treturn RelativeMotion(Motion(translationMotion, RotationalMotion()), CFrame(0.0, 0.0, speedDerivatives.getConstantValue()));\n\t}\n\n\tvirtual ~PistonConstraintTemplate() override {}\n};\n};"
  },
  {
    "path": "Physics3D/hardconstraints/controller/constController.h",
    "content": "#pragma once\n\n#include \"../../math/taylorExpansion.h\"\n\nnamespace P3D {\nclass ConstController {\npublic:\n\tdouble value;\n\tinline ConstController(double value) : value(value) {}\n\tinline void update(double deltaT) const {}\n\tinline double getValue() const { return value; }\n\tinline FullTaylor<double> getFullTaylorExpansion() const {\n\t\treturn FullTaylor<double>{value};\n\t}\n};\n};"
  },
  {
    "path": "Physics3D/hardconstraints/controller/sineWaveController.cpp",
    "content": "#include \"sineWaveController.h\"\n\n#include \"../../math/predefinedTaylorExpansions.h\"\n#include \"../../math/constants.h\"\n\nnamespace P3D {\nSineWaveController::SineWaveController(double minValue, double maxValue, double period) :\n\tminValue(minValue),\n\tmaxValue(maxValue),\n\tperiod(period),\n\tcurrentStepInPeriod(0) {\n\n\tassert(maxValue >= minValue);\n}\n\nvoid SineWaveController::update(double deltaT) {\n\tcurrentStepInPeriod += deltaT;\n\tif(currentStepInPeriod >= period) currentStepInPeriod -= period;\n}\n\ndouble SineWaveController::getValue() const {\n\tdouble multiplier = (maxValue - minValue) / 2;\n\tdouble offset = minValue + multiplier;\n\n\tdouble currentAngle = currentStepInPeriod * (2 * PI / period);\n\n\treturn sin(currentAngle) * multiplier + offset;\n}\n\nFullTaylor<double> SineWaveController::getFullTaylorExpansion() const {\n\tdouble multiplier = (maxValue - minValue) / 2;\n\tdouble offset = minValue + multiplier;\n\n\tdouble divPeriodToRadians = 2 * PI / period;\n\n\tFullTaylor<double> result = generateFullTaylorForSinWave<double, 3>(currentStepInPeriod, (2 * PI / period)) * multiplier;\n\tresult += offset;\n\treturn result;\n}\n};"
  },
  {
    "path": "Physics3D/hardconstraints/controller/sineWaveController.h",
    "content": "#pragma once\n\n#include \"../../math/taylorExpansion.h\"\n#include \"../../motion.h\"\n\nnamespace P3D {\nclass SineWaveController {\npublic:\n\tdouble currentStepInPeriod;\n\tdouble minValue;\n\tdouble maxValue;\n\tdouble period;\n\n\tSineWaveController(double minValue, double maxValue, double period);\n\n\tvoid update(double deltaT);\n\tdouble getValue() const;\n\tFullTaylor<double> getFullTaylorExpansion() const;\n};\n};\n"
  },
  {
    "path": "Physics3D/hardconstraints/fixedConstraint.cpp",
    "content": "#include \"fixedConstraint.h\"\n\nnamespace P3D {\nvoid FixedConstraint::update(double deltaT) {}\nvoid FixedConstraint::invert() {}\nCFrame FixedConstraint::getRelativeCFrame() const { return CFrame(0.0, 0.0, 0.0); }\nRelativeMotion FixedConstraint::getRelativeMotion() const { return RelativeMotion(Motion(Vec3(0.0, 0.0, 0.0), Vec3(0.0, 0.0, 0.0)), CFrame(0.0, 0.0, 0.0)); }\n};"
  },
  {
    "path": "Physics3D/hardconstraints/fixedConstraint.h",
    "content": "#pragma once\n\n#include \"hardConstraint.h\"\nnamespace P3D {\n// Mostly used for debugging. You should instead use plain part attachments. \n// This constraint should behave exactly the same as a plain part attachment, but being a HardConstraint, it is less performant. \nclass FixedConstraint : public HardConstraint {\npublic:\n\n\tvirtual void update(double deltaT) override;\n\tvirtual void invert() override;\n\n\tvirtual CFrame getRelativeCFrame() const override;\n\tvirtual RelativeMotion getRelativeMotion() const override;\n};\n};"
  },
  {
    "path": "Physics3D/hardconstraints/hardConstraint.cpp",
    "content": "#include \"hardConstraint.h\"\n\nnamespace P3D {\nCFrame HardConstraint::getRelativeCFrame() const {\n\treturn this->getRelativeMotion().locationOfRelativeMotion;\n}\nHardConstraint::~HardConstraint() {}\n};"
  },
  {
    "path": "Physics3D/hardconstraints/hardConstraint.h",
    "content": "#pragma once\n\n#include \"../math/cframe.h\"\n#include \"../motion.h\"\n#include \"../relativeMotion.h\"\n\n\n/*\n\tA HardConstraint is a constraint that fully defines one object in terms of another\n*/\nnamespace P3D {\nclass HardConstraint {\npublic:\n\tbool isInverted = false;\n\tvirtual void update(double deltaT) = 0;\n\tvirtual void invert() { isInverted = !isInverted; }\n\tvirtual RelativeMotion getRelativeMotion() const = 0;\n\n\tvirtual CFrame getRelativeCFrame() const = 0;\n\n\tvirtual ~HardConstraint();\n};\n};"
  },
  {
    "path": "Physics3D/hardconstraints/hardPhysicalConnection.cpp",
    "content": "#include \"hardPhysicalConnection.h\"\n\nnamespace P3D {\nHardPhysicalConnection::HardPhysicalConnection(std::unique_ptr<HardConstraint> constraintWithParent, const CFrame& attachOnChild, const CFrame& attachOnParent) :\n\tattachOnChild(attachOnChild),\n\tattachOnParent(attachOnParent),\n\tconstraintWithParent(std::move(constraintWithParent)) {}\n\n\nCFrame HardPhysicalConnection::getRelativeCFrameToParent() const {\n\treturn attachOnParent.localToGlobal(constraintWithParent->getRelativeCFrame().localToGlobal(~attachOnChild));\n}\n\nRelativeMotion HardPhysicalConnection::getRelativeMotion() const {\n\tRelativeMotion relMotion = constraintWithParent->getRelativeMotion();\n\n\treturn relMotion.extendBegin(this->attachOnParent).extendEnd(~this->attachOnChild);\n}\n\nvoid HardPhysicalConnection::update(double deltaT) {\n\tconstraintWithParent->update(deltaT);\n}\n\nHardPhysicalConnection HardPhysicalConnection::inverted()&& {\n\tthis->constraintWithParent->invert();\n\n\treturn HardPhysicalConnection(std::move(this->constraintWithParent), this->attachOnParent, this->attachOnChild);\n}\n};"
  },
  {
    "path": "Physics3D/hardconstraints/hardPhysicalConnection.h",
    "content": "#pragma once\n\n#include <memory>\n\n#include \"hardConstraint.h\"\n\n#include \"../math/cframe.h\"\n#include \"../relativeMotion.h\"\n\nnamespace P3D {\nstruct HardPhysicalConnection {\n\tCFrame attachOnChild;\n\tCFrame attachOnParent;\n\tstd::unique_ptr<HardConstraint> constraintWithParent;\n\n\tHardPhysicalConnection(std::unique_ptr<HardConstraint> constraintWithParent, const CFrame& attachOnChild, const CFrame& attachOnParent);\n\n\tCFrame getRelativeCFrameToParent() const;\n\tRelativeMotion getRelativeMotion() const;\n\n\tvoid update(double deltaT);\n\tHardPhysicalConnection inverted()&&;\n};\n}\n"
  },
  {
    "path": "Physics3D/hardconstraints/motorConstraint.cpp",
    "content": "#include \"motorConstraint.h\"\n\n#include \"../math/linalg/trigonometry.h\"\n#include \"../math/constants.h\"\n\n#include \"../misc/debug.h\"\n\nnamespace P3D {\nvoid ConstantMotorTurner::update(double deltaT) {\n\tthis->currentAngle = fmod(fmod(this->currentAngle + deltaT * speed, 2 * PI) + 2 * PI, 2 * PI);\n}\n\nvoid ConstantMotorTurner::invert() { Debug::logError(\"ConstantSpeedMotorConstraint::invert is not implemented!\"); assert(false); }\n\n\ndouble ConstantMotorTurner::getValue() const {\n\treturn currentAngle;\n}\nFullTaylor<double> ConstantMotorTurner::getFullTaylorExpansion() const {\n\treturn FullTaylor<double>::fromConstantAndDerivatives(this->currentAngle, Taylor<double>{speed});\n}\n};"
  },
  {
    "path": "Physics3D/hardconstraints/motorConstraint.h",
    "content": "#pragma once\n\n#include \"hardConstraint.h\"\n#include \"constraintTemplates.h\"\n\nnamespace P3D {\nclass ConstantMotorTurner {\npublic:\n\tdouble speed;\n\tdouble currentAngle;\n\n\tinline ConstantMotorTurner(double motorSpeed, double currentAngle) :\n\t\tspeed(motorSpeed), currentAngle(currentAngle) {}\n\tinline ConstantMotorTurner(double motorSpeed) :\n\t\tspeed(motorSpeed), currentAngle(0.0) {}\n\n\tvoid update(double deltaT);\n\tvoid invert();\n\tdouble getValue() const;\n\tFullTaylor<double> getFullTaylorExpansion() const;\n};\n\ntypedef MotorConstraintTemplate<ConstantMotorTurner> ConstantSpeedMotorConstraint;\n};"
  },
  {
    "path": "Physics3D/hardconstraints/sinusoidalPistonConstraint.h",
    "content": "#include \"hardConstraint.h\"\n\n#include \"constraintTemplates.h\"\n#include \"controller/sineWaveController.h\"\n\nnamespace P3D {\ntypedef PistonConstraintTemplate<SineWaveController> SinusoidalPistonConstraint;\n};"
  },
  {
    "path": "Physics3D/inertia.cpp",
    "content": "#include \"inertia.h\"\n\n#include \"math/linalg/trigonometry.h\"\n#include \"math/predefinedTaylorExpansions.h\"\n\nnamespace P3D {\nSymmetricMat3 getRotatedInertia(const SymmetricMat3& originalInertia, const Rotation& rotation) {\n\treturn rotation.localToGlobal(originalInertia);\n}\n\nSymmetricMat3 getTranslatedInertia(const SymmetricMat3& originalInertia, double mass, const Vec3& translation, const Vec3& centerOfMass) {\n\tSymmetricMat3 translationFactor = skewSymmetricSquared(translation + centerOfMass) - skewSymmetricSquared(centerOfMass);\n\treturn originalInertia - translationFactor * mass;\n}\n\n/*\ncomputes a translated inertial matrix,\nCOMOffset is the offset of the object's center of mass from the resulting center of mass\n== localCenterOfMass - totalCenterOfMass\n*/\nSymmetricMat3 getTranslatedInertiaAroundCenterOfMass(const SymmetricMat3& originalInertia, double mass, const Vec3& COMOffset) {\n\tSymmetricMat3 translationFactor = skewSymmetricSquared(COMOffset);\n\treturn originalInertia - translationFactor * mass;\n}\n\nSymmetricMat3 getTransformedInertia(const SymmetricMat3& originalInertia, double mass, const CFrame& cframe, const Vec3& centerOfMass) {\n\treturn getTranslatedInertia(cframe.getRotation().localToGlobal(originalInertia), mass, cframe.getPosition(), centerOfMass);\n}\n\n\n/*\ncomputes a translated inertial matrix, and it's derivatives\nCOMOffset is the offset of the object's center of mass from the resulting center of mass\nmotionOfOffset is the change of COMOffset over time, this is relative to the motion of the COM towards which this is computed\n*/\nFullTaylor<SymmetricMat3> getTranslatedInertiaDerivativesAroundCenterOfMass(const SymmetricMat3& originalInertia, double mass, const Vec3& COMOffset, const TranslationalMotion& motionOfOffset) {\n\tFullTaylor<SymmetricMat3> result = -generateFullTaylorForSkewSymmetricSquared<double, 3>(FullTaylor<Vec3>::fromConstantAndDerivatives(COMOffset, motionOfOffset.translation));\n\n\tresult *= mass;\n\tresult += originalInertia;\n\treturn result;\n}\n\n/*\ncomputes a rotated inertial matrix, where originalInertia is the inertia around the center of mass of the transformed object\nrotation is the starting rotation, and rotationMotion gives the change in rotation, both expressed in global space\n*/\nFullTaylor<SymmetricMat3> getRotatedInertiaTaylor(const SymmetricMat3& originalInertia, const Rotation& rotation, const RotationalMotion& rotationMotion) {\n\tMat3 rotationMat = rotation.asRotationMatrix();\n\tTaylor<Mat3> rotationDerivs = generateTaylorForRotationMatrix<double, 2>(rotationMotion.rotation, rotationMat);\n\n\n\t// rotation(t) * originalInertia * rotation(t).transpose()\n\t// diff  => rotation(t) * originalInertia * rotation'(t).transpose() + rotation'(t) * originalInertia * rotation(t).transpose()\n\t// diff2 => 2 * rotation'(t) * originalInertia * rotation'(t).transpose() + rotation(t) * originalInertia * rotation''(t).transpose() + rotation''(t) * originalInertia * rotation(t).transpose()\n\n\treturn FullTaylor<SymmetricMat3>{\n\t\trotation.localToGlobal(originalInertia),\n\t\taddTransposed(rotationMat * originalInertia * rotationDerivs[0].transpose()),\n\t\taddTransposed(rotationMat * originalInertia * rotationDerivs[1].transpose()) + 2.0 * mulSymmetricLeftRightTranspose(originalInertia, rotationDerivs[0])};\n}\n\n/*\ncomputes a transformed inertial matrix, where originalInertia is the inertia around the center of mass of the transformed object\nlocalCenterOfMass is the center of mass of the transformed object\noffsetCFrame is the offset of the object to it's new position relative to the total Center Of Mass\n*/\nSymmetricMat3 getTransformedInertiaAroundCenterOfMass(const SymmetricMat3& originalInertia, double mass, const Vec3& localCenterOfMass, const CFrame& offsetCFrame) {\n\tVec3 resultingOffset = offsetCFrame.localToGlobal(localCenterOfMass);\n\treturn getTransformedInertiaAroundCenterOfMass(originalInertia, mass, CFrame(resultingOffset, offsetCFrame.getRotation()));\n}\n\n/*\ncomputes a transformed inertial matrix, where originalInertia is the inertia around the center of mass of the transformed object\noffsetCFrame is the offset of the object's center of mass and rotation relative to the COM of it's parent.\n*/\nSymmetricMat3 getTransformedInertiaAroundCenterOfMass(const SymmetricMat3& originalInertia, double mass, const CFrame& offsetCFrame) {\n\tSymmetricMat3 translationFactor = skewSymmetricSquared(offsetCFrame.getPosition());\n\treturn getRotatedInertia(originalInertia, offsetCFrame.getRotation()) - translationFactor * mass;\n}\n\n/*\ncomputes the derivatives of a transformed inertial matrix, where originalInertia is the inertia around the center of mass of the transformed object\nlocalCenterOfMass is the local center of mass in the local coordinate system of startingCFrame\nstartingCFrame is the current relative position\nmotion is the relative motion of the offset object's center of mass relative to the total center of mass, in the coordinate system of the total center of mass.\n*/\nFullTaylor<SymmetricMat3> getTransformedInertiaDerivativesAroundCenterOfMass(const SymmetricMat3& originalInertia, double mass, const Vec3& localCenterOfMass, const CFrame& startingCFrame, const Motion& motion) {\n\tVec3 relativeOffset = startingCFrame.localToRelative(localCenterOfMass);\n\tVec3 resultingOffset = startingCFrame.getPosition() + relativeOffset;\n\tMotion resultingMotion = motion.getMotionOfPoint(relativeOffset);\n\treturn getTransformedInertiaDerivativesAroundCenterOfMass(originalInertia, mass, CFrame(resultingOffset, startingCFrame.getRotation()), resultingMotion);\n}\n\n/*\ncomputes a transformed inertial matrix, where originalInertia is the inertia around the center of mass of the transformed object\nstartingCFrame is the current relative position\nmotion is the relative motion of the offset object's center of mass relative to the total center of mass, in the coordinate system of the total center of mass.\n*/\nFullTaylor<SymmetricMat3> getTransformedInertiaDerivativesAroundCenterOfMass(const SymmetricMat3& originalInertia, double mass, const CFrame& startingCFrame, const Motion& motion) {\n\tFullTaylor<Vec3> translation = FullTaylor<Vec3>::fromConstantAndDerivatives(startingCFrame.getPosition(), motion.translation.translation);\n\tRotation originalRotation = startingCFrame.getRotation();\n\tRotationalMotion rotationMotion = motion.rotation;\n\t\n\tFullTaylor<SymmetricMat3> translationFactor = -generateFullTaylorForSkewSymmetricSquared<double, 3>(translation) * mass;\n\t//translationFactor.constantValue += originalInertia;\n\n\tFullTaylor<SymmetricMat3> rotationFactor = getRotatedInertiaTaylor(originalInertia, originalRotation, rotationMotion);\n\n\treturn translationFactor + rotationFactor;\n}\n};"
  },
  {
    "path": "Physics3D/inertia.h",
    "content": "#pragma once\n\n#include \"math/linalg/mat.h\"\n#include \"math/cframe.h\"\n#include \"math/taylorExpansion.h\"\n#include \"motion.h\"\n#include \"relativeMotion.h\"\n\nnamespace P3D {\nSymmetricMat3 getRotatedInertia(const SymmetricMat3& originalInertia, const Rotation& rotation);\nSymmetricMat3 getTranslatedInertia(const SymmetricMat3& originalInertia, double mass, const Vec3& translation, const Vec3& centerOfMass);\nSymmetricMat3 getTransformedInertia(const SymmetricMat3& originalInertia, double mass, const CFrame& cframe, const Vec3& centerOfMass);\n\n/*\ncomputes a translated inertial matrix,\nCOMOffset is the offset of the object's center of mass from the resulting center of mass\n== localCenterOfMass - totalCenterOfMass\n*/\nSymmetricMat3 getTranslatedInertiaAroundCenterOfMass(const SymmetricMat3& originalInertia, double mass, const Vec3& COMOffset);\n\n/*\ncomputes a transformed inertial matrix, where originalInertia is the inertia around the center of mass of the transformed object\noffsetCFrame is the offset of the object's center of mass and rotation relative to the COM of it's parent.\n*/\nSymmetricMat3 getTransformedInertiaAroundCenterOfMass(const SymmetricMat3& originalInertia, double mass, const CFrame& offsetCFrame);\n\n/*\ncomputes a transformed inertial matrix, where originalInertia is the inertia around the center of mass of the transformed object\nlocalCenterOfMass is the center of mass of the transformed object\noffsetCFrame is the offset of the object to it's new position relative to the total Center Of Mass\n*/\nSymmetricMat3 getTransformedInertiaAroundCenterOfMass(const SymmetricMat3& originalInertia, double mass, const Vec3& localCenterOfMass, const CFrame& offsetCFrame);\n\n/*\ncomputes a transformed inertial matrix, where originalInertia is the inertia around the center of mass of the transformed object\noffsetCFrame is the offset of the object's center of mass and rotation relative to the COM of it's parent.\n*/\nSymmetricMat3 getTransformedInertiaAroundCenterOfMass(const SymmetricMat3& originalInertia, double mass, const CFrame& offsetCFrame);\n\n/*\ncomputes a rotated inertial matrix, where originalInertia is the inertia around the center of mass of the transformed object\nrotation is the starting rotation, and rotationMotion gives the change in rotation, both expressed in global space\n*/\nFullTaylor<SymmetricMat3> getRotatedInertiaTaylor(const SymmetricMat3& originalInertia, const Rotation& rotation, const RotationalMotion& rotationMotion);\n\n/*\ncomputes a translated inertial matrix, and it's derivatives\nCOMOffset is the offset of the object's center of mass from the resulting center of mass\nmotionOfOffset is the change of COMOffset over time, this is relative to the motion of the COM towards which this is computed\n*/\nFullTaylor<SymmetricMat3> getTranslatedInertiaDerivativesAroundCenterOfMass(const SymmetricMat3& originalInertia, double mass, const Vec3& COMOffset, const TranslationalMotion& motionOfOffset);\n\n/*\ncomputes a transformed inertial matrix, where originalInertia is the inertia around the center of mass of the transformed object\nstartingCFrame is the current relative position\nmotion is the relative motion of the offset object's center of mass relative to the total center of mass, in the coordinate system of the total center of mass.\n*/\nFullTaylor<SymmetricMat3> getTransformedInertiaDerivativesAroundCenterOfMass(const SymmetricMat3& originalInertia, double mass, const CFrame& startingCFrame, const Motion& motion);\n\n/*\ncomputes the derivatives of a transformed inertial matrix, where originalInertia is the inertia around the center of mass of the transformed object\nlocalCenterOfMass is the local center of mass in the local coordinate system of startingCFrame\nstartingCFrame is the current relative position\nmotion is the relative motion of the offset object's center of mass relative to the total center of mass, in the coordinate system of the total center of mass.\n*/\nFullTaylor<SymmetricMat3> getTransformedInertiaDerivativesAroundCenterOfMass(const SymmetricMat3& originalInertia, double mass, const Vec3& localCenterOfMass, const CFrame& startingCFrame, const Motion& motion);\n\n\ninline Vec3 getAngularMomentumFromOffsetOnlyVelocity(const Vec3& offset, const Vec3& velocity, double mass) {\n\treturn offset % velocity * mass;\n}\n\n\n// offsetInertia = originalInertia - [ComOffset]x ^ 2 * mass\n// angularMomemtum = (offsetInertia - [ComOffset]x ^ 2 * mass) * angularVel\n// == offsetInertia * angularVel - ComOffset % (ComOffset % angularVel) * mass\n// == offsetInertia * (velocity % ComOffset)/|ComOffset|^2 + ComOffset % velocity * mass\n// leftOverAngularMomentum = \n\ninline Vec3 getAngularMomentumFromOffset(const Vec3& offset, const Vec3& velocity, const Vec3& angularVelocity, const SymmetricMat3& inertia, double mass) {\n\tVec3 velocityAngularMomentum = getAngularMomentumFromOffsetOnlyVelocity(offset, velocity, mass);\n\tVec3 rotationAngularMomentum = inertia * angularVelocity;\n\treturn velocityAngularMomentum + rotationAngularMomentum;\n}\n};"
  },
  {
    "path": "Physics3D/layer.cpp",
    "content": "#include \"layer.h\"\n#include \"world.h\"\n\n#include \"misc/validityHelper.h\"\n#include \"misc/debug.h\"\n#include \"misc/physicsProfiler.h\"\n\n#include <assert.h>\n\nnamespace P3D {\nWorldLayer::WorldLayer(ColissionLayer* parent) : parent(parent) {}\n\nWorldLayer::~WorldLayer() {\n\ttree.forEach([](Part& p) {\n\t\tp.layer = nullptr;\n\t});\n}\n\nWorldLayer::WorldLayer(WorldLayer&& other) noexcept :\n\ttree(std::move(other.tree)),\n\tparent(other.parent) {\n\n\ttree.forEach([this, &other](Part& p) {\n\t\tassert(p.layer = &other);\n\t\tp.layer = this;\n\t});\n}\nWorldLayer& WorldLayer::operator=(WorldLayer&& other) noexcept {\n\tstd::swap(tree, other.tree);\n\tstd::swap(parent, other.parent);\n\n\ttree.forEach([this, &other](Part& p) {\n\t\tassert(p.layer = &other);\n\t\tp.layer = this;\n\t});\n\tother.tree.forEach([this, &other](Part& p) {\n\t\tassert(p.layer = this);\n\t\tp.layer = &other;\n\t});\n\treturn *this;\n}\n\nvoid WorldLayer::refresh() {\n\tphysicsMeasure.mark(PhysicsProcess::UPDATE_TREE_BOUNDS);\n\ttree.recalculateBounds();\n\tphysicsMeasure.mark(PhysicsProcess::UPDATE_TREE_STRUCTURE);\n\ttree.improveStructure();\n}\n\nvoid WorldLayer::addPart(Part* newPart) {\n\ttree.add(newPart);\n}\n\nstatic void addMotorPhysToGroup(BoundsTree<Part>& tree, MotorizedPhysical* phys, Part* group) {\n\tauto base = tree.getPrototype().getBaseTrunk();\n\tTrunkAllocator& alloc = tree.getPrototype().getAllocator();\n\tmodifyGroupRecursive(alloc, base.first, base.second, group, group->getBounds(), [&](TreeNodeRef& groupNode, const BoundsTemplate<float>& groupNodeBounds) {\n\t\tPart* mp = phys->getMainPart();\n\t\tif(groupNode.isLeafNode()) {\n\t\t\tTreeTrunk* newTrunk = alloc.allocTrunk();\n\t\t\tnewTrunk->setSubNode(0, std::move(groupNode), groupNodeBounds);\n\t\t\tnewTrunk->setSubNode(1, TreeNodeRef(mp), mp->getBounds());\n\t\t\tgroupNode = TreeNodeRef(newTrunk, 2, true);\n\t\t} else {\n\t\t\taddRecursive(alloc, groupNode.asTrunk(), groupNode.getTrunkSize(), TreeNodeRef(mp), mp->getBounds());\n\t\t}\n\t\tTreeTrunk& curTrunk = groupNode.asTrunk();\n\t\tint curTrunkSize = groupNode.getTrunkSize();\n\t\tphys->forEachPartExceptMainPart([&](Part& part) {\n\t\t\tcurTrunkSize = addRecursive(alloc, curTrunk, curTrunkSize, TreeNodeRef(&part), part.getBounds());\n\t\t});\n\t\tgroupNode.setTrunkSize(curTrunkSize);\n\t\treturn TrunkSIMDHelperFallback::getTotalBounds(curTrunk, curTrunkSize);\n\t});\n}\n\nvoid WorldLayer::addIntoGroup(Part* newPart, Part* group) {\n\tassert(newPart->layer == nullptr);\n\tassert(group->layer == this);\n\n\tPhysical* partPhys = newPart->getPhysical();\n\tif(partPhys != nullptr) {\n\t\tMotorizedPhysical* mainPhys = partPhys->mainPhysical;\n\t\taddMotorPhysToGroup(tree, mainPhys, group);\n\t\tmainPhys->forEachPart([this](Part& p) {p.layer = this; });\n\t} else {\n\t\ttree.addToGroup(newPart, group);\n\t\tnewPart->layer = this;\n\t}\n}\n\nvoid WorldLayer::moveOutOfGroup(Part* part) {\n\tthis->tree.moveOutOfGroup(part);\n}\n\nvoid WorldLayer::removePart(Part* partToRemove) {\n\tassert(partToRemove->layer == this);\n\ttree.remove(partToRemove);\n\tparent->world->onPartRemoved(partToRemove);\n\tpartToRemove->layer = nullptr;\n}\n\nvoid WorldLayer::notifyPartBoundsUpdated(const Part* updatedPart, const Bounds& oldBounds) {\n\ttree.updateObjectBounds(updatedPart, oldBounds);\n}\nvoid WorldLayer::notifyPartGroupBoundsUpdated(const Part* mainPart, const Bounds& oldMainPartBounds) {\n\ttree.updateObjectGroupBounds(mainPart, oldMainPartBounds);\n}\n\nvoid WorldLayer::notifyPartStdMoved(Part* oldPartPtr, Part* newPartPtr) noexcept {\n\ttree.findAndReplaceObject(oldPartPtr, newPartPtr, newPartPtr->getBounds());\n}\n\nvoid WorldLayer::mergeGroups(Part* first, Part* second) {\n\tthis->tree.mergeGroups(first, second);\n}\n\n// TODO can be optimized, this only needs to move the single partToMove node\nvoid WorldLayer::moveIntoGroup(Part* partToMove, Part* group) {\n\tthis->tree.mergeGroups(partToMove, group);\n}\n\n// TODO can be optimized, this only needs to move the single part nodes\nvoid WorldLayer::joinPartsIntoNewGroup(Part* p1, Part* p2) {\n\tthis->tree.mergeGroups(p1, p2);\n}\n\nint WorldLayer::getID() const {\n\treturn (parent->getID() * ColissionLayer::NUMBER_OF_SUBLAYERS) + static_cast<int>(this - parent->subLayers);\n}\nWorldLayer* getLayerByID(std::vector<ColissionLayer>& knownLayers, int id) {\n\treturn &knownLayers[id / ColissionLayer::NUMBER_OF_SUBLAYERS].subLayers[id % ColissionLayer::NUMBER_OF_SUBLAYERS];\n}\nconst WorldLayer* getLayerByID(const std::vector<ColissionLayer>& knownLayers, int id) {\n\treturn &knownLayers[id / ColissionLayer::NUMBER_OF_SUBLAYERS].subLayers[id % ColissionLayer::NUMBER_OF_SUBLAYERS];\n}\nint getMaxLayerID(const std::vector<ColissionLayer>& knownLayers) {\n\treturn static_cast<int>(knownLayers.size()) * ColissionLayer::NUMBER_OF_SUBLAYERS;\n}\n\nint ColissionLayer::getID() const {\n\treturn static_cast<int>(this - &world->layers[0]);\n}\n\nColissionLayer::ColissionLayer() : world(nullptr), collidesInternally(true), subLayers{WorldLayer(this), WorldLayer(this)} {}\nColissionLayer::ColissionLayer(WorldPrototype* world, bool collidesInternally) : world(world), collidesInternally(collidesInternally), subLayers{WorldLayer(this), WorldLayer(this)} {}\n\nColissionLayer::ColissionLayer(ColissionLayer&& other) noexcept : world(other.world), collidesInternally(other.collidesInternally), subLayers{std::move(other.subLayers[0]), std::move(other.subLayers[1])} {\n\tother.world = nullptr;\n\n\tfor(WorldLayer& l : subLayers) {\n\t\tl.parent = this;\n\t}\n}\nColissionLayer& ColissionLayer::operator=(ColissionLayer&& other) noexcept {\n\tstd::swap(this->world, other.world);\n\tstd::swap(this->subLayers, other.subLayers);\n\tstd::swap(this->collidesInternally, other.collidesInternally);\n\n\tfor(WorldLayer& l : subLayers) {\n\t\tl.parent = this;\n\t}\n\tfor(WorldLayer& l : other.subLayers) {\n\t\tl.parent = &other;\n\t}\n\treturn *this;\n}\n\nvoid ColissionLayer::refresh() {\n\tsubLayers[FREE_PARTS_LAYER].refresh();\n}\n\n\n\nstatic bool boundsSphereEarlyEnd(const DiagonalMat3& scale, const Vec3& sphereCenter, double sphereRadius) {\n\treturn std::abs(sphereCenter.x) > scale[0] + sphereRadius || std::abs(sphereCenter.y) > scale[1] + sphereRadius || std::abs(sphereCenter.z) > scale[2] + sphereRadius;\n}\n\nstatic bool runColissionPreTests(const Part& p1, const Part& p2) {\n\tVec3 offset = p1.getPosition() - p2.getPosition();\n\tif(isLongerThan(offset, p1.maxRadius + p2.maxRadius)) {\n\t\tintersectionStatistics.addToTally(IntersectionResult::PART_DISTANCE_REJECT, 1);\n\t\treturn false;\n\t}\n\tif(boundsSphereEarlyEnd(p1.hitbox.scale, p1.getCFrame().globalToLocal(p2.getPosition()), p2.maxRadius)) {\n\t\tintersectionStatistics.addToTally(IntersectionResult::PART_BOUNDS_REJECT, 1);\n\t\treturn false;\n\t}\n\tif(boundsSphereEarlyEnd(p2.hitbox.scale, p2.getCFrame().globalToLocal(p1.getPosition()), p1.maxRadius)) {\n\t\tintersectionStatistics.addToTally(IntersectionResult::PART_BOUNDS_REJECT, 1);\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nstatic void findColissionsBetween(std::vector<Colission>& colissions, const BoundsTree<Part>& treeA, const BoundsTree<Part>& treeB) {\n\ttreeA.forEachColissionWith(treeB, [&colissions](Part* a, Part* b) {\n\t\tcolissions.push_back(Colission{a, b});\n\t});\n}\nstatic void findColissionsInternal(std::vector<Colission>& colissions, const BoundsTree<Part>& tree) {\n\ttree.forEachColission([&colissions](Part* a, Part* b) {\n\t\tcolissions.push_back(Colission{a, b});\n\t});\n}\n\nvoid ColissionLayer::getInternalColissions(ColissionBuffer& curColissions) const {\n\tfindColissionsInternal(curColissions.freePartColissions, subLayers[0].tree);\n\tfindColissionsBetween(curColissions.freeTerrainColissions, subLayers[0].tree, subLayers[1].tree);\n}\nvoid getColissionsBetween(const ColissionLayer& a, const ColissionLayer& b, ColissionBuffer& curColissions) {\n\tfindColissionsBetween(curColissions.freePartColissions, a.subLayers[0].tree, b.subLayers[0].tree);\n\tfindColissionsBetween(curColissions.freeTerrainColissions, a.subLayers[0].tree, b.subLayers[1].tree);\n\tfindColissionsBetween(curColissions.freeTerrainColissions, b.subLayers[0].tree, a.subLayers[1].tree);\n}\n};"
  },
  {
    "path": "Physics3D/layer.h",
    "content": "#pragma once\n\n#include <vector>\n\n#include \"boundstree/boundsTree.h\"\n#include \"part.h\"\n#include \"colissionBuffer.h\"\n\nnamespace P3D {\nclass WorldPrototype;\nclass ColissionLayer;\n\nclass WorldLayer {\npublic:\n\tBoundsTree<Part> tree;\n\tColissionLayer* parent;\n\n\texplicit WorldLayer(ColissionLayer* parent);\n\n\tWorldLayer(WorldLayer&& other) noexcept;\n\tWorldLayer& operator=(WorldLayer&& other) noexcept;\n\tWorldLayer(const WorldLayer&) = delete;\n\tWorldLayer& operator=(const WorldLayer&) = delete;\n\n\t~WorldLayer();\n\n\tvoid refresh();\n\n\tvoid addPart(Part* newPart);\n\tvoid removePart(Part* partToRemove);\n\tvoid addIntoGroup(Part* newPart, Part* group);\n\ttemplate<typename PartIterBegin, typename PartIterEnd>\n\tvoid addAllToGroup(PartIterBegin begin, PartIterEnd end, Part* group) {\n\t\ttree.addAllToGroup(begin, end, group);\n\t}\n\t//void addIntoGroup(MotorizedPhysical* newPhys, Part* group);\n\n\tvoid notifyPartBoundsUpdated(const Part* updatedPart, const Bounds& oldBounds);\n\tvoid notifyPartGroupBoundsUpdated(const Part* mainPart, const Bounds& oldMainPartBounds);\n\t/*\n\t\tWhen a part is std::move'd to a different location, this function is called to update any pointers\n\t\tThis is something that in general should not be performed when the part is already in a world, but this function is provided for completeness\n\t*/\n\tvoid notifyPartStdMoved(Part* oldPartPtr, Part* newPartPtr) noexcept;\n\n\tvoid mergeGroups(Part* first, Part* second);\n\tvoid moveIntoGroup(Part* partToMove, Part* group);\n\tvoid moveOutOfGroup(Part* part);\n\tvoid joinPartsIntoNewGroup(Part* p1, Part* p2);\n\n\ttemplate<typename PartIterBegin, typename PartIterEnd>\n\tvoid splitGroup(PartIterBegin begin, PartIterEnd end) {\n\t\ttree.splitGroup(begin, end);\n\t}\n\tvoid optimize() {\n\t\ttree.maxImproveStructure();\n\t}\n\n\ttemplate<typename Func>\n\tvoid forEach(const Func& funcToRun) const {\n\t\ttree.forEach(funcToRun);\n\t}\n\n\ttemplate<typename Filter, typename Func>\n\tvoid forEachFiltered(const Filter& filter, const Func& funcToRun) const {\n\t\ttree.forEachFiltered(filter, funcToRun);\n\t}\n\n\tint getID() const;\n};\n\nWorldLayer* getLayerByID(std::vector<ColissionLayer>& knownLayers, int id);\nconst WorldLayer* getLayerByID(const std::vector<ColissionLayer>& knownLayers, int id);\nint getMaxLayerID(const std::vector<ColissionLayer>& knownLayers);\n\nclass ColissionLayer {\npublic:\n\tstatic constexpr int FREE_PARTS_LAYER = 0;\n\tstatic constexpr int TERRAIN_PARTS_LAYER = 1;\n\tstatic constexpr int NUMBER_OF_SUBLAYERS = 2;\n\n\tWorldLayer subLayers[NUMBER_OF_SUBLAYERS];\n\t// freePartsLayer\n\t// terrainLayer\n\tWorldPrototype* world;\n\tbool collidesInternally;\n\n\tColissionLayer();\n\tColissionLayer(WorldPrototype* world, bool collidesInternally);\n\n\tColissionLayer(ColissionLayer&& other) noexcept;\n\tColissionLayer& operator=(ColissionLayer&& other) noexcept;\n\n\tvoid refresh();\n\n\tvoid getInternalColissions(ColissionBuffer& curColissions) const;\n\n\ttemplate<typename Func>\n\tvoid forEach(const Func& funcToRun) const {\n\t\tfor(const WorldLayer& subLayer : this->subLayers) {\n\t\t\tsubLayer.forEach(funcToRun);\n\t\t}\n\t}\n\n\ttemplate<typename Filter, typename Func>\n\tvoid forEachFiltered(const Filter& filter, const Func& funcToRun) const {\n\t\tfor(const WorldLayer& subLayer : this->subLayers) {\n\t\t\tsubLayer.forEachFiltered(filter, funcToRun);\n\t\t}\n\t}\n\n\tint getID() const;\n};\nvoid getColissionsBetween(const ColissionLayer& a, const ColissionLayer& b, ColissionBuffer& curColissions);\n};\n"
  },
  {
    "path": "Physics3D/math/boundingBox.h",
    "content": "#pragma once\n\n#include \"linalg/vec.h\"\n\nnamespace P3D {\ntemplate<typename T>\nstruct BoundingBoxTemplate {\n\tVector<T, 3> min;\n\tVector<T, 3> max;\n\n\tBoundingBoxTemplate() : min(), max() {}\n\tBoundingBoxTemplate(T x, T y, T z) : min(-x / 2, -y / 2, -z / 2), max(x / 2, y / 2, z / 2) {}\n\tBoundingBoxTemplate(T xmin, T ymin, T zmin, T xmax, T ymax, T zmax) : min(xmin, ymin, zmin), max(xmax, ymax, zmax) {}\n\tBoundingBoxTemplate(Vector<T, 3> min, Vector<T, 3> max) : min(min), max(max) {}\n\n\t[[nodiscard]] bool intersects(const BoundingBoxTemplate& o) const {\n\t\treturn\n\t\t\tmin.x <= o.max.x && max.x >= o.min.x &&\n\t\t\tmin.y <= o.max.y && max.y >= o.min.y &&\n\t\t\tmin.z <= o.max.z && max.z >= o.min.z;\n\t}\n\t[[nodiscard]] bool containsPoint(const Vector<T, 3>& point) const {\n\t\treturn\n\t\t\tpoint.x >= min.x && point.x <= max.x &&\n\t\t\tpoint.y >= min.y && point.y <= max.y &&\n\t\t\tpoint.z >= min.z && point.z <= max.z;\n\t}\n\n\t[[nodiscard]] T getWidth() const { return max.x - min.x; }\n\t[[nodiscard]] T getHeight() const { return max.y - min.y; }\n\t[[nodiscard]] T getDepth() const { return max.z - min.z; }\n\t[[nodiscard]] Vector<T, 3> getCenter() const { return (min + max) * 0.5; }\n\t[[nodiscard]] BoundingBoxTemplate expanded(T amount) const { return BoundingBoxTemplate(min.x - amount, min.y - amount, min.z - amount, max.x + amount, max.y + amount, max.z + amount); }\n\t[[nodiscard]] BoundingBoxTemplate expanded(const Vector<T, 3>& p) {\n\t\treturn BoundingBoxTemplate<T>(\n\t\t\tp.x < min.x ? p.x : min.x,\n\t\t\tp.y < min.y ? p.y : min.y,\n\t\t\tp.z < min.z ? p.z : min.z,\n\t\t\tp.x > max.x ? p.x : max.x,\n\t\t\tp.y > max.y ? p.y : max.y,\n\t\t\tp.z > max.z ? p.z : max.z\n\t\t);\n\t}\n\t[[nodiscard]] BoundingBoxTemplate expanded(const BoundingBoxTemplate& o) {\n\t\treturn BoundingBoxTemplate<T>(\n\t\t\to.min.x < min.x ? o.min.x : min.x,\n\t\t\to.min.y < min.y ? o.min.y : min.y,\n\t\t\to.min.z < min.z ? o.min.z : min.z,\n\t\t\to.max.x > max.x ? o.max.x : max.x,\n\t\t\to.max.y > max.y ? o.max.y : max.y,\n\t\t\to.max.z > max.z ? o.max.z : max.z\n\t\t);\n\t}\n\t[[nodiscard]] BoundingBoxTemplate scaled(T scaleX, T scaleY, T scaleZ) {\n\t\treturn BoundingBoxTemplate{min.x * scaleX, min.y * scaleY, min.z * scaleZ, max.x * scaleX, max.y * scaleY, max.z * scaleZ};\n\t}\n};\n\ntypedef BoundingBoxTemplate<double> BoundingBox;\n\nstruct CircumscribingSphere {\n\tVec3 origin = Vec3();\n\tdouble radius = 0;\n};\n};"
  },
  {
    "path": "Physics3D/math/bounds.h",
    "content": "#pragma once\n\n#include \"position.h\"\n#include \"boundingBox.h\"\n\n#include <fenv.h>\n\nnamespace P3D {\ntemplate<typename T>\nstruct BoundsTemplate {\n\tPositionTemplate<T> min;\n\tPositionTemplate<T> max;\n\n\tconstexpr BoundsTemplate() = default;\n\tconstexpr BoundsTemplate(const PositionTemplate<T>& min, const PositionTemplate<T>& max) noexcept : min(min), max(max) {}\n\n\tBoundsTemplate(const BoundsTemplate<T>&) = default;\n\tBoundsTemplate& operator=(const BoundsTemplate<T>&) = default;\n\n\t// conversion constructors. Bounds should expand with rounding errors, bounds must always be at least as large as the object they're bounding\n\ttemplate<typename OtherT>\n\tconstexpr BoundsTemplate(const BoundsTemplate<OtherT>& from) noexcept : min(), max() {\n\t\tint curRound = fegetround();\n\t\tfesetround(FE_UPWARD);\n\t\tthis->min.x = static_cast<T>(from.min.x);\n\t\tthis->min.y = static_cast<T>(from.min.y);\n\t\tthis->min.z = static_cast<T>(from.min.z);\n\t\tfesetround(FE_DOWNWARD);\n\t\tthis->max.x = static_cast<T>(from.max.x);\n\t\tthis->max.y = static_cast<T>(from.max.y);\n\t\tthis->max.z = static_cast<T>(from.max.z);\n\t\tfesetround(curRound);\n\t}\n\ttemplate<typename OtherT>\n\tconstexpr BoundsTemplate& operator=(const BoundsTemplate<OtherT>& from) noexcept {\n\t\tint curRound = fegetround();\n\t\tfesetround(FE_UPWARD);\n\t\tthis->min.x = static_cast<T>(from.min.x);\n\t\tthis->min.y = static_cast<T>(from.min.y);\n\t\tthis->min.z = static_cast<T>(from.min.z);\n\t\tfesetround(FE_DOWNWARD);\n\t\tthis->max.x = static_cast<T>(from.max.x);\n\t\tthis->max.y = static_cast<T>(from.max.y);\n\t\tthis->max.z = static_cast<T>(from.max.z);\n\t\tfesetround(curRound);\n\t\treturn *this;\n\t}\n\n\tconstexpr Vector<T, 3> getDiagonal() const noexcept {\n\t\treturn max - min;\n\t}\n\n\tconstexpr bool contains(const PositionTemplate<T>& p) const noexcept {\n\t\treturn p >= min && p <= max;\n\t}\n\n\tconstexpr bool contains(const BoundsTemplate& other) const noexcept {\n\t\treturn other.min >= this->min && other.max <= this->max;\n\t}\n\n\tconstexpr PositionTemplate<T> getCenter() const noexcept {\n\t\treturn avg(min, max);\n\t}\n\n\tconstexpr BoundsTemplate expanded(T amount) const noexcept {\n\t\treturn BoundsTemplate(min - Vector<T, 3>(amount, amount, amount), max + Vector<T, 3>(amount, amount, amount));\n\t}\n\n\tconstexpr BoundsTemplate expanded(Vector<T, 3> amount) const noexcept {\n\t\treturn BoundsTemplate(min - amount, max + amount);\n\t}\n\n\tconstexpr T getWidth() const noexcept { return max.x - min.x; }\n\tconstexpr T getHeight() const noexcept { return max.y - min.y; }\n\tconstexpr T getDepth() const noexcept { return max.z - min.z; }\n\tconstexpr T getVolume() const noexcept { Vector<T, 3> diag = max - min; return diag.x * diag.y * diag.z; }\n};\n\ntemplate<typename T>\nconstexpr bool intersects(const BoundsTemplate<T>& first, const BoundsTemplate<T>& second) noexcept {\n\treturn first.max >= second.min && first.min <= second.max;\n}\ntemplate<typename T>\nconstexpr BoundsTemplate<T> unionOfBounds(const BoundsTemplate<T>& first, const BoundsTemplate<T>& second) noexcept {\n\treturn BoundsTemplate<T>(min(first.min, second.min), max(first.max, second.max));\n}\ntemplate<typename T>\nconstexpr bool operator==(const BoundsTemplate<T>& first, const BoundsTemplate<T>& second) noexcept {\n\treturn first.min == second.min && first.max == second.max;\n}\ntemplate<typename T>\nconstexpr bool operator!=(const BoundsTemplate<T>& first, const BoundsTemplate<T>& second) noexcept {\n\treturn first.min != second.min || first.max != second.max;\n}\n\ntemplate<typename PT, typename VT>\nconstexpr BoundsTemplate<PT> operator+(const BoundingBoxTemplate<VT>& localBox, const PositionTemplate<PT>& pos) noexcept {\n\tPositionTemplate<PT> min = pos + localBox.min;\n\tPositionTemplate<PT> max = pos + localBox.max;\n\treturn BoundsTemplate<PT>(min, max);\n}\ntemplate<typename T>\nconstexpr BoundingBoxTemplate<T> operator-(const BoundsTemplate<T>& box, const PositionTemplate<T>& pos) noexcept {\n\tVector<T, 3> min = box.min - pos;\n\tVector<T, 3> max = box.max - pos;\n\treturn BoundingBoxTemplate<T>(min, max);\n}\n\ntypedef BoundsTemplate<Fix<32>> Bounds;\n};"
  },
  {
    "path": "Physics3D/math/cframe.h",
    "content": "#pragma once\n\n#include \"linalg/vec.h\"\n#include \"rotation.h\"\n\nnamespace P3D {\ntemplate<typename T>\nstruct CFrameTemplate {\npublic:\n\tVector<T, 3> position;\n\tRotationTemplate<T> rotation;\n\n\tCFrameTemplate(const Vector<T, 3>& position, const RotationTemplate<T>& rotation) : position(position), rotation(rotation) {}\n\texplicit CFrameTemplate(const Vector<T, 3>& position) : position(position), rotation() {}\n\texplicit CFrameTemplate(const T& x, const T& y, const T& z) : position(x, y, z), rotation() {}\n\texplicit CFrameTemplate(const T& x, const T& y, const T& z, const RotationTemplate<T>& rotation) : position(x, y, z), rotation(rotation) {}\n\texplicit CFrameTemplate(const RotationTemplate<T>& rotation) : position(0,0,0), rotation(rotation) {}\n\tCFrameTemplate() : position(0, 0, 0), rotation() {}\n\n\ttemplate<typename OtherT>\n\tCFrameTemplate(const CFrameTemplate<OtherT>& other) : \n\t\tposition(static_cast<Vector<T, 3>>(other.position)),\n\t\trotation(static_cast<RotationTemplate<T>>(other.rotation)) {}\n\n\tVector<T, 3> localToGlobal(const Vector<T, 3>& lVec) const {\n\t\treturn rotation.localToGlobal(lVec) + position;\n\t}\n\n\tVector<T, 3> globalToLocal(const Vector<T, 3>& gVec) const {\n\t\treturn rotation.globalToLocal(gVec - position);\n\t}\n\n\tVector<T, 3> localToRelative(const Vector<T, 3>& lVec) const {\n\t\treturn rotation.localToGlobal(lVec);\n\t}\n\n\tVector<T, 3> relativeToLocal(const Vector<T, 3>& rVec) const {\n\t\treturn rotation.globalToLocal(rVec);\n\t}\n\n\tVector<T, 3> globalToRelative(const Vector<T, 3> & gVec) const {\n\t\treturn gVec - position;\n\t}\n\n\tVector<T, 3> relativeToGlobal(const Vector<T, 3> & rVec) const {\n\t\treturn rVec + position;\n\t}\n\n\tCFrameTemplate<T> localToGlobal(const CFrameTemplate<T>& lFrame) const {\n\t\treturn CFrameTemplate<T>(position + rotation.localToGlobal(lFrame.position), rotation.localToGlobal(lFrame.rotation));\n\t}\n\n\tCFrameTemplate<T> globalToLocal(const CFrameTemplate<T>& gFrame) const {\n\t\treturn CFrameTemplate<T>(rotation.globalToLocal(gFrame.position - position), rotation.globalToLocal(gFrame.rotation));\n\t}\n\t\n\tCFrameTemplate<T> localToRelative(const CFrameTemplate<T>& lFrame) const {\n\t\treturn CFrameTemplate<T>(rotation.localToGlobal(lFrame.position), rotation.localToGlobal(lFrame.rotation));\n\t}\n\n\tCFrameTemplate<T> relativeToLocal(const CFrameTemplate<T>& rFrame) const {\n\t\treturn CFrameTemplate<T>(rotation.globalToLocal(rFrame.position), rotation.globalToLocal(rFrame.rotation));\n\t}\n\n\tCFrameTemplate<T> globalToRelative(const CFrameTemplate<T>& gFrame) const {\n\t\treturn CFrameTemplate<T>(gFrame.position - this->position, gFrame.rotation);\n\t}\n\n\tCFrameTemplate<T> relativeToGlobal(const CFrameTemplate<T>& gFrame) const {\n\t\treturn CFrameTemplate<T>(gFrame.position + this->position, gFrame.rotation);\n\t}\n\n\tRotationTemplate<T> localToGlobal(const RotationTemplate<T>& localRot) const {\n\t\treturn rotation.localToGlobal(localRot);\n\t}\n\n\tRotationTemplate<T> globalToLocal(const RotationTemplate<T>& globalRot) const {\n\t\treturn rotation.globalToLocal(globalRot);\n\t}\n\n\tCFrameTemplate<T> operator~() const {\n\t\treturn CFrameTemplate<T>(rotation.globalToLocal(-position), ~rotation);\n\t}\n\n\tVector<T, 3> getPosition() const {\n\t\treturn position;\n\t}\n\n\tRotationTemplate<T> getRotation() const {\n\t\treturn rotation;\n\t}\n\n\tvoid translate(const Vector<T, 3>& delta) {\n\t\tthis->position += delta;\n\t}\n\n\tvoid rotate(const Rotation& rot) {\n\t\tthis->rotation = rot * this->rotation;\n\t}\n\n\tCFrameTemplate<T>& operator+=(const Vector<T, 3>& delta) {\n\t\tposition += delta;\n\t\treturn *this;\n\t}\n\n\tCFrameTemplate<T>& operator-=(const Vector<T, 3>& delta) {\n\t\tposition -= delta;\n\t\treturn *this;\n\t}\n\n\tCFrameTemplate<T> operator+(const Vector<T, 3>& delta) const {\n\t\treturn CFrameTemplate<T>(this->position + delta, this->rotation);\n\t}\n\n\tCFrameTemplate<T> operator-(const Vector<T, 3>& delta) const {\n\t\treturn CFrameTemplate<T>(this->position - delta, this->rotation);\n\t}\n\n\tCFrameTemplate<T> extendLocal(const Vector<T, 3>& delta) const {\n\t\treturn CFrameTemplate<T>(this->localToGlobal(delta), this->rotation);\n\t}\n\n\t/*\n\t\tConverts this CFrame to a 4x4 matrix, where for any Vec3 p:\n\t\tcframe.asMat4() * Vec4(p, 1.0) == cframe.localToGlobal(p)\n\t*/\n\tMatrix<T, 4, 4> asMat4() const {\n\t\treturn Matrix<T, 4, 4>(rotation.asRotationMatrix(), this->position, Vector<T, 3>(), static_cast<T>(1));\n\t}\n\n\t/*\n\t\tConverts this CFrame to a 4x4 matrix with given scaling factor, where for any Vec3 p:\n\t\tcframe.asMat4WithPreScale(scale) * Vec4(p, 1.0) == cframe.localToGlobal(scale * p)\n\t*/\n\tMatrix<T, 4, 4> asMat4WithPreScale(const DiagonalMatrix<T, 3>& scale) const {\n\t\treturn Matrix<T, 4, 4>(rotation.asRotationMatrix() * scale, this->position, Vector<T, 3>(), static_cast<T>(1));\n\t}\n\n\t/*\n\t\tConverts this CFrame to a 4x4 matrix with given scaling factor, where for any Vec3 p:\n\t\tcframe.asMat4WithPostScale(scale) * Vec4(p, 1.0) == scale * cframe.localToGlobal(p)\n\t*/\n\tMatrix<T, 4, 4> asMat4WithPostScale(const DiagonalMatrix<T, 3>& scale) const {\n\t\treturn Matrix<T, 4, 4>(scale * rotation.asRotationMatrix(), this->position, Vector<T, 3>::ZEROS(), static_cast<T>(1));\n\t}\n};\n\ntypedef CFrameTemplate<double> CFrame;\ntypedef CFrameTemplate<float> CFramef;\n};"
  },
  {
    "path": "Physics3D/math/constants.h",
    "content": "#pragma once\n\n#include <limits>\n\nnamespace P3D {\n#define EPSILON(T) epsilon<T>()\n#define PI pi<double>()\n#define E e<double>()\n#define G g<double>()\n#define HALF_PI half_pi<double>()\n#define TWO_PI two_pi<double>()\n#define GOLDEN_RATIO golden_ratio<double>()\n#define SQ2_2 sq2_2<double>()\n#define SQ3_2 sq3_2<double>()\n\ntemplate<typename T>\nconstexpr T epsilon() {\n\treturn std::numeric_limits<T>::epsilon();\n}\n\ntemplate<typename T>\nconstexpr T pi() {\n\treturn static_cast<T>(3.14159265358979323846264338327950288);\n}\n\ntemplate<typename T>\nconstexpr T two_pi() {\n\treturn static_cast<T>(6.28318530717958647692528676655900576);\n}\n\ntemplate<typename T>\nconstexpr T half_pi() {\n\treturn static_cast<T>(1.57079632679489661923132169163975144);\n}\n\ntemplate<typename T>\nconstexpr T e() {\n\treturn static_cast<T>(2.71828182845904523536028747135266249);\n}\n\ntemplate<typename T>\nconstexpr T g() {\n\treturn static_cast<T>(1.61803398874989484820458683436563811772030917980576286213544862270526046281890);\n}\n\ntemplate<typename T>\nconstexpr T golden_ratio() {\n\treturn static_cast<T>(1.61803398874989484820458683436563811);\n}\n\ntemplate<typename T>\nconstexpr T sq2_2() {\n\treturn static_cast<T>(0.70710678118654752440084436210484903);\n}\n\ntemplate<typename T>\nconstexpr T sq3_2() {\n\treturn static_cast<T>(0.86602540378443864676372317075293618);\n}\n};"
  },
  {
    "path": "Physics3D/math/fix.h",
    "content": "#pragma once\n\n#include <stdint.h>\n\nnamespace P3D {\ntemplate<int64_t N>\nstruct Fix {\n\tint64_t value;\n\n\tstatic constexpr int64_t ONE = int64_t(1) << N;\n\n\tconstexpr Fix() noexcept : value(0) {}\n\tconstexpr Fix(double d) noexcept : value(static_cast<int64_t>(d * ONE)) {}\n\tconstexpr Fix(float f) noexcept : value(static_cast<int64_t>(static_cast<double>(f) * ONE)) {}\n\tconstexpr Fix(int l) noexcept : value(static_cast<int64_t>(l) << N) {}\n\tconstexpr Fix(int64_t l) noexcept : value(l << N) {}\n\n\tinline constexpr operator double() const noexcept { return static_cast<double>(value) / ONE; }\n\tinline constexpr operator float() const noexcept { return static_cast<float>(value) / ONE; }\n\tinline explicit constexpr operator int64_t() const noexcept {\n\t\tif(value >= 0 || (value & (ONE-1)) == 0) {\n\t\t\treturn value >> N;\n\t\t} else {\n\t\t\treturn (value >> N) + 1;\n\t\t}\n\t}\n\n\tinline Fix<N>& operator++() noexcept { value += ONE; return *this; }\n\tinline Fix<N> operator++(int) & noexcept  { Fix<N> old = *this; value += ONE; return old; }\n\tinline Fix<N>& operator--() noexcept { value -= ONE; return *this; }\n\tinline Fix<N> operator--(int) & noexcept  { Fix<N> old = *this; value -= ONE; return old; }\n\n\tinline Fix<N>& operator+=(const Fix<N>& b) noexcept { this->value += b.value; return *this; }\n\tinline Fix<N>& operator-=(const Fix<N>& b) noexcept { this->value -= b.value; return *this; }\n\tinline Fix<N>& operator+=(int64_t b) noexcept { this->value += (b << N); return *this; }\n\tinline Fix<N>& operator-=(int64_t b) noexcept { this->value -= (b << N); return *this; }\n\tinline Fix<N>& operator+=(double b) noexcept { this->value += static_cast<int64_t>(ONE * b); return *this; }\n\tinline Fix<N>& operator-=(double b) noexcept { this->value -= static_cast<int64_t>(ONE * b); return *this; }\n\tinline Fix<N>& operator+=(float b) noexcept { this->value += static_cast<int64_t>(ONE * static_cast<double>(b)); return *this; }\n\tinline Fix<N>& operator-=(float b) noexcept { this->value -= static_cast<int64_t>(ONE * static_cast<double>(b)); return *this; }\n\n\tinline constexpr Fix<N> operator-() const noexcept {Fix<N> result; result.value = -this->value; return result;}\n};\n\n\ntemplate<int64_t N> inline constexpr Fix<N> operator+(Fix<N> a, Fix<N> b)   noexcept {Fix<N> result; result.value = a.value + b.value;  return result;}\ntemplate<int64_t N> inline constexpr Fix<N> operator-(Fix<N> a, Fix<N> b)   noexcept {Fix<N> result; result.value = a.value - b.value;  return result;}\ntemplate<int64_t N> inline constexpr Fix<N> operator+(Fix<N> a, int64_t b)  noexcept {Fix<N> result; result.value = a.value + (b << N); return result;}\ntemplate<int64_t N> inline constexpr Fix<N> operator-(Fix<N> a, int64_t b)  noexcept {Fix<N> result; result.value = a.value - (b << N); return result;}\ntemplate<int64_t N> inline constexpr Fix<N> operator+(int64_t a, Fix<N> b)  noexcept {Fix<N> result; result.value = (a << N) + b.value; return result;}\ntemplate<int64_t N> inline constexpr Fix<N> operator-(int64_t a, Fix<N> b)  noexcept {Fix<N> result; result.value = (a << N) - b.value; return result;}\n\ntemplate<int64_t N> inline constexpr Fix<N> operator+(Fix<N> a, double b)   noexcept {return a + Fix<N>(b);}\ntemplate<int64_t N> inline constexpr Fix<N> operator+(double a, Fix<N> b)   noexcept {return Fix<N>(a) + b;}\ntemplate<int64_t N> inline constexpr Fix<N> operator-(Fix<N> a, double b)   noexcept {return a - Fix<N>(b);}\ntemplate<int64_t N> inline constexpr Fix<N> operator-(double a, Fix<N> b)   noexcept {return Fix<N>(a) - b;}\n\ntemplate<int64_t N> inline constexpr Fix<N> operator+(Fix<N> a, float b)    noexcept {return a + Fix<N>(b);}\ntemplate<int64_t N> inline constexpr Fix<N> operator+(float a, Fix<N> b)    noexcept {return Fix<N>(a) + b;}\ntemplate<int64_t N> inline constexpr Fix<N> operator-(Fix<N> a, float b)    noexcept {return a - Fix<N>(b);}\ntemplate<int64_t N> inline constexpr Fix<N> operator-(float a, Fix<N> b)    noexcept {return Fix<N>(a) - b;}\n\ntemplate<int64_t N> inline constexpr Fix<N> operator*(Fix<N> a, int64_t b)  noexcept {Fix<N> result; result.value = a.value * b; return result;}\ntemplate<int64_t N> inline constexpr Fix<N> operator*(int64_t a, Fix<N> b)  noexcept {Fix<N> result; result.value = a * b.value; return result;}\n\ntemplate<int64_t N> inline constexpr Fix<N> operator*(Fix<N> a, int b)  noexcept { Fix<N> result; result.value = a.value * b; return result; }\ntemplate<int64_t N> inline constexpr Fix<N> operator*(int a, Fix<N> b)  noexcept { Fix<N> result; result.value = a * b.value; return result; }\n\ntemplate<int64_t N> inline constexpr Fix<N> operator*(Fix<N> a, double b)   noexcept {Fix<N> result; result.value = static_cast<int64_t>(a.value * b); return result;}\ntemplate<int64_t N> inline constexpr Fix<N> operator*(Fix<N> a, float b)    noexcept {Fix<N> result; result.value = static_cast<int64_t>(a.value * b); return result;}\ntemplate<int64_t N> inline constexpr Fix<N> operator*(double a, Fix<N> b)   noexcept {Fix<N> result; result.value = static_cast<int64_t>(a * b.value); return result;}\ntemplate<int64_t N> inline constexpr Fix<N> operator*(float a, Fix<N> b)    noexcept {Fix<N> result; result.value = static_cast<int64_t>(a * b.value); return result;}\n\ntemplate<int64_t N> inline constexpr Fix<N> operator/(Fix<N> a, double b)   noexcept {Fix<N> result; result.value = static_cast<int64_t>(a.value / b); return result;}\ntemplate<int64_t N> inline constexpr Fix<N> operator/(Fix<N> a, float b)    noexcept {Fix<N> result; result.value = static_cast<int64_t>(a.value / b); return result;}\ntemplate<int64_t N> inline constexpr Fix<N> operator/(double a, Fix<N> b)   noexcept {Fix<N> result; result.value = static_cast<int64_t>(a / b.value); return result;}\ntemplate<int64_t N> inline constexpr Fix<N> operator/(float a, Fix<N> b)    noexcept {Fix<N> result; result.value = static_cast<int64_t>(a / b.value); return result;}\n\ntemplate<int64_t N> inline constexpr Fix<N> operator/(Fix<N> a, int64_t b)  noexcept {Fix<N> result; result.value = a.value / b; return result;}\ntemplate<int64_t N> inline constexpr Fix<N> operator/(Fix<N> a, int b)  noexcept { Fix<N> result; result.value = a.value / b; return result; }\n\ntemplate<int64_t N> inline constexpr Fix<N> operator<<(Fix<N> a, int64_t b) noexcept {Fix<N> result; result.value = a.value << b; return result;}\ntemplate<int64_t N> inline constexpr Fix<N> operator>>(Fix<N> a, int64_t b) noexcept {Fix<N> result; result.value = a.value >> b; return result;}\n\ntemplate<int64_t N> inline constexpr Fix<N> operator<<(Fix<N> a, int b) noexcept { Fix<N> result; result.value = a.value << b; return result; }\ntemplate<int64_t N> inline constexpr Fix<N> operator>>(Fix<N> a, int b) noexcept { Fix<N> result; result.value = a.value >> b; return result; }\n\n\n#define CREATE_COMPARISONS(T1, T2, V1, V2) \\\ntemplate<int64_t N> inline constexpr bool operator==(T1 a, T2 b) noexcept { return V1 == V2; } \\\ntemplate<int64_t N> inline constexpr bool operator!=(T1 a, T2 b) noexcept { return V1 != V2; } \\\ntemplate<int64_t N> inline constexpr bool operator>=(T1 a, T2 b) noexcept { return V1 >= V2; } \\\ntemplate<int64_t N> inline constexpr bool operator<=(T1 a, T2 b) noexcept { return V1 <= V2; } \\\ntemplate<int64_t N> inline constexpr bool operator>(T1 a, T2 b) noexcept { return V1 > V2; } \\\ntemplate<int64_t N> inline constexpr bool operator<(T1 a, T2 b) noexcept { return V1 < V2; }\n\nCREATE_COMPARISONS(Fix<N>, Fix<N>, a.value, b.value);\nCREATE_COMPARISONS(Fix<N>, double, a, Fix<N>(b));\nCREATE_COMPARISONS(double, Fix<N>, Fix<N>(a), b);\nCREATE_COMPARISONS(Fix<N>, float, a, Fix<N>(b));\nCREATE_COMPARISONS(float, Fix<N>, Fix<N>(a), b);\nCREATE_COMPARISONS(Fix<N>, int64_t, a.value, b << N);\nCREATE_COMPARISONS(int64_t, Fix<N>, a << N, b.value);\nCREATE_COMPARISONS(Fix<N>, int, a.value, int64_t(b) << N);\nCREATE_COMPARISONS(int, Fix<N>, int64_t(a) << N, b.value);\n#undef CREATE_COMPARISONS\n\ntemplate<int64_t N>\ninline constexpr Fix<N> min(Fix<N> first, Fix<N> second) noexcept {\n\treturn (first.value <= second.value) ? first : second;\n}\n\ntemplate<int64_t N>\ninline constexpr Fix<N> max(Fix<N> first, Fix<N> second) noexcept {\n\treturn (first.value >= second.value) ? first : second;\n}\n};"
  },
  {
    "path": "Physics3D/math/globalCFrame.h",
    "content": "#pragma once\n\n#include \"position.h\"\n#include \"rotation.h\"\n#include \"cframe.h\"\n\nnamespace P3D {\nclass GlobalCFrame {\npublic:\n\tPosition position;\n\tRotation rotation;\n\tGlobalCFrame() : position(), rotation() {}\n\tGlobalCFrame(const Fix<32>& x, const Fix<32>& y, const Fix<32>& z) : position(x, y, z), rotation() {}\n\tGlobalCFrame(double x, double y, double z) : position(x, y, z), rotation() {}\n\tGlobalCFrame(double x, double y, double z, const Rotation& rotation) : position(x, y, z), rotation(rotation) {}\n\tGlobalCFrame(const Position& position) : position(position), rotation() {}\n\tGlobalCFrame(const Rotation& rotation) : position(), rotation(rotation) {}\n\tGlobalCFrame(const Position& position, const Rotation& rotation) : position(position), rotation(rotation) {}\n\n\tinline Position getPosition() const {return position;}\n\tinline Rotation getRotation() const { return rotation; }\n\n\tinline Vec3 globalToLocal(const Position& globalPos) const {\n\t\treturn rotation.globalToLocal(Vec3(globalPos - this->position));\n\t}\n\n\tinline Position localToGlobal(const Vec3& localVec) const {\n\t\treturn position + Vec3Fix(rotation.localToGlobal(localVec));\n\t}\n\n\tinline Vec3 localToRelative(const Vec3& localVec) const {\n\t\treturn rotation.localToGlobal(localVec);\n\t}\n\n\tinline Vec3 relativeToLocal(const Vec3& relativeVec) const {\n\t\treturn rotation.globalToLocal(relativeVec);\n\t}\n\n\tinline Vec3 globalToRelative(const Position& gPos) const {\n\t\treturn gPos - position;\n\t}\n\n\tinline Position relativeToGlobal(const Vec3& rVec) const {\n\t\treturn position + rVec;\n\t}\n\n\tinline GlobalCFrame localToGlobal(const CFrame& localFrame) const {\n\t\treturn GlobalCFrame(position + rotation.localToGlobal(localFrame.getPosition()), rotation * localFrame.getRotation());\n\t}\n\n\tinline CFrame globalToLocal(const GlobalCFrame& globalFrame) const {\n\t\treturn CFrame(rotation.globalToLocal(Vec3(globalFrame.position - position)), ~rotation * globalFrame.rotation);\n\t}\n\n\tinline Rotation localToGlobal(const Rotation& localRot) const {\n\t\treturn rotation * localRot;\n\t}\n\n\tinline Rotation globalToLocal(const Rotation& globalRot) const {\n\t\treturn ~rotation * globalRot;\n\t}\n\n\tinline CFrame localToRelative(const CFrame& lFrame) const {\n\t\treturn CFrame(rotation * lFrame.position, rotation * lFrame.rotation);\n\t}\n\n\tinline CFrame relativeToLocal(const CFrame& rFrame) const {\n\t\treturn CFrame(rotation.globalToLocal(rFrame.position), ~rotation * rFrame.rotation);\n\t}\n\n\tinline void translate(const Vec3Fix& offset) {\n\t\tthis->position += offset;\n\t}\n\n\tinline GlobalCFrame translated(const Vec3Fix& offset) {\n\t\treturn GlobalCFrame(position + offset, rotation);\n\t}\n\n\tinline void rotate(const Rotation& rot) {\n\t\tthis->rotation = rot * this->rotation;\n\t}\n\n\tinline GlobalCFrame rotated(const Rotation& rot) const {\n\t\treturn GlobalCFrame(position, rot * rotation);\n\t}\n\t\n\tinline GlobalCFrame& operator+=(const Vec3Fix& offset) {\n\t\tthis->position += offset;\n\t\treturn *this;\n\t}\n\tinline GlobalCFrame& operator-=(const Vec3Fix& offset) {\n\t\tthis->position -= offset;\n\t\treturn *this;\n\t}\n\tinline GlobalCFrame operator+(const Vec3Fix& offset) const {\n\t\treturn GlobalCFrame(position + offset, this->rotation);\n\t}\n\tinline GlobalCFrame operator-(const Vec3Fix& offset) const {\n\t\treturn GlobalCFrame(position - offset, this->rotation);\n\t}\n\n\tinline GlobalCFrame extendLocal(const Vec3& offset) const {\n\t\treturn GlobalCFrame(this->localToGlobal(offset), this->rotation);\n\t}\n\n\t/*\n\t\tConverts this CFrame to a 4x4 matrix, where for any Vec3 p:\n\t\tcframe.asMat4() * Vec4(p, 1.0) == cframe.localToGlobal(p)\n\n\t\tNote: loss of precision for far out positions, it is recommended to first compute the relative position, and then construct this matrix. \n\t\tThis is because the position is unsafely cast to a Vec3. \n\t*/\n\tMat4 asMat4() const {\n\t\treturn join(rotation.asRotationMatrix(), castPositionToVec3(this->position), Vec3(0.0, 0.0, 0.0), 1.0);\n\t}\n\n\t/*\n\t\tConverts this CFrame to a 4x4 matrix with given scaling factor, where for any Vec3 p:\n\t\tcframe.asMat4WithPreScale(scale) * Vec4(p, 1.0) == cframe.localToGlobal(scale * p)\n\n\t\tNote: loss of precision for far out positions, it is recommended to first compute the relative position, and then construct this matrix. \n\t\tThis is because the position is unsafely cast to a Vec3. \n\t*/\n\tMat4 asMat4WithPreScale(const DiagonalMat3& scale) const {\n\t\treturn join(rotation.asRotationMatrix() * scale, castPositionToVec3(this->position), Vec3(0.0, 0.0, 0.0), 1.0);\n\t}\n\n\t/*\n\t\tConverts this CFrame to a 4x4 matrix with given scaling factor, where for any Vec3 p:\n\t\tcframe.asMat4WithPostScale(scale) * Vec4(p, 1.0) == scale * cframe.localToGlobal(p)\n\n\t\tNote: loss of precision for far out positions, it is recommended to first compute the relative position, and then construct this matrix. \n\t\tThis is because the position is unsafely cast to a Vec3. \n\t*/\n\tMat4 asMat4WithPostScale(const DiagonalMat3& scale) const {\n\t\treturn join(scale * rotation.asRotationMatrix(), castPositionToVec3(this->position), Vec3(0.0, 0.0, 0.0), 1.0);\n\t}\n};\n\n\ninline CFrame operator-(GlobalCFrame cf, Position relativeTo) {\n\treturn CFrame(cf.getPosition() - relativeTo, cf.getRotation());\n}\ninline GlobalCFrame operator+(Position relativeTo, CFrame cf) {\n\treturn GlobalCFrame(relativeTo + cf.getPosition(), cf.getRotation());\n}\n};"
  },
  {
    "path": "Physics3D/math/globalTransform.h",
    "content": "#pragma once\n\n#include \"position.h\"\n#include \"linalg/mat.h\"\n#include \"transform.h\"\n#include \"globalCFrame.h\"\n\nnamespace P3D {\nclass GlobalTransform {\npublic:\n\tPosition position;\n\tMat3 transform;\n\tGlobalTransform() : position(), transform(Mat3::IDENTITY()) {}\n\tGlobalTransform(const Fix<32>& x, const Fix<32>& y, const Fix<32>& z) : position(x, y, z), transform(Mat3::IDENTITY()) {}\n\tGlobalTransform(double x, double y, double z) : position(x, y, z), transform(Mat3::IDENTITY()) {}\n\tGlobalTransform(double x, double y, double z, const Mat3& transform) : position(x, y, z), transform(transform) {}\n\tGlobalTransform(const Position& position) : position(position), transform(Mat3::IDENTITY()) {}\n\tGlobalTransform(const Mat3& transform) : position(), transform(transform) {}\n\tGlobalTransform(const Position& position, const Mat3& transform) : position(position), transform(transform) {}\n\n\tGlobalTransform(const GlobalCFrame& cframe) : position(cframe.getPosition()), transform(cframe.getRotation()) {}\n\n\tinline Position getPosition() const { return position; }\n\tinline Mat3 getTransform() const { return transform; }\n\n\tinline Vec3 globalToLocal(const Position& globalPos) const {\n\t\treturn ~transform * Vec3(globalPos - this->position);\n\t}\n\n\tinline Position localToGlobal(const Vec3& localVec) const {\n\t\treturn position + Vec3Fix(transform * localVec);\n\t}\n\n\tinline Vec3 localToRelative(const Vec3& localVec) const {\n\t\treturn transform * localVec;\n\t}\n\n\tinline Vec3 relativeToLocal(const Vec3& relativeVec) const {\n\t\treturn ~transform * relativeVec;\n\t}\n\n\tinline GlobalTransform localToGlobal(const Transform& localTransform) const {\n\t\treturn GlobalTransform(position + transform * localTransform.getPosition(), transform * localTransform.getLocalTransformation());\n\t}\n\n\tinline Transform globalToLocal(const GlobalTransform& globalFrame) const {\n\t\treturn Transform(~transform * Vec3(globalFrame.position - position), ~transform * globalFrame.transform);\n\t}\n\n\tinline Mat3 localToGlobal(const Mat3& localRot) const {\n\t\treturn transform * localRot;\n\t}\n\n\tinline Mat3 globalToLocal(const Mat3& globalRot) const {\n\t\treturn ~transform * globalRot;\n\t}\n\n\tinline Transform localToRelative(const Transform& lTransform) const {\n\t\treturn Transform(transform * lTransform.position, transform * lTransform.transform);\n\t}\n\n\tinline Transform relativeToLocal(const Transform& lTransform) const {\n\t\treturn Transform(~transform * lTransform.position, ~transform * lTransform.transform);\n\t}\n\n\tinline void translate(const Vec3Fix& offset) {\n\t\tthis->position += offset;\n\t}\n\tinline GlobalTransform translated(const Vec3Fix& offset) const {\n\t\treturn GlobalTransform(position + offset);\n\t}\n\tinline void rotate(const Mat3& rot) {\n\t\tthis->transform = rot * this->transform;\n\t}\n\n\tinline GlobalTransform rotated(const Mat3& rot) const {\n\t\treturn GlobalTransform(position, rot * transform);\n\t}\n};\n};\n"
  },
  {
    "path": "Physics3D/math/linalg/commonMatrices.h",
    "content": "#pragma once\n\n#include \"mat.h\"\n#include \"quat.h\"\n#include \"../constants.h\"\n\nnamespace P3D {\n#define QROT_X_90(Type) Quaternion<Type> {\\\nSQ2_2, SQ2_2, 0, 0}\n\n#define QROT_X_180(Type) Quaternion<Type> {\\\n0, 1, 0, 0}\n\n#define QROT_X_270(Type) Quaternion<Type> {\\\n-SQ2_2, SQ2_2, 0, 0}\n\n#define QROT_Y_90(Type) Quaternion<Type> {\\\nSQ2_2, 0, SQ2_2, 0}\n\n#define QROT_Y_180(Type) Quaternion<Type> {\\\n0, 0, 1, 0}\n\n#define QROT_Y_270(Type) Quaternion<Type> {\\\nSQ2_2, 0, -SQ2_2, 0}\n\n#define QROT_Z_90(Type) Quaternion<Type> {\\\nSQ2_2, 0, 0, SQ2_2}\n\n#define QROT_Z_180(Type) Quaternion<Type> {\\\n0, 0, 0, 1}\n\n#define QROT_Z_270(Type) Quaternion<Type> {\\\n-SQ2_2, 0, 0, SQ2_2}\n\n#define ROT_X_90(Type) Matrix<Type, 3, 3> {\\\n1, 0, 0,\\\n0, 0, -1,\\\n0, 1, 0}\n\n#define ROT_X_180(Type) Matrix<Type, 3, 3> {\\\n1, 0, 0,\\\n0, -1, 0,\\\n0, 0, -1}\n\n#define ROT_X_270(Type) Matrix<Type, 3, 3> {\\\n1, 0, 0, \\\n0, 0, 1, \\\n0, -1, 0}\n\n\n#define ROT_Y_90(Type) Matrix<Type, 3, 3> {\\\n0, 0, 1,\\\n0, 1, 0,\\\n-1, 0, 0}\n\n#define ROT_Y_180(Type) Matrix<Type, 3, 3> {\\\n-1, 0, 0,\\\n0, 1, 0,\\\n0, 0,-1}\n\n#define ROT_Y_270(Type) Matrix<Type, 3, 3> {\\\n0, 0,-1,\\\n0, 1, 0,\\\n1, 0, 0}\n\n#define ROT_Z_90(Type) Matrix<Type, 3, 3> {\\\n0, -1, 0,\\\n1, 0, 0,\\\n0, 0, 1}\n\n#define ROT_Z_180(Type) Matrix<Type, 3, 3> {\\\n-1, 0, 0,\\\n0, -1, 0,\\\n0, 0, 1}\n\n#define ROT_Z_270(Type) Matrix<Type, 3, 3> {\\\n0, 1, 0,\\\n-1, 0, 0,\\\n0, 0, 1}\n};"
  },
  {
    "path": "Physics3D/math/linalg/eigen.cpp",
    "content": "#include \"eigen.h\"\n\n#include <cmath>\n\nnamespace P3D {\ntemplate<typename N>\nvoid update(EigenValues<N, 3>& e, bool* changed, int k, N t) {\n\tN y = e[k];\n\te[k] = y + t;\n\tchanged[k] = !(y == e[k]);\n}\ntemplate<typename N>\nvoid rotateEigen(Matrix<N, 3, 3>& copy, int k, int l, int i, int j, N c, N s) {\n\tN SKL = copy(k, l);\n\tN SIJ = copy(i, j);\n\tcopy(k, l) = c * SKL - s * SIJ;\n\tcopy(i, j) = s * SKL + c * SIJ;\n}\n\nEigenSet<double, 3> getEigenDecomposition(const SymmetricMat3& sm) {\n\n\tMat3 copy(sm);\n\n\tEigenValues<double, 3> eigenValues{sm(0, 0),sm(1, 1),sm(2, 2)};\n\tMat3 eigenVectors = Mat3::IDENTITY();\n\n\tbool changed[3]{true, true, true};\n\n\n\tint tieBreaker = 0;\n\tconst int values[6]{\n\t\t0,1,\n\t\t0,2,\n\t\t1,2\n\t};\n\twhile(changed[0] || changed[1] || changed[2]) {\n\t\tdouble top = std::abs(copy(0, 1));\n\t\tdouble topRight = std::abs(copy(0, 2));\n\t\tdouble right = std::abs(copy(1, 2));\n\n\t\tint k, l;\n\n\t\t// find which of the three upper off-diagonal elements is the biggest\n\t\tif(top > topRight && top > right) { k = 0; l = 1; } \n\t\telse if(topRight > top && topRight > right) { k = 0; l = 2; } \n\t\telse if(right > top && right > topRight) { k = 1; l = 2; } else {\n\t\t\t// TIEBREAKER\n\t\t\tk = values[tieBreaker * 2]; l = values[tieBreaker * 2 + 1];\n\t\t\ttieBreaker = (tieBreaker + 1) % 3;\n\t\t}\n\n\t\tdouble p = copy(k, l);\n\n\t\tif(p == 0) {\n\t\t\treturn EigenSet<double, 3>(eigenValues, eigenVectors);\n\t\t}\n\n\n\t\tdouble y = (eigenValues[l] - eigenValues[k]) / 2; \n\t\tdouble d = std::abs(y) + std::sqrt(p * p + y * y);\n\t\tdouble r = std::sqrt(p * p + d * d); \n\t\tdouble c = d / r; \n\t\tdouble s = p / r; \n\t\tdouble t = p * p / d;\n\n\t\tif(y < 0) { s = -s; t = -t; };\n\n\t\tcopy(k, l) =  0.0; \n\t\tupdate(eigenValues, changed, k, -t); \n\t\tupdate(eigenValues, changed, l, t);\n\n\t\tfor(int i = 0; i <= k - 1; i++) rotateEigen(copy, i, k, i, l, c, s);\n\t\tfor(int i = k + 1; i <= l - 1; i++) rotateEigen(copy, k, i, i, l, c, s);\n\t\tfor(int i = l + 1; i < 3; i++) rotateEigen(copy, k, i, l, i, c, s);\n\n\t\tfor(int i = 0; i < 3; i++) {\n\t\t\tdouble EIK = eigenVectors(i, k);\n\t\t\tdouble EIL = eigenVectors(i, l);\n\t\t\teigenVectors(i, k) = c * EIK - s * EIL;\n\t\t\teigenVectors(i, l) = s * EIK + c * EIL;\n\t\t}\n\t}\n\treturn EigenSet<double, 3>(eigenValues, eigenVectors);\n}\n};\n"
  },
  {
    "path": "Physics3D/math/linalg/eigen.h",
    "content": "#pragma once\n\n#include \"mat.h\"\n#include <initializer_list>\n#include <stddef.h>\n\nnamespace P3D {\ntemplate<typename T, std::size_t Size>\nstruct EigenValues {\n\tT values[Size];\n\n\tEigenValues(std::initializer_list<T> list) {\n\t\tassert(list.size() == Size);\n\t\tconst double* listValues = list.begin();\n\t\tfor(std::size_t i = 0; i < Size; i++) {\n\t\t\tvalues[i] = listValues[i];\n\t\t}\n\t}\n\n\tDiagonalMatrix<T, Size> asDiagonalMatrix() const {\n\t\treturn DiagonalMatrix<T, Size>(values);\n\t}\n\n\tconst T& operator[](std::size_t index) const { return values[index]; }\n\tT& operator[](std::size_t index) { return values[index]; }\n};\n\ntemplate<typename T, std::size_t Size>\nstruct EigenSet {\n\tEigenValues<T, Size> eigenValues;\n\tMatrix<T, Size, Size> eigenVectors;\n\tEigenSet(EigenValues<T, Size> eigenValues, const Matrix<T, Size, Size>& eigenVectors) : eigenValues(eigenValues), eigenVectors(eigenVectors) {};\n};\n\nEigenSet<double, 3> getEigenDecomposition(const SymmetricMat3& sm);\n};"
  },
  {
    "path": "Physics3D/math/linalg/largeMatrix.h",
    "content": "#pragma once\n\n#include \"mat.h\"\n#include <utility>\n#include <assert.h>\n\nnamespace P3D {\ntemplate<typename T>\nclass UnmanagedLargeVector {\npublic:\n\tT* data;\n\tsize_t n;\n\n\tUnmanagedLargeVector() : n(0), data(nullptr) {}\n\tUnmanagedLargeVector(T* dataBuf, size_t size) : data(dataBuf), n(size) {}\n\n\tUnmanagedLargeVector(UnmanagedLargeVector&& other) noexcept : data(other.data), n(other.n) {\n\t\tother.data = nullptr;\n\t\tother.n = 0;\n\t}\n\n\tinline UnmanagedLargeVector& operator=(UnmanagedLargeVector&& other) noexcept {\n\t\tstd::swap(this->data, other.data);\n\t\tstd::swap(this->n, other.n);\n\t\treturn *this;\n\t}\n\n\tsize_t size() const { return n; }\n\n\ttemplate<typename VectorType>\n\tinline void setSubVector(const VectorType& vec, size_t offset = 0) {\n\t\tassert(offset + vec.size() <= n);\n\t\tfor(size_t i = 0; i < vec.size(); i++) {\n\t\t\tthis->data[i + offset] = vec[i];\n\t\t}\n\t}\n\n\ttemplate<size_t Size>\n\tinline Vector<T, Size> getSubVector(size_t offset = 0) {\n\t\tassert(offset + Size <= n);\n\t\tVector<T, Size> result;\n\t\tfor (size_t i = 0; i < Size; i++) {\n\t\t\tresult[i] = this->data[i + offset];\n\t\t}\n\t\treturn result;\n\t}\n\n\tinline UnmanagedLargeVector<T> subVector(size_t offset, size_t size) {\n\t\tassert(offset + size <= n);\n\t\treturn UnmanagedLargeVector<T>(this->data + offset, size);\n\t}\n\tinline UnmanagedLargeVector<const T> subVector(size_t offset, size_t size) const {\n\t\tassert(offset + size <= n);\n\t\treturn UnmanagedLargeVector<const T>(this->data + offset, size);\n\t}\n\n\tT& operator[] (size_t index) {\n\t\tassert(index >= 0 && index < n);\n\t\treturn data[index];\n\t}\n\tconst T& operator[] (size_t index) const {\n\t\tassert(index >= 0 && index < n);\n\t\treturn data[index];\n\t}\n\n\tinline UnmanagedLargeVector& operator+=(const UnmanagedLargeVector& other) {\n\t\tassert(this->n == other.n);\n\n\t\tfor(size_t i = 0; i < n; i++) {\n\t\t\tthis->data[i] += other.data[i];\n\t\t}\n\t\treturn *this;\n\t}\n\tinline UnmanagedLargeVector& operator-=(const UnmanagedLargeVector& other) {\n\t\tassert(this->n == other.n);\n\n\t\tfor(size_t i = 0; i < n; i++) {\n\t\t\tthis->data[i] -= other.data[i];\n\t\t}\n\t\treturn *this;\n\t}\n};\n\ntemplate<typename T>\nclass LargeVector : public UnmanagedLargeVector<T> {\npublic:\n\tLargeVector() = default;\n\tLargeVector(size_t size) : UnmanagedLargeVector<T>(new T[size], size) {}\n\n\tLargeVector(size_t size, const T* initialData) : UnmanagedLargeVector<T>(new T[size], size) {\n\t\tfor(size_t i = 0; i < size; i++) {\n\t\t\tthis->data[i] = initialData[i];\n\t\t}\n\t}\n\t~LargeVector() {\n\t\tdelete[] this->data;\n\t}\n\n\tLargeVector(const LargeVector& other) : UnmanagedLargeVector<T>(new T[other.n], other.n) {\n\t\tfor(int i = 0; i < other.n; i++) {\n\t\t\tthis->data[i] = other.data[i];\n\t\t}\n\t}\n\tinline LargeVector& operator=(const LargeVector& other) {\n\t\tdelete[] this->data;\n\t\tthis->n = other.n;\n\t\tthis->data = new T[other.n];\n\t\tfor(int i = 0; i < other.n; i++) {\n\t\t\tthis->data[i] = other.data[i];\n\t\t}\n\t\treturn *this;\n\t}\n};\n\ntemplate<typename T>\nclass UnmanagedLargeMatrix {\npublic:\n\tT* data;\n\tsize_t w, h;\n\n\tUnmanagedLargeMatrix() : w(0), h(0), data(nullptr) {}\n\tUnmanagedLargeMatrix(T* buffer, size_t width, size_t height) : w(width), h(height), data(buffer) {}\n\n\tinline UnmanagedLargeMatrix(UnmanagedLargeMatrix&& other) noexcept : data(other.data), w(other.w), h(other.h) {\n\t\tother.data = nullptr;\n\t\tother.w = 0;\n\t\tother.h = 0;\n\t}\n\n\tinline UnmanagedLargeMatrix& operator=(UnmanagedLargeMatrix&& other) noexcept {\n\t\tstd::swap(this->data, other.data);\n\t\tstd::swap(this->w, other.w);\n\t\tstd::swap(this->h, other.h);\n\t\treturn *this;\n\t}\n\n\tT& operator()(size_t row, size_t col) {\n\t\tassert(row >= 0 && row < h);\n\t\tassert(col >= 0 && col < w);\n\t\treturn data[w * row + col];\n\t}\n\n\tconst T& operator()(size_t row, size_t col) const {\n\t\tassert(row >= 0 && row < h);\n\t\tassert(col >= 0 && col < w);\n\t\treturn data[w * row + col];\n\t}\n\n\tvoid setSubMatrix(size_t topLeftRow, size_t topLeftCol, const UnmanagedLargeMatrix& matrix) {\n\t\tfor (size_t row = 0; row < matrix.h; row++) {\n\t\t\tfor (size_t col = 0; col < matrix.w; col++) {\n\t\t\t\t(*this)(row + topLeftRow, col + topLeftCol) = matrix(row, col);\n\t\t\t}\n\t\t}\n\t}\n\n\tsize_t width() const { return w; }\n\tsize_t height() const { return h; }\n\n\tLargeVector<T> getRow(size_t row) const {\n\t\tLargeVector<T> result(w);\n\t\tfor(size_t i = 0; i < w; i++) {\n\t\t\tresult[i] = (*this)(row, i);\n\t\t}\n\t\treturn result;\n\t}\n\tLargeVector<T> getCol(size_t col) const {\n\t\tLargeVector<T> result(h);\n\t\tfor(size_t i = 0; i < h; i++) {\n\t\t\tresult[i] = (*this)(i, col);\n\t\t}\n\t\treturn result;\n\t}\n\ttemplate<typename VectorType>\n\tvoid setRow(size_t row, const VectorType& value) {\n\t\tassert(w == value.size());\n\t\tfor(size_t i = 0; i < w; i++) {\n\t\t\t(*this)(row, i) = value[i];\n\t\t}\n\t}\n\ttemplate<typename VectorType>\n\tvoid setCol(size_t col, const VectorType& value) {\n\t\tassert(h == value.size());\n\t\tfor(size_t i = 0; i < h; i++) {\n\t\t\t(*this)(i, col) = value[i];\n\t\t}\n\t}\n\t\n\tinline UnmanagedLargeMatrix& operator+=(const UnmanagedLargeMatrix& other) {\n\t\tassert(this->w == other.w);\n\t\tassert(this->h == other.h);\n\n\t\tfor(size_t i = 0; i < w * h; i++) {\n\t\t\tthis->data[i] += other.data[i];\n\t\t}\n\t\treturn *this;\n\t}\n\n\tinline UnmanagedLargeMatrix& operator-=(const UnmanagedLargeMatrix& other) {\n\t\tassert(this->w == other.w);\n\t\tassert(this->h == other.h);\n\n\t\tfor(size_t i = 0; i < w * h; i++) {\n\t\t\tthis->data[i] -= other.data[i];\n\t\t}\n\t\treturn *this;\n\t}\n\n\tT* begin() {return data;}\n\tT* end() {return data + w * h;}\n\tconst T* begin() const { return data; }\n\tconst T* end() const { return data + w * h; }\n};\n\ntemplate<typename T>\nclass LargeMatrix : public UnmanagedLargeMatrix<T> {\npublic:\n\tLargeMatrix() = default;\n\tLargeMatrix(size_t width, size_t height) : UnmanagedLargeMatrix<T>(new T[width * height], width, height) {}\n\t~LargeMatrix() {\n\t\tdelete[] this->data;\n\t}\n\tLargeMatrix(const LargeMatrix& other) : UnmanagedLargeMatrix<T>(new T[other.w * other.h], other.w, other.h) {\n\t\tfor(size_t i = 0; i < other.w * other.h; i++) {\n\t\t\tthis->data[i] = other.data[i];\n\t\t}\n\t}\n\tLargeMatrix& operator=(const LargeMatrix& other) {\n\t\tdelete[] this->data;\n\t\tthis->h = other.h;\n\t\tthis->w = other.w;\n\t\tthis->data = new T[other.h * other.w];\n\t\tfor(size_t i = 0; i < other.w * other.h; i++) {\n\t\t\tthis->data[i] = other.data[i];\n\t\t}\n\t\treturn *this;\n\t}\n\tLargeMatrix(LargeMatrix&& other) noexcept : UnmanagedLargeMatrix<T>(other.data, other.w, other.h) {\n\t\tother.data = nullptr;\n\t\tother.w = 0;\n\t\tother.h = 0;\n\t}\n\tLargeMatrix& operator=(LargeMatrix&& other) noexcept {\n\t\tstd::swap(this->data, other.data);\n\t\tstd::swap(this->w, other.w);\n\t\tstd::swap(this->h, other.h);\n\t\treturn *this;\n\t}\n\n\tstatic LargeMatrix zero(size_t width, size_t height) {\n\t\tLargeMatrix result(width, height);\n\t\tfor(size_t i = 0; i < width * height; i++) {\n\t\t\tresult.data[i] = 0;\n\t\t}\n\t\treturn result;\n\t}\n};\n\nconstexpr size_t getAmountOfElementsForSymmetric(size_t size) {\n\treturn size * (size + 1) / 2;\n}\n\ntemplate<typename T>\nclass UnmanagedLargeSymmetricMatrix {\npublic:\n\tT* data;\n\tsize_t size;\n\n\tUnmanagedLargeSymmetricMatrix() : data(nullptr), size(0) {}\n\tUnmanagedLargeSymmetricMatrix(T* data, size_t size) : data(data), size(size) {}\n\n\tinline UnmanagedLargeSymmetricMatrix(UnmanagedLargeSymmetricMatrix&& other) noexcept : data(other.data), size(other.size) {\n\t\tother.data = nullptr;\n\t\tother.size = 0;\n\t}\n\n\tinline UnmanagedLargeSymmetricMatrix& operator=(UnmanagedLargeSymmetricMatrix&& other) noexcept {\n\t\tstd::swap(this->data, other.data);\n\t\tstd::swap(this->size, other.size);\n\t\treturn *this;\n\t}\n\n\tsize_t width() const { return size; }\n\tsize_t height() const { return size; }\n\n\tLargeVector<T> getRow(size_t row) const {\n\t\tLargeVector<T> result(size);\n\t\tfor(size_t i = 0; i < size; i++) {\n\t\t\tresult[i] = (*this)(row, i);\n\t\t}\n\t\treturn result;\n\t}\n\tLargeVector<T> getCol(size_t col) const {\n\t\tLargeVector<T> result(size);\n\t\tfor(size_t i = 0; i < size; i++) {\n\t\t\tresult[i] = (*this)(i, col);\n\t\t}\n\t\treturn result;\n\t}\n\ttemplate<typename VectorType>\n\tvoid setRow(size_t row, const VectorType& value) {\n\t\tassert(size == value.size());\n\t\tfor(size_t i = 0; i < size; i++) {\n\t\t\t(*this)(row, i) = value[i];\n\t\t}\n\t}\n\ttemplate<typename VectorType>\n\tvoid setCol(size_t col, const VectorType& value) {\n\t\tassert(size == value.size());\n\t\tfor(size_t i = 0; i < size; i++) {\n\t\t\t(*this)(i, col) = value[i];\n\t\t}\n\t}\n\t\n\tinline UnmanagedLargeSymmetricMatrix& operator+=(const UnmanagedLargeSymmetricMatrix& other) {\n\t\tassert(this->size == other.size);\n\n\t\tfor(size_t i = 0; i < size * (size + 1) / 2; i++) {\n\t\t\tthis->data[i] += other.data[i];\n\t\t}\n\t\treturn *this;\n\t}\n\tinline UnmanagedLargeSymmetricMatrix& operator-=(const UnmanagedLargeSymmetricMatrix& other) {\n\t\tassert(this->size == other.size);\n\n\t\tfor(size_t i = 0; i < size * (size + 1) / 2; i++) {\n\t\t\tthis->data[i] -= other.data[i];\n\t\t}\n\t\treturn *this;\n\t}\n\n\tT& operator()(size_t row, size_t col) {\n\t\tsize_t a = (row >= col) ? row : col; // max\n\t\tsize_t b = (row >= col) ? col : row; // min\n\n\t\tassert(b >= 0);\n\t\tassert(a < size);\n\n\t\treturn this->data[a * (a + 1) / 2 + b];\n\t}\n\tconst T& operator()(size_t row, size_t col) const {\n\t\tsize_t a = (row >= col) ? row : col; // max\n\t\tsize_t b = (row >= col) ? col : row; // min\n\n\t\tassert(b >= 0);\n\t\tassert(a < size);\n\n\t\treturn this->data[a * (a + 1) / 2 + b];\n\t}\n};\n\ntemplate<typename T>\nclass LargeSymmetricMatrix : public UnmanagedLargeSymmetricMatrix<T> {\npublic:\n\tLargeSymmetricMatrix() = default;\n\tLargeSymmetricMatrix(size_t size) : UnmanagedLargeSymmetricMatrix<T>(new T[getAmountOfElementsForSymmetric(size)], size) {}\n\t~LargeSymmetricMatrix() { delete[] this->data; }\n\n\tLargeSymmetricMatrix(const LargeSymmetricMatrix& other) : UnmanagedLargeSymmetricMatrix<T>(new T[getAmountOfElementsForSymmetric(other.size)], other.size) {\n\t\tfor(size_t i = 0; i < getAmountOfElementsForSymmetric(other.size); i++) {\n\t\t\tthis->data[i] = other.data[i];\n\t\t}\n\t}\n\tinline LargeSymmetricMatrix& operator=(const LargeSymmetricMatrix& other) {\n\t\tdelete[] this->data;\n\t\tthis->size = other.size;\n\t\tthis->data = new T[getAmountOfElementsForSymmetric(other.size)];\n\t\tfor(size_t i = 0; i < getAmountOfElementsForSymmetric(other.size); i++) {\n\t\t\tthis->data[i] = other.data[i];\n\t\t}\n\t\treturn *this;\n\t}\n};\n\ntemplate<typename T, size_t Rows>\nclass UnmanagedVerticalFixedMatrix {\npublic:\n\tT* data;\n\tsize_t cols;\n\n\tUnmanagedVerticalFixedMatrix() : data(nullptr), cols(0) {}\n\tUnmanagedVerticalFixedMatrix(T* data, size_t width) : data(data), cols(width) {}\n\n\tinline UnmanagedVerticalFixedMatrix(UnmanagedVerticalFixedMatrix&& other) : data(other.data), cols(other.cols) {\n\t\tother.data = nullptr;\n\t\tother.cols = 0;\n\t}\n\n\tinline UnmanagedVerticalFixedMatrix& operator=(UnmanagedVerticalFixedMatrix&& other) {\n\t\tstd::swap(this->data, other.data);\n\t\tstd::swap(this->cols, other.cols);\n\t\treturn *this;\n\t}\n\n\tsize_t width() const { return cols; }\n\tconstexpr size_t height() const { return Rows; }\n\t\n\tLargeVector<T> getRow(size_t row) const {\n\t\tLargeVector<T> result(cols);\n\t\tfor(size_t i = 0; i < cols; i++) {\n\t\t\tresult[i] = (*this)(row, i);\n\t\t}\n\t\treturn result;\n\t}\n\tVector<T, Rows> getCol(size_t col) const {\n\t\tVector<T, Rows> result;\n\t\tfor(size_t i = 0; i < Rows; i++) {\n\t\t\tresult[i] = (*this)(i, col);\n\t\t}\n\t\treturn result;\n\t}\n\ttemplate<typename VectorType>\n\tvoid setRow(size_t row, const VectorType& value) {\n\t\tassert(cols == value.size());\n\t\tfor(size_t i = 0; i < cols; i++) {\n\t\t\t(*this)(row, i) = value[i];\n\t\t}\n\t}\n\tvoid setCol(size_t col, const Vector<T, Rows>& value) {\n\t\tfor(size_t i = 0; i < Rows; i++) {\n\t\t\t(*this)(i, col) = value[i];\n\t\t}\n\t}\n\n\tUnmanagedVerticalFixedMatrix<T, Rows> subCols(size_t offset, size_t size) {\n\t\tassert(offset + size <= cols);\n\t\treturn UnmanagedVerticalFixedMatrix<T, Rows>(data + Rows * offset, size);\n\t}\n\tUnmanagedVerticalFixedMatrix<const T, Rows> subCols(size_t offset, size_t size) const {\n\t\tassert(offset + size <= cols);\n\t\treturn UnmanagedVerticalFixedMatrix<const T, Rows>(data + Rows * offset, size);\n\t}\n\n\tinline UnmanagedVerticalFixedMatrix& operator+=(const UnmanagedVerticalFixedMatrix& other) {\n\t\tassert(this->cols == other.cols);\n\n\t\tfor(size_t i = 0; i < Rows * cols; i++) {\n\t\t\tthis->data[i] += other.data[i];\n\t\t}\n\t\treturn *this;\n\t}\n\tinline UnmanagedVerticalFixedMatrix& operator-=(const UnmanagedVerticalFixedMatrix& other) {\n\t\tassert(this->cols == other.cols);\n\n\t\tfor(size_t i = 0; i < Rows * cols; i++) {\n\t\t\tthis->data[i] -= other.data[i];\n\t\t}\n\t\treturn *this;\n\t}\n\n\tT& operator()(size_t row, size_t col) {\n\t\tassert(row >= 0 && row < Rows && col >= 0 && col < cols);\n\t\treturn data[col * Rows + row];\n\t}\n\tconst T& operator()(size_t row, size_t col) const {\n\t\tassert(row >= 0 && row < Rows && col >= 0 && col < cols);\n\t\treturn data[col * Rows + row];\n\t}\n\tT* begin() { return data; }\n\tconst T* begin() const { return data; }\n\tT* end() { return data + cols*Rows; }\n\tconst T* end() const { return data + cols*Rows; }\n};\n\ntemplate<typename T, size_t Rows>\nclass VerticalFixedMatrix : public UnmanagedVerticalFixedMatrix<T, Rows> {\npublic:\n\tVerticalFixedMatrix() = default;\n\tVerticalFixedMatrix(size_t cols) : UnmanagedVerticalFixedMatrix<T, Rows>(new T[cols * Rows], cols * Rows) {}\n\t~VerticalFixedMatrix() { delete[] this->data; }\n\n\tVerticalFixedMatrix(const VerticalFixedMatrix& other) : UnmanagedVerticalFixedMatrix<T, Rows>(new T[other.cols * Rows], other.cols * Rows) {\n\t\tfor(size_t i = 0; i < other.cols * Rows; i++) {\n\t\t\tthis->data[i] = other.data[i];\n\t\t}\n\t}\n\tinline VerticalFixedMatrix& operator=(const VerticalFixedMatrix& other) {\n\t\tdelete[] this->data;\n\t\tthis->size = other.size;\n\t\tthis->data = new T[other.cols * Rows];\n\t\tfor(size_t i = 0; i < other.cols * Rows; i++) {\n\t\t\tthis->data[i] = other.data[i];\n\t\t}\n\t\treturn *this;\n\t}\n};\n\ntemplate<typename T, size_t Cols>\nclass UnmanagedHorizontalFixedMatrix {\npublic:\n\tT* data;\n\tsize_t rows;\n\n\tUnmanagedHorizontalFixedMatrix() : data(nullptr), rows(0) {}\n\tUnmanagedHorizontalFixedMatrix(T* data, size_t width) : data(data), rows(width) {}\n\n\tinline UnmanagedHorizontalFixedMatrix(UnmanagedHorizontalFixedMatrix&& other) : data(other.data), rows(other.rows) {\n\t\tother.data = nullptr;\n\t\tother.rows = 0;\n\t}\n\n\tinline UnmanagedHorizontalFixedMatrix& operator=(UnmanagedHorizontalFixedMatrix&& other) {\n\t\tstd::swap(this->data, other.data);\n\t\tstd::swap(this->rows, other.rows);\n\t\treturn *this;\n\t}\n\n\tconstexpr size_t width() const { return Cols; }\n\tsize_t height() const { return rows; }\n\t\n\tVector<T, Cols> getRow(size_t row) const {\n\t\tVector<T, Cols> result;\n\t\tfor(size_t i = 0; i < Cols; i++) {\n\t\t\tresult[i] = (*this)(row, i);\n\t\t}\n\t\treturn result;\n\t}\n\tLargeVector<T> getCol(size_t col) const {\n\t\tLargeVector<T> result(rows);\n\t\tfor(size_t i = 0; i < rows; i++) {\n\t\t\tresult[i] = (*this)(i, col);\n\t\t}\n\t\treturn result;\n\t}\n\tvoid setRow(size_t row, const Vector<T, Cols>& value) {\n\t\tfor(size_t i = 0; i < Cols; i++) {\n\t\t\t(*this)(row, i) = value[i];\n\t\t}\n\t}\n\ttemplate<typename VectorType>\n\tvoid setCol(size_t col, const VectorType& value) {\n\t\tassert(rows == value.size());\n\t\tfor(size_t i = 0; i < rows; i++) {\n\t\t\t(*this)(i, col) = value[i];\n\t\t}\n\t}\n\n\tUnmanagedHorizontalFixedMatrix<T, Cols> subRows(size_t offset, size_t size) {\n\t\tassert(offset + size <= rows);\n\t\treturn UnmanagedHorizontalFixedMatrix<T, Cols>(data + Cols * offset, size);\n\t}\n\tUnmanagedHorizontalFixedMatrix<const T, Cols> subRows(size_t offset, size_t size) const {\n\t\tassert(offset + size <= rows);\n\t\treturn UnmanagedHorizontalFixedMatrix<const T, Cols>(data + Cols * offset, size);\n\t}\n\n\tinline UnmanagedHorizontalFixedMatrix& operator+=(const UnmanagedHorizontalFixedMatrix& other) {\n\t\tassert(this->rows == other.rows);\n\n\t\tfor(size_t i = 0; i < rows * Cols; i++) {\n\t\t\tthis->data[i] += other.data[i];\n\t\t}\n\t\treturn *this;\n\t}\n\tinline UnmanagedHorizontalFixedMatrix& operator-=(const UnmanagedHorizontalFixedMatrix& other) {\n\t\tassert(this->rows == other.rows);\n\n\t\tfor(size_t i = 0; i < rows * Cols; i++) {\n\t\t\tthis->data[i] -= other.data[i];\n\t\t}\n\t\treturn *this;\n\t}\n\n\tT& operator()(size_t row, size_t col) {\n\t\tassert(row >= 0 && row < rows && col >= 0 && col < Cols);\n\t\treturn data[row * Cols + col];\n\t}\n\tconst T& operator()(size_t row, size_t col) const {\n\t\tassert(row >= 0 && row < rows && col >= 0 && col < Cols);\n\t\treturn data[row * Cols + col];\n\t}\n\tT* begin() { return data; }\n\tconst T* begin() const { return data; }\n\tT* end() { return data + rows * Cols; }\n\tconst T* end() const { return data + rows * Cols; }\n};\n\ntemplate<typename T, size_t Cols>\nclass HorizontalFixedMatrix : public UnmanagedHorizontalFixedMatrix<T, Cols> {\npublic:\n\tHorizontalFixedMatrix() = default;\n\tHorizontalFixedMatrix(size_t cols) : UnmanagedHorizontalFixedMatrix<T, Cols>(new T[cols * Cols], cols) {}\n\t~HorizontalFixedMatrix() { delete[] this->data; }\n\n\tHorizontalFixedMatrix(const HorizontalFixedMatrix& other) : UnmanagedHorizontalFixedMatrix<T, Cols>(new T[other.rows * Cols], other.rows * Cols) {\n\t\tfor(size_t i = 0; i < other.rows * Cols; i++) {\n\t\t\tthis->data[i] = other.data[i];\n\t\t}\n\t}\n\tinline HorizontalFixedMatrix& operator=(const HorizontalFixedMatrix& other) {\n\t\tdelete[] this->data;\n\t\tthis->size = other.size;\n\t\tthis->data = new T[other.rows * Cols];\n\t\tfor(size_t i = 0; i < other.rows * Cols; i++) {\n\t\t\tthis->data[i] = other.data[i];\n\t\t}\n\t\treturn *this;\n\t}\n};\n\n/*\n\tOperators\n*/\n\ntemplate<typename T>\nLargeVector<T> operator*(const UnmanagedLargeMatrix<T>& m, const UnmanagedLargeVector<T>& v) {\n\tassert(v.n == m.w);\n\tLargeVector<T> newVector(m.h);\n\n\tfor(size_t i = 0; i < m.h; i++) {\n\t\tT total = m(i, 0) * v[0];\n\n\t\tfor(size_t j = 1; j < m.w; j++) {\n\t\t\ttotal += m(i, j) * v[j];\n\t\t}\n\t\tnewVector[i] = total;\n\t}\n\treturn newVector;\n}\n\ntemplate<typename T>\nLargeVector<T> operator*(const UnmanagedLargeSymmetricMatrix<T>& m, const UnmanagedLargeVector<T>& v) {\n\tassert(v.n == m.size);\n\tLargeVector<T> newVector(m.size);\n\n\tfor(size_t i = 0; i < m.size; i++) {\n\t\tT total = m(i, 0) * v[0];\n\n\t\tfor(size_t j = 1; j < m.size; j++) {\n\t\t\ttotal += m(i, j) * v[j];\n\t\t}\n\t\tnewVector[i] = total;\n\t}\n\treturn newVector;\n}\n\ntemplate<typename T, size_t Size>\nVector<T, Size> operator*(const UnmanagedVerticalFixedMatrix<T, Size>& m, const UnmanagedLargeVector<T>& v) {\n\tassert(m.cols == v.n);\n\tVector<T, Size> result;\n\n\tfor(size_t i = 0; i < Size; i++) {\n\t\tT total = m(i, 0) * v[0];\n\n\t\tfor(size_t j = 1; j < m.cols; j++) {\n\t\t\ttotal += m(i, j) * v[j];\n\t\t}\n\t\tresult[i] = total;\n\t}\n\treturn result;\n}\n\ntemplate<typename T, size_t Height, size_t Width>\nMatrix<T, Height, Width> operator*(const UnmanagedVerticalFixedMatrix<T, Height>& m1, const UnmanagedHorizontalFixedMatrix<T, Width>& m2) {\n\tassert(m1.cols == m2.rows);\n\tMatrix<T, Height, Width> result;\n\n\tinMemoryMatrixMultiply(m1, m2, result);\n\treturn result;\n}\n\ntemplate<typename M1, typename M2, typename MResult>\nvoid inMemoryMatrixMultiply(const M1& m1, const M2& m2, MResult& result) {\n\tassert(m1.height() == result.height()); // result height\n\tassert(m2.width() == result.width()); // result width\n\tassert(m1.width() == m2.height()); // intermediate\n\n\tfor(std::size_t col = 0; col < result.width(); col++) {\n\t\tfor(std::size_t row = 0; row < result.height(); row++) {\n\t\t\tauto sum = m1(row, 0) * m2(0, col);\n\t\t\tfor(std::size_t i = 1; i < m1.width(); i++) {\n\t\t\t\tsum += m1(row, i) * m2(i, col);\n\t\t\t}\n\t\t\tresult(row, col) = sum;\n\t\t}\n\t}\n}\n\ntemplate<typename M, typename V, typename VResult>\nvoid inMemoryMatrixVectorMultiply(const M& m, const V& v, VResult& result) {\n\tassert(v.size() == m.width());\n\tassert(result.size() == m.height());\n\n\tfor(std::size_t row = 0; row < m.height(); row++) {\n\t\tauto sum = m(row, 0) * v[0];\n\t\tfor(std::size_t col = 1; col < m.width(); col++) {\n\t\t\tsum += m(row, col) * v[col];\n\t\t}\n\t\tresult[row] = sum;\n\t}\n}\n\ntemplate<typename V>\nvoid inMemoryVectorNegate(V& v) {\n\tfor(std::size_t i = 0; i < v.size(); i++) {\n\t\tv[i] = -v[i];\n\t}\n}\n\ntemplate<typename M>\nvoid inMemoryMatrixNegate(M& m) {\n\tfor(std::size_t row = 0; row < m.height(); row++) {\n\t\tfor(std::size_t col = 0; col < m.width(); col++) {\n\t\t\tm(row, col) = -m(row, col);\n\t\t}\n\t}\n}\n};"
  },
  {
    "path": "Physics3D/math/linalg/largeMatrixAlgorithms.h",
    "content": "#pragma once\n\n\n#include \"largeMatrix.h\"\n\n#include <utility>\n#include <cmath>\n#include <assert.h>\n#include <stddef.h>\n\nnamespace P3D {\ntemplate<typename T>\nstatic void swapRows(UnmanagedLargeVector<T>& v, std::size_t rowA, std::size_t rowB) {\n\tstd::swap(v[rowA], v[rowB]);\n}\ntemplate<typename T>\nstatic void swapRows(UnmanagedLargeMatrix<T>& m, std::size_t rowA, std::size_t rowB) {\n\tfor(std::size_t i = 0; i < m.w; i++) {\n\t\tstd::swap(m(rowA, i), m(rowB, i));\n\t}\n}\ntemplate<typename T, std::size_t Cols>\nstatic void swapRows(UnmanagedHorizontalFixedMatrix<T, Cols>& m, std::size_t rowA, std::size_t rowB) {\n\tfor(std::size_t i = 0; i < Cols; i++) {\n\t\tstd::swap(m(rowA, i), m(rowB, i));\n\t}\n}\ntemplate<typename T, std::size_t Rows>\nstatic void swapRows(UnmanagedVerticalFixedMatrix<T, Rows>& m, std::size_t rowA, std::size_t rowB) {\n\tfor(std::size_t i = 0; i < m.cols; i++) {\n\t\tstd::swap(m(rowA, i), m(rowB, i));\n\t}\n}\n\ntemplate<typename T>\nstatic void subtractRowsFactorTimes(UnmanagedLargeVector<T>& v, std::size_t editRow, std::size_t subtractingRow, T factor) {\n\tv[editRow] -= v[subtractingRow] * factor;\n}\ntemplate<typename T>\nstatic void subtractRowsFactorTimes(UnmanagedLargeMatrix<T>& m, std::size_t editRow, std::size_t subtractingRow, T factor) {\n\tfor(std::size_t i = 0; i < m.w; i++) {\n\t\tm(editRow, i) -= m(subtractingRow, i) * factor;\n\t}\n}\ntemplate<typename T, std::size_t Cols>\nstatic void subtractRowsFactorTimes(UnmanagedHorizontalFixedMatrix<T, Cols>& m, std::size_t editRow, std::size_t subtractingRow, T factor) {\n\tfor(std::size_t i = 0; i < Cols; i++) {\n\t\tm(editRow, i) -= m(subtractingRow, i) * factor;\n\t}\n}\ntemplate<typename T, std::size_t Rows>\nstatic void subtractRowsFactorTimes(UnmanagedVerticalFixedMatrix<T, Rows>& m, std::size_t editRow, std::size_t subtractingRow, T factor) {\n\tfor(std::size_t i = 0; i < m.cols; i++) {\n\t\tm(editRow, i) -= m(subtractingRow, i) * factor;\n\t}\n}\n\ntemplate<typename T>\nstatic void multiplyRowBy(UnmanagedLargeVector<T>& v, std::size_t row, T factor) {\n\tv[row] *= factor;\n}\ntemplate<typename T>\nstatic void multiplyRowBy(UnmanagedLargeMatrix<T>& m, std::size_t row, T factor) {\n\tfor(std::size_t i = 0; i < m.w; i++) {\n\t\tm(row, i) *= factor;\n\t}\n}\ntemplate<typename T, std::size_t Cols>\nstatic void multiplyRowBy(UnmanagedHorizontalFixedMatrix<T, Cols>& m, std::size_t row, T factor) {\n\tfor(std::size_t i = 0; i < Cols; i++) {\n\t\tm(row, i) *= factor;\n\t}\n}\ntemplate<typename T, std::size_t Rows>\nstatic void multiplyRowBy(UnmanagedVerticalFixedMatrix<T, Rows>& m, std::size_t row, T factor) {\n\tfor(std::size_t i = 0; i < m.cols; i++) {\n\t\tm(row, i) *= factor;\n\t}\n}\n\ntemplate<typename T>\nstatic std::size_t getHeight(UnmanagedLargeVector<T>& v) {\n\treturn v.n;\n}\ntemplate<typename T>\nstatic std::size_t getHeight(UnmanagedLargeMatrix<T>& m) {\n\treturn m.h;\n}\ntemplate<typename T, std::size_t Cols>\nstatic std::size_t getHeight(UnmanagedHorizontalFixedMatrix<T, Cols>& m) {\n\treturn m.rows;\n}\ntemplate<typename T, std::size_t Rows>\nstatic std::size_t getHeight(UnmanagedVerticalFixedMatrix<T, Rows>& m) {\n\treturn Rows;\n}\n\ntemplate<typename System, typename SolutionType>\nvoid destructiveSolve(System& m, SolutionType& v) {\n\tassert(getHeight(v) == m.w && m.w == m.h);\n\tstd::size_t size = getHeight(v);\n\n\t// make matrix upper triangular\n\tfor(std::size_t i = 0; i < size; i++) {\n\t\tauto bestPivot = std::abs(m(i, i));\n\t\tstd::size_t bestPivotIndex = i;\n\t\tfor(std::size_t j = i + 1; j < size; j++) {\n\t\t\tauto newPivot = std::abs(m(j, i));\n\t\t\tif(newPivot > bestPivot) {\n\t\t\t\tbestPivot = newPivot;\n\t\t\t\tbestPivotIndex = j;\n\t\t\t}\n\t\t}\n\n\t\tif(bestPivotIndex != i) {\n\t\t\tswapRows(m, bestPivotIndex, i);\n\t\t\tswapRows(v, bestPivotIndex, i);\n\t\t}\n\n\t\tauto pivot = m(i, i);\n\n\t\tfor(std::size_t j = i + 1; j < size; j++) {\n\t\t\tauto factor = m(j, i) / pivot;\n\n\t\t\tm(j, i) -= m(i, i) * factor;\n\n\t\t\tfor(std::size_t k = i + 1; k < size; k++) {\n\t\t\t\tm(j, k) -= m(i, k) * factor;\n\t\t\t}\n\t\t\tsubtractRowsFactorTimes(v, j, i, factor);\n\t\t}\n\t}\n\n\t// back substitution\n\tfor(signed long long i = size - 1; i >= 0; i--) {\n\t\tmultiplyRowBy(v, i, 1 / m(i, i));\n\t\tfor(signed long long j = i - 1; j >= 0; j--) {\n\t\t\tsubtractRowsFactorTimes(v, j, i, m(j, i));\n\t\t}\n\t}\n}\n};"
  },
  {
    "path": "Physics3D/math/linalg/mat.h",
    "content": "#pragma once\n\n#include \"vec.h\"\n#include <initializer_list>\n#include <assert.h>\n#include <stddef.h>\n#include <cstddef>\n#include <utility>\n#include <type_traits>\n\nnamespace P3D {\ntemplate<typename T, std::size_t Height, std::size_t Width>\nclass Matrix {\npublic:\n\tT data[Width * Height];\n\n\tinline constexpr T& operator()(std::size_t row, std::size_t col) {\n\t\tassert(row >= 0 && row < Height);\n\t\tassert(col >= 0 && col < Width);\n\n\t\treturn data[col * Height + row];\n\t}\n\n\tinline constexpr T operator()(std::size_t row, std::size_t col) const {\n\t\tassert(row >= 0 && row < Height);\n\t\tassert(col >= 0 && col < Width);\n\n\t\treturn data[col * Height + row];\n\t}\n\n\tMatrix() : data{} {}\n\n\t/*\n\t\tInitialize matrices like so\n\n\t\tMatrix<T, 3, 4>{\n\t\t\t1, 2, 3, 4,\n\t\t\t5, 6, 7, 8,\n\t\t\t9, 10, 11, 12\n\t\t};\n\t*/\n\tinline constexpr Matrix(std::initializer_list<T> list) : data{} {\n\t\tassert(list.size() == Width * Height);\n\t\tauto listIter = list.begin();\n\t\tfor (std::size_t row = 0; row < Height; row++) {\n\t\t\tfor (std::size_t col = 0; col < Width; col++) {\n\t\t\t\t(*this)(row, col) = *listIter;\n\t\t\t\t++listIter;\n\t\t\t}\n\t\t}\n\t}\n\n\tinline constexpr Matrix(const Matrix&) = default;\n\tinline constexpr Matrix& operator=(const Matrix&) = default;\n\tinline constexpr Matrix(Matrix&&) = default;\n\tinline constexpr Matrix& operator=(Matrix&&) = default;\n\n\ttemplate<typename OtherT>\n\tinline constexpr Matrix(const Matrix<OtherT, Height, Width>& m) : data{} {\n\t\tfor(std::size_t row = 0; row < Height; row++) {\n\t\t\tfor(std::size_t col = 0; col < Width; col++) {\n\t\t\t\t(*this)(row, col) = static_cast<T>(m(row, col));\n\t\t\t}\n\t\t}\n\t}\n\n\tinline static Matrix<T, Height, Width> fromRows(std::initializer_list<Vector<T, Width>> rows) {\n\t\tassert(rows.size() == Height);\n\t\tMatrix<T, Height, Width> result;\n\t\tauto rowIter = rows.begin();\n\t\tfor(std::size_t row = 0; row < Height; row++) {\n\t\t\tconst Vector<T, Width>& curRow = *rowIter;\n\t\t\tfor(std::size_t col = 0; col < Width; col++) {\n\t\t\t\tresult(row, col) = curRow[col];\n\t\t\t}\n\t\t\trowIter++;\n\t\t}\n\t\treturn result;\n\t}\n\n\tinline static Matrix<T, Height, Width> fromColumns(std::initializer_list<Vector<T, Height>> columns) {\n\t\tassert(columns.size() == Width);\n\t\tMatrix<T, Height, Width> result;\n\t\tauto colIter = columns.begin();\n\t\tfor(std::size_t col = 0; col < Width; col++) {\n\t\t\tconst Vector<T, Height>& curCol = *colIter;\n\t\t\tfor(std::size_t row = 0; row < Height; row++) {\n\t\t\t\tresult(row, col) = curCol[row];\n\t\t\t}\n\t\t\tcolIter++;\n\t\t}\n\t\treturn result;\n\t}\n\n\tconstexpr size_t width() const { return Width; }\n\tconstexpr size_t height() const { return Height; }\n\n\tvoid setDataRowMajor(const T* data) {\n\t\tfor (std::size_t row = 0; row < Height; row++) {\n\t\t\tfor (std::size_t col = 0; col < Width; col++) {\n\t\t\t\t(*this)(row, col) = data[row * Width + col];\n\t\t\t}\n\t\t}\n\t}\n\tvoid setDataColMajor(const T* data) {\n\t\tfor (std::size_t row = 0; row < Height; row++) {\n\t\t\tfor (std::size_t col = 0; col < Width; col++) {\n\t\t\t\t(*this)(row, col) = data[row + col * Height];\n\t\t\t}\n\t\t}\n\t}\n\n\tMatrix<T, Width, Height> transpose() const {\n\t\tMatrix<T, Width, Height> result;\n\t\tfor (std::size_t row = 0; row < Height; row++) {\n\t\t\tfor (std::size_t col = 0; col < Width; col++) {\n\t\t\t\tresult(col, row) = (*this)(row, col);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\ttemplate<std::size_t SubHeight, std::size_t SubWidth>\n\tMatrix<T, SubHeight, SubWidth> getSubMatrix(std::size_t topLeftRow, std::size_t topLeftCol) const {\n\t\tassert(topLeftRow >= 0 && topLeftRow + SubHeight <= Height);\n\t\tassert(topLeftCol >= 0 && topLeftCol + SubWidth <= Width);\n\n\t\tMatrix<T, SubHeight, SubWidth> result;\n\n\t\tfor (std::size_t row = 0; row < SubHeight; row++) {\n\t\t\tfor (std::size_t col = 0; col < SubWidth; col++) {\n\t\t\t\tresult(row, col) = (*this)(row+topLeftRow, col+topLeftCol);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\ttemplate<std::size_t SubHeight, std::size_t SubWidth>\n\tvoid setSubMatrix(const Matrix<T, SubHeight, SubWidth>& mat, std::size_t topLeftRow, std::size_t topLeftCol) {\n\t\tassert(topLeftRow >= 0 && topLeftRow + SubHeight <= Height);\n\t\tassert(topLeftCol >= 0 && topLeftCol + SubWidth <= Width);\n\n\t\tfor (std::size_t row = 0; row < SubHeight; row++) {\n\t\t\tfor (std::size_t col = 0; col < SubWidth; col++) {\n\t\t\t\t(*this)(row + topLeftRow, col + topLeftCol) = mat(row, col);\n\t\t\t}\n\t\t}\n\t}\n\n\tMatrix<T, Height, Width - 1> withoutCol(std::size_t colToDelete) const {\n\t\tassert(colToDelete >= 0 && colToDelete < Width);\n\n\t\tMatrix<T, Height, Width - 1> newMat;\n\t\tfor (std::size_t row = 0; row < Height; row++) {\n\t\t\tfor (std::size_t col = 0; col < colToDelete; col++) {\n\t\t\t\tnewMat(row, col) = (*this)(row, col);\n\t\t\t}\n\t\t\tfor (std::size_t col = colToDelete+1; col < Width; col++) {\n\t\t\t\tnewMat(row, col - 1) = (*this)(row, col);\n\t\t\t}\n\t\t}\n\t\treturn newMat;\n\t}\n\tMatrix<T, Height - 1, Width> withoutRow(std::size_t rowToDelete) const {\n\t\tassert(rowToDelete >= 0 && rowToDelete < Height);\n\n\t\tMatrix<T, Height - 1, Width> newMat;\n\t\tfor (std::size_t col = 0; col < Width; col++) {\n\t\t\tfor (std::size_t row = 0; row < rowToDelete; row++) {\n\t\t\t\tnewMat(row, col) = (*this)(row, col);\n\t\t\t}\n\t\t\tfor (std::size_t row = rowToDelete; row < Height - 1; row++) {\n\t\t\t\tnewMat(row, col) = (*this)(row + 1, col);\n\t\t\t}\n\t\t}\n\n\t\treturn newMat;\n\t}\n\tMatrix<T, Height - 1, Width - 1> withoutRowCol(std::size_t rowToDelete, std::size_t colToDelete) const {\n\t\tassert(colToDelete >= 0 && colToDelete < Width);\n\t\tassert(rowToDelete >= 0 && rowToDelete < Height);\n\n\t\tMatrix<T, Height - 1, Width - 1> newMat;\n\t\tfor (std::size_t row = 0; row < rowToDelete; row++) {\n\t\t\tfor (std::size_t col = 0; col < colToDelete; col++) {\n\t\t\t\tnewMat(row, col) = (*this)(row, col);\n\t\t\t}\n\t\t\tfor (std::size_t col = colToDelete + 1; col < Width; col++) {\n\t\t\t\tnewMat(row, col - 1) = (*this)(row, col);\n\t\t\t}\n\t\t}\n\t\tfor (std::size_t row = rowToDelete + 1; row < Height; row++) {\n\t\t\tfor (std::size_t col = 0; col < colToDelete; col++) {\n\t\t\t\tnewMat(row - 1, col) = (*this)(row, col);\n\t\t\t}\n\t\t\tfor (std::size_t col = colToDelete + 1; col < Width; col++) {\n\t\t\t\tnewMat(row - 1, col - 1) = (*this)(row, col);\n\t\t\t}\n\t\t}\n\t\treturn newMat;\n\t}\n\n\tVector<T, Width> getRow(std::size_t row) const {\n\t\tassert(row >= 0 && row < Height);\n\t\tVector<T, Width> result;\n\n\t\tfor(std::size_t i = 0; i < Width; i++) {\n\t\t\tresult[i] = (*this)(row, i);\n\t\t}\n\t\treturn result;\n\t}\n\n\tVector<T, Height> getCol(std::size_t col) const {\n\t\tassert(col >= 0 && col < Width);\n\t\tVector<T, Height> result;\n\n\t\tfor(std::size_t i = 0; i < Height; i++) {\n\t\t\tresult[i] = (*this)(i, col);\n\t\t}\n\t\treturn result;\n\t}\n\t\n\tvoid setRow(std::size_t row, const Vector<T, Width>& data) {\n\t\tassert(row >= 0 && row < Height);\n\n\t\tfor (std::size_t i = 0; i < Width; i++) {\n\t\t\t(*this)(row, i) = data[i];\n\t\t}\n\t}\n\tvoid setCol(std::size_t col, const Vector<T, Height>& data) {\n\t\tassert(col >= 0 && col < Width);\n\n\t\tfor (std::size_t i = 0; i < Height; i++) {\n\t\t\t(*this)(i, col) = data[i];\n\t\t}\n\t}\n\n\tstatic inline constexpr Matrix<T, Height, Width> ZEROS() {\n\t\tMatrix<T, Height, Width> mat;\n\t\tfor (std::size_t row = 0; row < Height; row++) {\n\t\t\tfor (std::size_t col = 0; col < Width; col++) {\n\t\t\t\tmat(row, col) = 0;\n\t\t\t}\n\t\t}\n\t\treturn mat;\n\t}\n\n\tstatic inline constexpr Matrix<T, Height, Width> IDENTITY() {\n\t\tMatrix<T, Height, Width> mat;\n\t\tfor (std::size_t row = 0; row < Height; row++) {\n\t\t\tfor (std::size_t col = 0; col < Width; col++) {\n\t\t\t\tmat(row, col) = (row == col) ? T(1) : T(0);\n\t\t\t}\n\t\t}\n\t\treturn mat;\n\t}\n\n\tstatic inline constexpr Matrix<T, Height, Width> DIAGONAL(const T& diagonalVal) {\n\t\tMatrix<T, Height, Width> mat;\n\t\tfor(std::size_t row = 0; row < Height; row++) {\n\t\t\tfor(std::size_t col = 0; col < Width; col++) {\n\t\t\t\tmat(row, col) = (row == col) ? diagonalVal : T(0);\n\t\t\t}\n\t\t}\n\t\treturn mat;\n\t}\n\n\tstatic Matrix<T, Height, Width> fromColMajorData(const T* data) {\n\t\tMatrix<T, Height, Width> mat;\n\t\tfor (std::size_t row = 0; row < Height; row++) {\n\t\t\tfor (std::size_t col = 0; col < Width; col++) {\n\t\t\t\tmat(row, col) = data[row + col * Height];\n\t\t\t}\n\t\t}\n\t\treturn mat;\n\t}\n\n\tstatic Matrix<T, Height, Width> fromRowMajorData(const T* data) {\n\t\tMatrix<T, Height, Width> mat;\n\t\tfor (std::size_t row = 0; row < Height; row++) {\n\t\t\tfor (std::size_t col = 0; col < Width; col++) {\n\t\t\t\tmat(row, col) = data[row * Width + col];\n\t\t\t}\n\t\t}\n\t\treturn mat;\n\t}\n\n\tvoid toColMajorData(T* buf) const {\n\t\tfor (std::size_t row = 0; row < Height; row++) {\n\t\t\tfor (std::size_t col = 0; col < Width; col++) {\n\t\t\t\tbuf[row + col * Height] = (*this)(row, col);\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid toRowMajorData(T* buf) const {\n\t\tfor (std::size_t row = 0; row < Height; row++) {\n\t\t\tfor (std::size_t col = 0; col < Width; col++) {\n\t\t\t\tbuf[row * Width + col] = (*this)(row, col);\n\t\t\t}\n\t\t}\n\t}\n};\n\n\n/*\n\tSymmetric matrix indexing\n\t0\n\t1 2\n\t3 4 5\n\t6 7 8 9\n\tA B C D E\n\n\t(3, 0) = 6\n\t(1, 0) = 1\n\t(2, 2) = 5\n\t(a, b) = a*(a+1)/2+b\n*/\n\ntemplate<typename T, std::size_t Size>\nclass SymmetricMatrix {\n\tT data[Size * (Size + 1) / 2];\npublic:\n\tinline constexpr T& operator()(std::size_t row, std::size_t col) {\n\t\tstd::size_t a = (row >= col) ? row : col; // max\n\t\tstd::size_t b = (row >= col) ? col : row; // min\n\n\t\tassert(b >= 0);\n\t\tassert(a < Size);\n\n\t\treturn data[a * (a + 1) / 2 + b];\n\t}\n\n\tinline constexpr T operator()(std::size_t row, std::size_t col) const {\n\t\tstd::size_t a = (row >= col) ? row : col; // max\n\t\tstd::size_t b = (row >= col) ? col : row; // min\n\n\t\tassert(b >= 0);\n\t\tassert(a < Size);\n\n\t\treturn data[a * (a + 1) / 2 + b];\n\t}\n\n\tSymmetricMatrix() : data{} {}\n\t/*\n\t\tInitialize symmetric matrices like so\n\n\t\tSymmetricMatrix<T, 4>{\n\t\t\t1,\n\t\t\t2, 3,\n\t\t\t4, 5, 6,\n\t\t\t7, 8, 9, 10\n\t\t};\n\t*/\n\tinline constexpr SymmetricMatrix(const std::initializer_list<T>& list) : data{} {\n\t\tassert(list.size() == Size * (Size + 1) / 2);\n\n\t\tauto listIter = list.begin();\n\t\tfor (std::size_t row = 0; row < Size; row++) {\n\t\t\tfor (std::size_t col = 0; col <= row; col++) {\n\t\t\t\t(*this)(row, col) = *listIter;\n\t\t\t\t++listIter;\n\t\t\t}\n\t\t}\n\t}\n\n\ttemplate<typename OtherT>\n\tinline constexpr SymmetricMatrix(const SymmetricMatrix<OtherT, Size>& m) : data{} {\n\t\tfor(std::size_t row = 0; row < Size; row++) {\n\t\t\tfor(std::size_t col = 0; col <= row; col++) {\n\t\t\t\t(*this)(row, col) = m(row, col);\n\t\t\t}\n\t\t}\n\t}\n\n\tconstexpr size_t width() const { return Size; }\n\tconstexpr size_t height() const { return Size; }\n\n\tstatic inline constexpr SymmetricMatrix<T, Size> ZEROS() {\n\t\tSymmetricMatrix<T, Size> mat;\n\t\tfor (std::size_t row = 0; row < Size; row++) {\n\t\t\tfor (std::size_t col = 0; col <= row; col++) {\n\t\t\t\tmat(row, col) = 0;\n\t\t\t}\n\t\t}\n\t\treturn mat;\n\t}\n\n\tstatic inline constexpr SymmetricMatrix<T, Size> IDENTITY() {\n\t\tSymmetricMatrix<T, Size> mat;\n\t\tfor (std::size_t row = 0; row < Size; row++) {\n\t\t\tfor (std::size_t col = 0; col <= row; col++) {\n\t\t\t\tmat(row, col) = (row == col) ? T(1) : T(0);\n\t\t\t}\n\t\t}\n\t\treturn mat;\n\t}\n\n\tstatic inline constexpr SymmetricMatrix<T, Size> DIAGONAL(const T& diagonalVal) {\n\t\tSymmetricMatrix<T, Size> mat;\n\t\tfor(std::size_t row = 0; row < Size; row++) {\n\t\t\tfor(std::size_t col = 0; col <= row; col++) {\n\t\t\t\tmat(row, col) = (row == col) ? diagonalVal : T(0);\n\t\t\t}\n\t\t}\n\t\treturn mat;\n\t}\n\n\toperator Matrix<T, Size, Size>() const {\n\t\tMatrix<T, Size, Size> mat;\n\t\tfor (std::size_t row = 0; row < Size; row++) {\n\t\t\tfor (std::size_t col = 0; col <= row; col++) {\n\t\t\t\tconst T& val = (*this)(row, col);\n\t\t\t\tmat(row, col) = val;\n\t\t\t\tmat(col, row) = val;\n\t\t\t}\n\t\t}\n\t\treturn mat;\n\t}\n\n\tVector<T, Size> getRow(std::size_t row) const {\n\t\tassert(row >= 0 && row < Size);\n\t\tVector<T, Size> result;\n\n\t\tfor(std::size_t i = 0; i < Size; i++) {\n\t\t\tresult[i] = (*this)(row, i);\n\t\t}\n\t\treturn result;\n\t}\n\n\tVector<T, Size> getCol(std::size_t col) const {\n\t\tassert(col >= 0 && col < Size);\n\t\tVector<T, Size> result;\n\n\t\tfor(std::size_t i = 0; i < Size; i++) {\n\t\t\tresult[i] = (*this)(i, col);\n\t\t}\n\t\treturn result;\n\t}\n};\n\ntemplate<typename T, std::size_t Size>\nclass DiagonalMatrix {\npublic:\n\tT data[Size];\n\t\n\tinline constexpr T& operator[](std::size_t index) { assert(index >= 0 && index < Size); return data[index]; }\n\tinline constexpr const T& operator[](std::size_t index) const { assert(index >= 0 && index < Size); return data[index]; }\n\n\tinline constexpr T operator()(std::size_t row, std::size_t col) const {\n\t\treturn (row == col) ? data[row] : static_cast<T>(0);\n\t}\n\n\tDiagonalMatrix() : data{} {\n\t\tfor(std::size_t i = 0; i < Size; i++) {\n\t\t\tdata[i] = T();\n\t\t}\n\t}\n\t/*\n\t\tInitialize diagonal matrices like so\n\n\t\tDiagonalMatrix<T, 4>{\n\t\t\t1,\n\t\t\t   2,\n\t\t\t      3,\n\t\t\t         4\n\t\t};\n\t*/\n\tinline constexpr DiagonalMatrix(const std::initializer_list<T>& list) : data{} {\n\t\tassert(list.size() == Size);\n\n\t\tauto listIter = list.begin();\n\t\tfor (std::size_t i = 0; i < Size; i++) {\n\t\t\t(*this)[i] = *listIter;\n\t\t\t++listIter;\n\t\t}\n\t}\n\n\tinline constexpr DiagonalMatrix(const T* list) : data{} {\n\t\tfor(std::size_t i = 0; i < Size; i++) {\n\t\t\t(*this)[i] = list[i];\n\t\t}\n\t}\n\n\ttemplate<typename OtherT>\n\tinline constexpr DiagonalMatrix(const DiagonalMatrix<OtherT, Size>& m) : data{} {\n\t\tfor(std::size_t i = 0; i < Size; i++) {\n\t\t\t(*this)[i] = static_cast<T>(m[i]);\n\t\t}\n\t}\n\n\tconstexpr size_t width() const { return Size; }\n\tconstexpr size_t height() const { return Size; }\n\n\tstatic inline constexpr DiagonalMatrix<T, Size> ZEROS() {\n\t\tDiagonalMatrix<T, Size> mat;\n\t\tfor (std::size_t i = 0; i < Size; i++) {\n\t\t\tmat[i] = 0;\n\t\t}\n\t\treturn mat;\n\t}\n\n\tstatic inline constexpr DiagonalMatrix<T, Size> IDENTITY() {\n\t\tDiagonalMatrix<T, Size> mat;\n\t\tfor (std::size_t i = 0; i < Size; i++) {\n\t\t\tmat[i] = T(1);\n\t\t}\n\t\treturn mat;\n\t}\n\n\tstatic inline constexpr DiagonalMatrix<T, Size> DIAGONAL(const T& diagonalVal) {\n\t\tDiagonalMatrix<T, Size> mat;\n\t\tfor(std::size_t i = 0; i < Size; i++) {\n\t\t\tmat[i] = diagonalVal;\n\t\t}\n\t\treturn mat;\n\t}\n\n\toperator SymmetricMatrix<T, Size>() const {\n\t\tSymmetricMatrix<T, Size> mat;\n\t\tfor (std::size_t row = 0; row < Size; row++) {\n\t\t\tfor (std::size_t col = 0; col < row; col++) {\n\t\t\t\tmat(row, col) = 0;\n\t\t\t}\n\t\t\tmat(row, row) = this->data[row];\n\t\t}\n\t\treturn mat;\n\t}\n\n\toperator Matrix<T, Size, Size>() const {\n\t\tMatrix<T, Size, Size> mat;\n\t\tfor (std::size_t row = 0; row < Size; row++) {\n\t\t\tfor (std::size_t col = 0; col < row; col++) {\n\t\t\t\tmat(row, col) = 0;\n\t\t\t\tmat(col, row) = 0;\n\t\t\t}\n\t\t\tmat(row, row) = (*this)[row];\n\t\t}\n\t\treturn mat;\n\t}\n};\n\ntemplate<typename T, std::size_t Size>\nusing SquareMatrix = Matrix<T, Size, Size>;\n\ntemplate<typename T, std::size_t Size>\nusing UnitaryMatrix = SquareMatrix<T, Size>;\n\n\n/*\n\t===== Predefined matrices\n*/\n\ntemplate<typename T, std::size_t Size>\nusing RotationMatrix = Matrix<T, Size, Size>;\n\n// Mat2\ntypedef Matrix<double, 2, 2>\tMat2;\ntypedef Matrix<float, 2, 2>\t\tMat2f;\ntypedef Matrix<long long, 2, 2>\tMat2l;\ntypedef Matrix<double, 2, 2>\tRotMat2;\n\n// Mat3\ntypedef Matrix<double, 3, 3>\tMat3;\ntypedef Matrix<float, 3, 3>\t\tMat3f;\ntypedef Matrix<long long, 3, 3>\tMat3l;\n\ntypedef SymmetricMatrix<double, 3>\t\tSymmetricMat3;\ntypedef SymmetricMatrix<float, 3>\t\tSymmetricMat3f;\ntypedef SymmetricMatrix<long long, 3>\tSymmetricMat3l;\n\ntypedef DiagonalMatrix<double, 3>\t\tDiagonalMat3;\ntypedef DiagonalMatrix<float, 3>\t\tDiagonalMat3f;\ntypedef DiagonalMatrix<long long, 3>\tDiagonalMat3l;\n\n// Mat4\ntypedef Matrix<double, 4, 4>\tMat4;\ntypedef Matrix<float, 4, 4>\t\tMat4f;\ntypedef Matrix<long long, 4, 4>\tMat4l;\n\n\n\n\n\n/*\n\t===== Operators =====\n*/\n\ntemplate<typename T, std::size_t Size>\nT det(const Matrix<T, Size, Size>& matrix) {\n\tT total = 0;\n\n\tMatrix<T, Size - 1, Size> allButFirstRow = matrix.withoutRow(0);\n\n\tfor (std::size_t col = 0; col < Size; col++) {\n\t\tT detOfMinor = det(allButFirstRow.withoutCol(col));\n\t\t\n\t\tT value = detOfMinor * matrix(0, col);\n\n\t\ttotal += (col % 2 == 0)? value : -value;\n\t}\n\treturn total;\n}\ntemplate<typename T>\nT det(const Matrix<T, 0, 0> & matrix) {\n\treturn 1; // for shits n giggles\n}\ntemplate<typename T>\nT det(const Matrix<T, 1, 1>& matrix) {\n\treturn matrix(0, 0);\n}\ntemplate<typename T>\nT det(const Matrix<T, 2, 2> & matrix) {\n\treturn matrix(0, 0) * matrix(1, 1) - matrix(0, 1) * matrix(1, 0);\n}\ntemplate<typename T, std::size_t Size>\nT det(const SymmetricMatrix<T, Size>& mat) {\n\treturn det(static_cast<Matrix<T, Size, Size>>(mat));\n}\ntemplate<typename T, std::size_t Size>\nT det(const DiagonalMatrix<T, Size>& mat) {\n\tT total = mat[0];\n\n\tfor (std::size_t i = 1; i < Size; i++) {\n\t\ttotal *= mat[i];\n\t}\n\treturn total;\n}\ntemplate<typename T>\nT det(const DiagonalMatrix<T, 0>& mat) {\n\treturn 1;\n}\n\ntemplate<typename T, std::size_t Height, std::size_t Width1, std::size_t Width2>\nMatrix<T, Height, Width1 + Width2> joinHorizontal(const Matrix<T, Height, Width1>& mat1, const Matrix<T, Height, Width2>& mat2) {\n\tMatrix<T, Height, Width1 + Width2> result;\n\tfor (std::size_t row = 0; row < Height; row++) {\n\t\tfor (std::size_t col = 0; col < Width1; col++) {\n\t\t\tresult(row, col) = mat1(row, col);\n\t\t}\n\t\tfor (std::size_t col = 0; col < Width2; col++) {\n\t\t\tresult(row, col + Width1) = mat2(row, col);\n\t\t}\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Width, std::size_t Height1, std::size_t Height2>\nMatrix<T, Height1 + Height2, Width> joinVertical(const Matrix<T, Height1, Width>& mat1, const Matrix<T, Height2, Width>& mat2) {\n\tMatrix<T, Height1 + Height2, Width> result;\n\tfor (std::size_t row = 0; row < Height1; row++) {\n\t\tfor (std::size_t col = 0; col < Width; col++) {\n\t\t\tresult(row, col) = mat1(row, col);\n\t\t}\n\t}\n\tfor (std::size_t row = 0; row < Height2; row++) {\n\t\tfor (std::size_t col = 0; col < Width; col++) {\n\t\t\tresult(row + Height1, col) = mat2(row, col);\n\t\t}\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Height1, std::size_t Height2, std::size_t Width1, std::size_t Width2>\nMatrix<T, Height1 + Height2, Width1 + Width2> join(const Matrix<T, Height1, Width1>& topLeft, const Matrix<T, Height1, Width2>& topRight, \n\t\t\t\t\t\t\t\t\t\t\t\t   const Matrix<T, Height2, Width1>& botLeft, const Matrix<T, Height2, Width2>& botRight) {\n\n\tMatrix<T, Height1 + Height2, Width1 + Width2> result;\n\tfor(std::size_t row = 0; row < Height1; row++) {\n\t\tfor(std::size_t col = 0; col < Width1; col++) {\n\t\t\tresult(row, col) = topLeft(row, col);\n\t\t}\n\t\tfor(std::size_t col = 0; col < Width2; col++) {\n\t\t\tresult(row, col + Width1) = topRight(row, col);\n\t\t}\n\t}\n\tfor(std::size_t row = 0; row < Height2; row++) {\n\t\tfor(std::size_t col = 0; col < Width1; col++) {\n\t\t\tresult(row + Height1, col) = botLeft(row, col);\n\t\t}\n\t\tfor(std::size_t col = 0; col < Width2; col++) {\n\t\t\tresult(row + Height1, col + Width1) = botRight(row, col);\n\t\t}\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Height, std::size_t Width>\nMatrix<T, Height + 1, Width + 1> join(const Matrix<T, Height, Width> & topLeft, const Vector<T, Height> & topRight, const Vector<T, Width> & botLeft, const T & botRight) {\n\tMatrix<T, Height + 1, Width + 1> result;\n\tfor(std::size_t row = 0; row < Height; row++) {\n\t\tfor(std::size_t col = 0; col < Width; col++) {\n\t\t\tresult(row, col) = topLeft(row, col);\n\t\t}\n\t\tresult(row, Width) = topRight[row];\n\t}\n\tfor(std::size_t col = 0; col < Width; col++) {\n\t\tresult(Height, col) = botLeft[col];\n\t}\n\tresult(Height, Width) = botRight;\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Height1, std::size_t Height2, std::size_t Width1, std::size_t Width2>\nMatrix<T, Height1 + Height2, Width1 + Width2> joinDiagonal(const Matrix<T, Height1, Width1>& topLeft, const Matrix<T, Height1, Width2>& botRight) {\n\n\tMatrix<T, Height1 + Height2, Width1 + Width2> result;\n\tfor(std::size_t row = 0; row < Height1; row++) {\n\t\tfor(std::size_t col = 0; col < Width1; col++) {\n\t\t\tresult(row, col) = topLeft(row, col);\n\t\t}\n\t\tfor(std::size_t col = 0; col < Width2; col++) {\n\t\t\tresult(row, col + Width1) = 0;\n\t\t}\n\t}\n\tfor(std::size_t row = 0; row < Height2; row++) {\n\t\tfor(std::size_t col = 0; col < Width1; col++) {\n\t\t\tresult(row + Height1, col) = 0;\n\t\t}\n\t\tfor(std::size_t col = 0; col < Width2; col++) {\n\t\t\tresult(row + Height1, col + Width1) = botRight(row, col);\n\t\t}\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Height, std::size_t Width>\nMatrix<T, Height + 1, Width + 1> joinDiagonal(const Matrix<T, Height, Width>& topLeft, const T& botRight) {\n\tMatrix<T, Height + 1, Width + 1> result;\n\tfor(std::size_t row = 0; row < Height; row++) {\n\t\tfor(std::size_t col = 0; col < Width; col++) {\n\t\t\tresult(row, col) = topLeft(row, col);\n\t\t}\n\t\tresult(row, Width) = 0;\n\t}\n\tfor(std::size_t col = 0; col < Width; col++) {\n\t\tresult(Height, col) = 0;\n\t}\n\tresult(Height, Width) = botRight;\n\treturn result;\n}\n\n/*\n\t===== Everything standard matrix =====\n*/\n\ntemplate<typename T, std::size_t Height, std::size_t Width>\nMatrix<T, Height, Width> operator+(const Matrix<T, Height, Width>& m1, const Matrix<T, Height, Width>& m2) {\n\tMatrix<T, Height, Width> result;\n\n\tfor (std::size_t row = 0; row < Height; row++) {\n\t\tfor (std::size_t col = 0; col < Width; col++) {\n\t\t\tresult(row, col) = m1(row, col) + m2(row, col);\n\t\t}\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Height, std::size_t Width>\nMatrix<T, Height, Width> operator-(const Matrix<T, Height, Width>& m1, const Matrix<T, Height, Width>& m2) {\n\tMatrix<T, Height, Width> result;\n\n\tfor (std::size_t row = 0; row < Height; row++) {\n\t\tfor (std::size_t col = 0; col < Width; col++) {\n\t\t\tresult(row, col) = m1(row, col) - m2(row, col);\n\t\t}\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Height, std::size_t Width>\nMatrix<T, Height, Width> operator-(const Matrix<T, Height, Width>& m) {\n\tMatrix<T, Height, Width> result;\n\n\tfor (std::size_t row = 0; row < Height; row++) {\n\t\tfor (std::size_t col = 0; col < Width; col++) {\n\t\t\tresult(row, col) = -m(row, col);\n\t\t}\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Height, std::size_t Width>\nVector<T, Height> operator*(const Matrix<T, Height, Width>& m, const Vector<T, Width>& v) {\n\tVector<T, Height> result;\n\n\tfor (std::size_t row = 0; row < Height; row++) {\n\t\tT sum = m(row, 0) * v[0];\n\t\tfor (std::size_t col = 1; col < Width; col++) {\n\t\t\tsum += m(row, col) * v[col];\n\t\t}\n\t\tresult[row] = sum;\n\t}\n\treturn result;\n}\n\n// Do Not Remove, actually improves performance on VC++\ntemplate<typename T>\nMatrix<T, 3, 3> operator*(const Matrix<T, 3, 3>& m, const Matrix<T, 3, 3> & m2) {\n\tMatrix<T, 3, 3> result;\n\tresult.data[0] = m.data[0] * m2.data[0] + m.data[3] * m2.data[1] + m.data[6] * m2.data[2];\n\tresult.data[1] = m.data[1] * m2.data[0] + m.data[4] * m2.data[1] + m.data[7] * m2.data[2];\n\tresult.data[2] = m.data[2] * m2.data[0] + m.data[5] * m2.data[1] + m.data[8] * m2.data[2];\n\n\tresult.data[3] = m.data[0] * m2.data[3] + m.data[3] * m2.data[4] + m.data[6] * m2.data[5];\n\tresult.data[4] = m.data[1] * m2.data[3] + m.data[4] * m2.data[4] + m.data[7] * m2.data[5];\n\tresult.data[5] = m.data[2] * m2.data[3] + m.data[5] * m2.data[4] + m.data[8] * m2.data[5];\n\t\n\tresult.data[6] = m.data[0] * m2.data[6] + m.data[3] * m2.data[7] + m.data[6] * m2.data[8];\n\tresult.data[7] = m.data[1] * m2.data[6] + m.data[4] * m2.data[7] + m.data[7] * m2.data[8];\n\tresult.data[8] = m.data[2] * m2.data[6] + m.data[5] * m2.data[7] + m.data[8] * m2.data[8];\n\n\treturn result;\n}\n\n// Do Not Remove, actually improves performance on VC++\ntemplate<typename T>\nVector<T, 3> operator*(const Matrix<T, 3, 3>& m, const Vector<T, 3>& v) {\n\tT x = m.data[0] * v[0] + m.data[3] * v[1] + m.data[6] * v[2];\n\tT y = m.data[1] * v[0] + m.data[4] * v[1] + m.data[7] * v[2];\n\tT z = m.data[2] * v[0] + m.data[5] * v[1] + m.data[8] * v[2];\n\n\treturn Vector<T, 3>(x, y, z);\n}\n\ntemplate<typename T, std::size_t ResultHeight, std::size_t ResultWidth, std::size_t IntermediateSize>\nMatrix<T, ResultHeight, ResultWidth> operator*(const Matrix<T, ResultHeight, IntermediateSize>& m1, const Matrix<T, IntermediateSize, ResultWidth>& m2) {\n\tMatrix<T, ResultHeight, ResultWidth> result;\n\n\tfor (std::size_t col = 0; col < ResultWidth; col++) {\n\t\tfor (std::size_t row = 0; row < ResultHeight; row++) {\n\t\t\tT sum = m1(row, 0) * m2(0, col);\n\t\t\tfor (std::size_t i = 1; i < IntermediateSize; i++) {\n\t\t\t\tsum += m1(row, i) * m2(i, col);\n\t\t\t}\n\t\t\tresult(row, col) = sum;\n\t\t}\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Height, std::size_t Width>\nMatrix<T, Height, Width> operator*(const Matrix<T, Height, Width>& m1, const T& factor) {\n\tMatrix<T, Height, Width> result;\n\n\tfor (std::size_t row = 0; row < Height; row++) {\n\t\tfor (std::size_t col = 0; col < Width; col++) {\n\t\t\tresult(row, col) = m1(row, col) * factor;\n\t\t}\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Height, std::size_t Width>\nMatrix<T, Height, Width> operator*(const T& factor, const Matrix<T, Height, Width>& m1) {\n\tMatrix<T, Height, Width> result;\n\n\tfor (std::size_t row = 0; row < Height; row++) {\n\t\tfor (std::size_t col = 0; col < Width; col++) {\n\t\t\tresult(row, col) = factor * m1(row, col);\n\t\t}\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Height, std::size_t Width>\nMatrix<T, Height, Width> operator/(const Matrix<T, Height, Width>& m1, const T& factor) {\n\tMatrix<T, Height, Width> result;\n\n\tfor (std::size_t row = 0; row < Height; row++) {\n\t\tfor (std::size_t col = 0; col < Width; col++) {\n\t\t\tresult(row, col) = m1(row, col) / factor;\n\t\t}\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Height, std::size_t Width>\nMatrix<T, Height, Width>& operator+=(Matrix<T, Height, Width>& m1, const Matrix<T, Height, Width>& m2) {\n\tfor (std::size_t row = 0; row < Height; row++) {\n\t\tfor (std::size_t col = 0; col < Width; col++) {\n\t\t\tm1(row, col) += m2(row, col);\n\t\t}\n\t}\n\treturn m1;\n}\ntemplate<typename T, std::size_t Height, std::size_t Width>\nMatrix<T, Height, Width>& operator-=(Matrix<T, Height, Width>& m1, const Matrix<T, Height, Width>& m2) {\n\tfor (std::size_t row = 0; row < Height; row++) {\n\t\tfor (std::size_t col = 0; col < Width; col++) {\n\t\t\tm1(row, col) -= m2(row, col);\n\t\t}\n\t}\n\treturn m1;\n}\ntemplate<typename T, std::size_t Height, std::size_t Width>\nMatrix<T, Height, Width>& operator*=(Matrix<T, Height, Width>& mat, const T& factor) {\n\tfor (std::size_t row = 0; row < Height; row++) {\n\t\tfor (std::size_t col = 0; col < Width; col++) {\n\t\t\tmat(row, col) *= factor;\n\t\t}\n\t}\n\treturn mat;\n}\ntemplate<typename T, std::size_t Height, std::size_t Width>\nMatrix<T, Height, Width>& operator/=(Matrix<T, Height, Width>& mat, const T& factor) {\n\tfor (std::size_t row = 0; row < Height; row++) {\n\t\tfor (std::size_t col = 0; col < Width; col++) {\n\t\t\tmat(row, col) /= factor;\n\t\t}\n\t}\n\treturn mat;\n}\n\ntemplate<typename T, std::size_t Size>\nMatrix<T, Size, Size> operator~(const Matrix<T, Size, Size>& matrix) {\n\tMatrix<T, Size, Size> result;\n\n\tT d = det(matrix);\n\n\tfor (std::size_t row = 0; row < Size; row++) {\n\t\tfor (std::size_t col = 0; col < Size; col++) {\n\t\t\tMatrix<T, Size - 1, Size - 1> tmp = matrix.withoutRowCol(row, col);\n\t\t\tT coFactor = det(tmp);\n\n\t\t\tT value = coFactor / d;\n\n\t\t\t// transpose the coFactors here, therefore indexing (col, row)\n\t\t\tresult(col, row) = ((row + col) % 2 == 0) ? value : -value;\n\t\t}\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Size>\nMatrix<T, Size, Size> inverse(const Matrix<T, Size, Size>& matrix) {\n\treturn ~matrix;\n}\n\n/*\n\t===== Everything symmetric matrix ===== \n*/\n\n\ntemplate<typename T, std::size_t Size>\nSymmetricMatrix<T, Size> operator+(const SymmetricMatrix<T, Size>& m1, const SymmetricMatrix<T, Size>& m2) {\n\tSymmetricMatrix<T, Size> result;\n\n\tfor (std::size_t row = 0; row < Size; row++) {\n\t\tfor (std::size_t col = 0; col <= row; col++) {\n\t\t\tresult(row, col) = m1(row, col) + m2(row, col);\n\t\t}\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Size>\nSymmetricMatrix<T, Size> operator-(const SymmetricMatrix<T, Size>& m1, const SymmetricMatrix<T, Size>& m2) {\n\tSymmetricMatrix<T, Size> result;\n\n\tfor (std::size_t row = 0; row < Size; row++) {\n\t\tfor (std::size_t col = 0; col <= row; col++) {\n\t\t\tresult(row, col) = m1(row, col) - m2(row, col);\n\t\t}\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Size>\nSymmetricMatrix<T, Size> operator-(const SymmetricMatrix<T, Size>& m) {\n\tSymmetricMatrix<T, Size> result;\n\n\tfor (std::size_t row = 0; row < Size; row++) {\n\t\tfor (std::size_t col = 0; col <= row; col++) {\n\t\t\tresult(row, col) = -m(row, col);\n\t\t}\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Size>\nVector<T, Size> operator*(const SymmetricMatrix<T, Size>& m, const Vector<T, Size>& v) {\n\tVector<T, Size> result;\n\n\tfor (std::size_t row = 0; row < Size; row++) {\n\t\tT sum = m(row, 0) * v[0];\n\t\tfor (std::size_t col = 1; col < Size; col++) {\n\t\t\tsum += m(row, col) * v[col];\n\t\t}\n\t\tresult[row] = sum;\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Size>\nSymmetricMatrix<T, Size> operator*(const SymmetricMatrix<T, Size>& m1, const SymmetricMatrix<T, Size>& m2) {\n\tSymmetricMatrix<T, Size> result;\n\n\tfor (std::size_t col = 0; col < Size; col++) {\n\t\tfor (std::size_t row = 0; row <= col; row++) {\n\t\t\tT sum = m1(row, 0) * m2(0, col);\n\t\t\tfor (std::size_t i = 1; i < Size; i++) {\n\t\t\t\tsum += m1(row, i) * m2(i, col);\n\t\t\t}\n\t\t\tresult(row, col) = sum;\n\t\t}\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Size>\nSymmetricMatrix<T, Size> operator*(const SymmetricMatrix<T, Size>& m1, const T& factor) {\n\tSymmetricMatrix<T, Size> result;\n\n\tfor (std::size_t row = 0; row < Size; row++) {\n\t\tfor (std::size_t col = 0; col <= row; col++) {\n\t\t\tresult(row, col) = m1(row, col) * factor;\n\t\t}\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Size>\nSymmetricMatrix<T, Size> operator*(const T& factor, const SymmetricMatrix<T, Size>& m1) {\n\tSymmetricMatrix<T, Size> result;\n\n\tfor (std::size_t row = 0; row < Size; row++) {\n\t\tfor (std::size_t col = 0; col <= row; col++) {\n\t\t\tresult(row, col) = factor * m1(row, col);\n\t\t}\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Size>\nSymmetricMatrix<T, Size> operator/(const SymmetricMatrix<T, Size>& m1, const T& factor) {\n\tSymmetricMatrix<T, Size> result;\n\n\tfor (std::size_t row = 0; row < Size; row++) {\n\t\tfor (std::size_t col = 0; col <= row; col++) {\n\t\t\tresult(row, col) = m1(row, col) / factor;\n\t\t}\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Size>\nSymmetricMatrix<T, Size>& operator+=(SymmetricMatrix<T, Size>& m1, const SymmetricMatrix<T, Size>& m2) {\n\tfor (std::size_t row = 0; row < Size; row++) {\n\t\tfor (std::size_t col = 0; col <= row; col++) {\n\t\t\tm1(row, col) += m2(row, col);\n\t\t}\n\t}\n\treturn m1;\n}\ntemplate<typename T, std::size_t Size>\nSymmetricMatrix<T, Size>& operator-=(SymmetricMatrix<T, Size>& m1, const SymmetricMatrix<T, Size>& m2) {\n\tfor (std::size_t row = 0; row < Size; row++) {\n\t\tfor (std::size_t col = 0; col <= row; col++) {\n\t\t\tm1(row, col) -= m2(row, col);\n\t\t}\n\t}\n\treturn m1;\n}\ntemplate<typename T, std::size_t Size>\nSymmetricMatrix<T, Size>& operator*=(SymmetricMatrix<T, Size>& mat, const T& factor) {\n\tfor (std::size_t row = 0; row < Size; row++) {\n\t\tfor (std::size_t col = 0; col <= row; col++) {\n\t\t\tmat(row, col) *= factor;\n\t\t}\n\t}\n\treturn mat;\n}\ntemplate<typename T, std::size_t Size>\nSymmetricMatrix<T, Size>& operator/=(SymmetricMatrix<T, Size>& mat, const T& factor) {\n\tfor (std::size_t row = 0; row < Size; row++) {\n\t\tfor (std::size_t col = 0; col <= row; col++) {\n\t\t\tmat(row, col) /= factor;\n\t\t}\n\t}\n\treturn mat;\n}\n\ntemplate<typename T, std::size_t Size>\nSymmetricMatrix<T, Size> operator~(const SymmetricMatrix<T, Size>& matrix) {\n\tSymmetricMatrix<T, Size> result;\n\n\tT d = det(matrix);\n\n\tfor (std::size_t row = 0; row < Size; row++) {\n\t\tfor (std::size_t col = 0; col <= row; col++) {\n\t\t\tMatrix<T, Size - 1, Size - 1> tmp = static_cast<Matrix<T, Size, Size>>(matrix).withoutRowCol(row, col);\n\t\t\tT coFactor = det(tmp);\n\n\t\t\tT value = coFactor / d;\n\n\t\t\t// transpose the coFactors here, therefore indexing (col, row)\n\t\t\tresult(col, row) = ((row + col) % 2 == 0) ? value : -value;\n\t\t}\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Size>\nSymmetricMatrix<T, Size> inverse(const SymmetricMatrix<T, Size>& matrix) {\n\treturn ~matrix;\n}\n\n/*\n\t===== Everything Diagonal Matrix =====\n*/\n\ntemplate<typename T, std::size_t Size>\nDiagonalMatrix<T, Size> operator+(const DiagonalMatrix<T, Size>& m1, const DiagonalMatrix<T, Size>& m2) {\n\tDiagonalMatrix<T, Size> result;\n\n\tfor (std::size_t i = 0; i < Size; i++) {\n\t\tresult[i] = m1[i] + m2[i];\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Size>\nDiagonalMatrix<T, Size> operator-(const DiagonalMatrix<T, Size>& m1, const DiagonalMatrix<T, Size>& m2) {\n\tDiagonalMatrix<T, Size> result;\n\n\tfor (std::size_t i = 0; i < Size; i++) {\n\t\tresult[i] = m1[i] - m2[i];\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Size>\nDiagonalMatrix<T, Size> operator-(const DiagonalMatrix<T, Size>& m) {\n\tDiagonalMatrix<T, Size> result;\n\n\tfor (std::size_t i = 0; i < Size; i++) {\n\t\tresult[i] = -m[i];\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Size>\nVector<T, Size> operator*(const DiagonalMatrix<T, Size>& m, const Vector<T, Size>& v) {\n\tVector<T, Size> result;\n\n\tfor (std::size_t i = 0; i < Size; i++) {\n\t\tresult[i] = m[i] * v[i];\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Size>\nDiagonalMatrix<T, Size> operator*(const DiagonalMatrix<T, Size>& m1, const DiagonalMatrix<T, Size>& m2) {\n\tDiagonalMatrix<T, Size> result;\n\n\tfor (std::size_t i = 0; i < Size; i++) {\n\t\tresult[i] = m1[i] * m2[i];\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Size>\nDiagonalMatrix<T, Size> operator*(const DiagonalMatrix<T, Size>& m1, const T& factor) {\n\tDiagonalMatrix<T, Size> result;\n\n\tfor (std::size_t i = 0; i < Size; i++) {\n\t\t\tresult[i] = m1[i] * factor;\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Size>\nDiagonalMatrix<T, Size> operator*(const T& factor, const DiagonalMatrix<T, Size>& m1) {\n\tDiagonalMatrix<T, Size> result;\n\n\tfor (std::size_t i = 0; i < Size; i++) {\n\t\tresult[i] = factor * m1[i];\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Size>\nDiagonalMatrix<T, Size> operator/(const DiagonalMatrix<T, Size>& m1, const T& factor) {\n\tDiagonalMatrix<T, Size> result;\n\n\tfor (std::size_t i = 0; i < Size; i++) {\n\t\tresult[i] = m1[i] / factor;\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Size>\nDiagonalMatrix<T, Size>& operator+=(DiagonalMatrix<T, Size>& m1, const DiagonalMatrix<T, Size>& m2) {\n\tfor (std::size_t i = 0; i < Size; i++) {\n\t\tm1[i] += m2[i];\n\t}\n\treturn m1;\n}\ntemplate<typename T, std::size_t Size>\nDiagonalMatrix<T, Size>& operator-=(DiagonalMatrix<T, Size>& m1, const DiagonalMatrix<T, Size>& m2) {\n\tfor (std::size_t i = 0; i < Size; i++) {\n\t\tm1[i] -= m2[i];\n\t}\n\treturn m1;\n}\ntemplate<typename T, std::size_t Size>\nDiagonalMatrix<T, Size>& operator*=(DiagonalMatrix<T, Size>& mat, const T& factor) {\n\tfor (std::size_t i = 0; i < Size; i++) {\n\t\tmat[i] *= factor;\n\t}\n\treturn mat;\n}\ntemplate<typename T, std::size_t Size>\nDiagonalMatrix<T, Size>& operator*=(DiagonalMatrix<T, Size>& mat, const DiagonalMatrix<T, Size>& other) {\n\tfor (std::size_t i = 0; i < Size; i++) {\n\t\tmat[i] *= other[i];\n\t}\n\treturn mat;\n}\ntemplate<typename T, std::size_t Size>\nDiagonalMatrix<T, Size>& operator/=(DiagonalMatrix<T, Size>& mat, const T& factor) {\n\tfor (std::size_t i = 0; i < Size; i++) {\n\t\tmat[i] /= factor;\n\t}\n\treturn mat;\n}\n\ntemplate<typename T, std::size_t Size>\nDiagonalMatrix<T, Size> operator~(const DiagonalMatrix<T, Size>& matrix) {\n\tDiagonalMatrix<T, Size> result;\n\n\tfor (std::size_t i = 0; i < Size; i++) {\n\t\tresult[i] = 1 / matrix[i];\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Size>\nDiagonalMatrix<T, Size> inverse(const DiagonalMatrix<T, Size>& matrix) {\n\treturn ~matrix;\n}\n\n/*\n\t===== Compatibility between the matrix types =====\n*/\n\ntemplate<typename T, std::size_t Size>\nSymmetricMatrix<T, Size> operator*(const SymmetricMatrix<T, Size>& m1, const DiagonalMatrix<T, Size>& m2) {\n\treturn m1 * static_cast<SymmetricMatrix<T, Size>>(m2);\n}\ntemplate<typename T, std::size_t Size>\nSymmetricMatrix<T, Size> operator*(const DiagonalMatrix<T, Size>& m1, const SymmetricMatrix<T, Size>& m2) {\n\treturn static_cast<SymmetricMatrix<T, Size>>(m1) * m2;\n}\n\ntemplate<typename T, std::size_t Size, std::size_t Width>\nMatrix<T, Size, Width> operator*(const SymmetricMatrix<T, Size>& m1, const Matrix<T, Size, Width>& m2) {\n\treturn static_cast<Matrix<T, Size, Size>>(m1)* m2;\n}\ntemplate<typename T, std::size_t Size, std::size_t Height>\nMatrix<T, Height, Size> operator*(const Matrix<T, Height, Size>& m1, const SymmetricMatrix<T, Size>& m2) {\n\treturn m1 * static_cast<Matrix<T, Size, Size>>(m2);\n}\n\ntemplate<typename T, std::size_t Size, std::size_t Width>\nMatrix<T, Size, Width> operator*(const DiagonalMatrix<T, Size>& m1, const Matrix<T, Size, Width>& m2) {\n\treturn static_cast<Matrix<T, Size, Size>>(m1)* m2;\n}\ntemplate<typename T, std::size_t Size, std::size_t Height>\nMatrix<T, Height, Size> operator*(const Matrix<T, Height, Size>& m1, const DiagonalMatrix<T, Size>& m2) {\n\treturn m1 * static_cast<Matrix<T, Size, Size>>(m2);\n}\n\n\n/*\n\t===== Other functions =====\n*/\n\ntemplate<typename T, std::size_t Height, std::size_t Width>\nMatrix<T, Height, Width> outer(const Vector<T, Height>& v1, const Vector<T, Width>& v2) {\n\tMatrix<T, Height, Width> result;\n\n\tfor (std::size_t row = 0; row < Height; row++) {\n\t\tfor (std::size_t col = 0; col < Width; col++) {\n\t\t\tresult(row, col) = v1[row] * v2[col];\n\t\t}\n\t}\n\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Size>\nSymmetricMatrix<T, Size> selfOuter(const Vector<T, Size>& v) {\n\tSymmetricMatrix<T, Size> result;\n\n\tfor (std::size_t row = 0; row < Size; row++) {\n\t\tfor (std::size_t col = 0; col <= row; col++) {\n\t\t\tresult(row, col) = v[row] * v[col];\n\t\t}\n\t}\n\treturn result;\n}\n\n\ntemplate<typename T, std::size_t Size>\nVector<T, Size> toVector(const Matrix<T, Size, 1>& mat) {\n\tVector<T, Size> result;\n\tfor(std::size_t i = 0; i < Size; i++) {\n\t\tresult[i] = mat(i, 0);\n\t}\n\treturn result;\n}\ntemplate<typename T, std::size_t Size>\nVector<T, Size> toVector(const Matrix<T, 1, Size>& mat) {\n\tVector<T, Size> result;\n\tfor(std::size_t i = 0; i < Size; i++) {\n\t\tresult[i] = mat(0, i);\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Size>\nMatrix<T, Size, 1> toRowMatrix(const Vector<T, Size>& vec) {\n\tMatrix<T, Size, 1> result;\n\tfor(std::size_t i = 0; i < Size; i++) {\n\t\tresult(0, i) = vec[i];\n\t}\n\treturn result;\n}\ntemplate<typename T, std::size_t Size>\nMatrix<T, 1, Size> toColMatrix(const Vector<T, Size>& vec) {\n\tMatrix<T, 1, Size> result;\n\tfor(std::size_t i = 0; i < Size; i++) {\n\t\tresult(i, 0) = vec[i];\n\t}\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Size>\nSymmetricMatrix<T, Size> makeSymmetric(const SquareMatrix<T, Size>& mat) {\n\tSymmetricMatrix<T, Size> result;\n\tfor(std::size_t row = 0; row < Size; row++) {\n\t\tfor(std::size_t col = 0; col <= row; col++) {\n\t\t\tresult(row, col) = mat(row, col);\n\t\t\tassert(std::abs(mat(row, col) - mat(col, row)) < 1E-6);\n\t\t}\n\t}\n\treturn result;\n}\n\n/*\n\tComputes mat + mat.transpose()\n*/\ntemplate<typename T, std::size_t Size>\nSymmetricMatrix<T, Size> addTransposed(const SquareMatrix<T, Size>& mat) {\n\tSymmetricMatrix<T, Size> result;\n\tfor(std::size_t resultRow = 0; resultRow < Size; resultRow++) {\n\t\tfor(std::size_t resultCol = 0; resultCol <= resultRow; resultCol++) {\n\t\t\tresult(resultRow, resultCol) = mat(resultRow, resultCol) + mat(resultCol, resultRow);\n\t\t}\n\t}\n\treturn result;\n}\n\n/*\n\tcomputes \n\tm * sym * m.transpose()\n*/\ntemplate<typename T, std::size_t Size>\nSymmetricMatrix<T, Size> mulSymmetricLeftRightTranspose(const SymmetricMatrix<T, Size>& sym, const SquareMatrix<T, Size>& m) {\n\tSquareMatrix<T, Size> symResult = m * sym * m.transpose();\n\treturn makeSymmetric(symResult);\n}\n/*\n\tcomputes\n\tm.transpose() * sym * m\n*/\ntemplate<typename T, std::size_t Size>\nSymmetricMatrix<T, Size> mulSymmetricLeftTransposeRight(const SymmetricMatrix<T, Size>& sym, const SquareMatrix<T, Size>& m) {\n\tSquareMatrix<T, Size> symResult = m.transpose() * sym * m;\n\treturn makeSymmetric(symResult);\n}\n\n\n/*\n\tGeneric matrix functions\n*/\n\n\n\ntemplate<size_t R, size_t C, typename MatrixT>\nauto getSubMatrix(const MatrixT& matrix, size_t rowOffset = 0, size_t colOffset = 0) -> Matrix<typename std::remove_reference<decltype(matrix(0,0))>::type, R, C> {\n\tassert(rowOffset >= 0 && rowOffset + R <= matrix.height() && colOffset >= 0 && colOffset + C <= matrix.width());\n\n\tMatrix<decltype(matrix(0, 0)), R, C> result;\n\n\tfor(size_t r = 0; r < R; r++) {\n\t\tfor(size_t c = 0; c < C; c++) {\n\t\t\tresult(r, c) = matrix(r + rowOffset, c + colOffset);\n\t\t}\n\t}\n\n\treturn result;\n}\n\ntemplate<size_t R, size_t C, typename MatrixT>\nvoid setSubMatrix(MatrixT& matrix, const Matrix<typename std::remove_reference<decltype(std::declval<MatrixT>()(0,0))>::type, R, C>& value, size_t rowOffset = 0, size_t colOffset = 0) {\n\tassert(rowOffset >= 0 && rowOffset + value.height() <= matrix.height() && colOffset >= 0 && colOffset + value.width() <= matrix.width());\n\tfor(size_t r = 0; r < R; r++) {\n\t\tfor(size_t c = 0; c < C; c++) {\n\t\t\tmatrix(r + rowOffset, c + colOffset) = value(r, c);\n\t\t}\n\t}\n}\n\ntemplate<size_t Size, typename MatrixT>\nvoid setSubMatrix(MatrixT& matrix, const SymmetricMatrix<typename std::remove_reference<decltype(std::declval<MatrixT>()(0, 0))>::type, Size>& value, size_t rowOffset = 0, size_t colOffset = 0) {\n\tassert(rowOffset >= 0 && rowOffset + value.height() <= matrix.height() && colOffset >= 0 && colOffset + value.width() <= matrix.width());\n\tfor(size_t r = 0; r < Size; r++) {\n\t\tfor(size_t c = 0; c < r; c++) {\n\t\t\tconst auto& v = value(r, c);\n\t\t\tmatrix(r + rowOffset, c + colOffset) = v;\n\t\t\tmatrix(c + colOffset, r + rowOffset) = v;\n\t\t}\n\t\tmatrix(r + rowOffset, r + colOffset) = value(r, r);\n\t}\n}\n\ntemplate<size_t Size, typename MatrixT>\nvoid setSubMatrix(MatrixT& matrix, const DiagonalMatrix<typename std::remove_reference<decltype(std::declval<MatrixT>()(0, 0))>::type, Size>& value, size_t rowOffset = 0, size_t colOffset = 0) {\n\tassert(rowOffset >= 0 && rowOffset + value.height() <= matrix.height() && colOffset >= 0 && colOffset + value.width() <= matrix.width());\n\tfor(size_t r = 0; r < Size; r++) {\n\t\tfor(size_t c = 0; c < Size; c++) {\n\t\t\tmatrix(r + rowOffset, c + colOffset) = (r == c)? value[r] : 0;\n\t\t}\n\t}\n}\n\n};\n\n\n\n\n"
  },
  {
    "path": "Physics3D/math/linalg/quat.h",
    "content": "#pragma once\n\n#include <stddef.h>\n#include <cmath>\n#include \"vec.h\"\n\nnamespace P3D {\ntemplate<typename T>\nstruct Quaternion {\n\n\tT w;\n\tunion {\n\t\tstruct {\n\t\t\tT i;\n\t\t\tT j;\n\t\t\tT k;\n\t\t};\n\t\tVector<T, 3> v;\n\t};\n\n\tconstexpr Quaternion() : w(0), i(0), j(0), k(0) {}\n\tconstexpr Quaternion(T w, T i, T j, T k) : w(w), i(i), j(j), k(k) {}\n\tconstexpr Quaternion(T w, Vector<T, 3> v) : w(w), v(v) {}\n\n\ttemplate<typename OtherT>\n\texplicit operator Quaternion<OtherT>() const {\n\t\tQuaternion<OtherT> result;\n\n\t\tresult.w = static_cast<OtherT>(w);\n\t\tresult.i = static_cast<OtherT>(i);\n\t\tresult.j = static_cast<OtherT>(j);\n\t\tresult.k = static_cast<OtherT>(k);\n\n\t\treturn result;\n\t}\n\n\tstatic inline constexpr Quaternion<T> IDENTITY() {\n\t\treturn Quaternion<T>(1, 0, 0, 0);\n\t}\n\n\tstatic inline constexpr Quaternion<T> ZEROS() {\n\t\treturn Quaternion<T>(0, 0, 0, 0);\n\t}\n};\n\ntypedef Quaternion<double>\t\tQuat4;\ntypedef Quaternion<float>\t\tQuat4f;\ntypedef Quaternion<long long>\tQuat4l;\ntypedef Quaternion<int>\t\t\tQuat4i;\n\ntemplate<typename T>\nQuaternion<T> operator*(const Quaternion<T>& a, const Quaternion<T>& b) {\n\tT w = a.w * b.w - (a.v * b.v);\n\tVector<T, 3> v = a.w * b.v + a.v * b.w + (a.v % b.v);\n\treturn Quaternion<T>(w, v);\n}\n\n// computes  q * Quaternion(0, v)\ntemplate<typename T>\nQuaternion<T> operator*(const Quaternion<T>& q, const Vector<T, 3>& v) {\n\treturn Quaternion<T>(-(v * q.v), q.w * v + q.v % v);\n}\n\n// computes  Quaternion(0, v) * q\ntemplate<typename T>\nQuaternion<T> operator*(const Vector<T, 3>& v, const Quaternion<T>& q) {\n\treturn Quaternion<T>(-(v * q.v), q.w * v + v % q.v);\n}\n\n// computes q * v * conj(q)  if q is a unit quaternion\ntemplate<typename T>\nVector<T, 3> mulQuaternionLeftRightConj(const Quaternion<T>& q, const Vector<T, 3>& v) {\n\tVector<T, 3> u = q.v;\n\tVector<T, 3> cross_uv = u % v;\n\treturn v + ((cross_uv * q.w) + u % cross_uv) * static_cast<T>(2);\n}\n\n// computes conj(q) * v * q  if q is a unit quaternion\ntemplate<typename T>\nVector<T, 3> mulQuaternionLeftConjRight(const Quaternion<T>& q, const Vector<T, 3>& v) {\n\tVector<T, 3> u = q.v;\n\tVector<T, 3> cross_uv = v % u;\n\treturn v + ((cross_uv * q.w) + cross_uv % u) * static_cast<T>(2);\n}\n\ntemplate<typename T>\nQuaternion<T> operator*(const Quaternion<T>& quat, T factor) {\n\treturn Quaternion<T>(quat.w * factor, quat.v * factor);\n}\n\ntemplate<typename T>\nQuaternion<T> operator*(T factor, const Quaternion<T>& quat) {\n\treturn Quaternion<T>(factor * quat.w, factor * quat.v);\n}\n\ntemplate<typename T>\nQuaternion<T> operator+(const Quaternion<T>& a, const Quaternion<T>& b) {\n\treturn Quaternion<T>(a.w + b.w, a.v + b.v);\n}\n\ntemplate<typename T>\nQuaternion<T> operator-(const Quaternion<T>& a, const Quaternion<T>& b) {\n\treturn Quaternion<T>(a.w - b.w, a.v - b.v);\n}\n\ntemplate<typename T>\nQuaternion<T> operator/(const Quaternion<T>& quat, T factor) {\n\treturn Quaternion<T>(quat.w / factor, quat.v / factor);\n}\n\ntemplate<typename T>\nQuaternion<T> operator-(const Quaternion<T>& quat) {\n\treturn Quaternion<T>(-quat.w, -quat.v);\n}\n\ntemplate<typename T>\nQuaternion<T>& operator+=(Quaternion<T>& quat, const Quaternion<T>& other) {\n\tquat.w += other.w;\n\tquat.v += other.v;\n\n\treturn quat;\n}\ntemplate<typename T>\nQuaternion<T>& operator-=(Quaternion<T>& quat, const Quaternion<T>& other) {\n\tquat.w -= other.w;\n\tquat.v -= other.v;\n\n\treturn quat;\n}\n\ntemplate<typename T>\nQuaternion<T>& operator*=(Quaternion<T>& quat, T factor) {\n\tquat.w *= factor;\n\tquat.v *= factor;\n\n\treturn quat;\n}\n\ntemplate<typename T>\nQuaternion<T>& operator/=(Quaternion<T>& quat, T factor) {\n\tquat.w /= factor;\n\tquat.v /= factor;\n\n\treturn quat;\n}\n\ntemplate<typename T>\nT dot(const Quaternion<T>& a, const Quaternion<T>& b) {\n\treturn a.w * b.w + a.i * b.i + a.j * b.j + a.k * b.k;\n}\n\ntemplate<typename T>\nQuaternion<T> operator!(const Quaternion<T>& quat) {\n\treturn Quaternion<T>(quat.w, -quat.v);\n}\n\ntemplate<typename T>\nQuaternion<T> conj(const Quaternion<T>& quat) {\n\treturn !quat;\n}\n\ntemplate<typename T>\nT lengthSquared(const Quaternion<T>& q) {\n\treturn q.w * q.w + q.i * q.i + q.j * q.j + q.k * q.k;\n}\n\ntemplate<typename T>\nT length(const Quaternion<T>& quat) {\n\treturn std::sqrt(lengthSquared(quat));\n}\n\ntemplate<typename T>\nQuaternion<T> normalize(const Quaternion<T>& quat) {\n\treturn quat / length(quat);\n}\n\ntemplate<typename T>\nQuaternion<T> operator~(const Quaternion<T>& quat) {\n\treturn !quat / lengthSquared(quat);\n}\n\ntemplate<typename T>\nQuaternion<T> inverse(const Quaternion<T>& quat) {\n\treturn ~quat;\n}\n};\n"
  },
  {
    "path": "Physics3D/math/linalg/trigonometry.cpp",
    "content": "#include \"trigonometry.h\"\n#include \"mat.h\"\n\n#include <cmath>\n\nnamespace P3D {\ntemplate<typename T>\nMatrix<T, 4, 4> rotate(const Matrix<T, 4, 4>& mat, T angle, T x, T y, T z) {\n\tT s = sin(angle);\n\tT c = cos(angle);\n\tT C = (1 - c);\n\n\tMatrix<T, 3, 3> rotator{\n\t\tx * x * C + c,\t\t\tx * y * C - z * s,\t\tx * z * C + y * s,\n\t\ty * x * C + z * s,\t\ty * y * C + c,\t\t\ty * z * C - x * s,\n\t\tz * x * C - y * s,\t\tz * y * C + x * s,\t\tz * z * C + c\n\t};\n\n\tMatrix<T, 4, 3> leftSide = mat.template getSubMatrix<4, 3>(0, 0);\n\n\tMatrix<T, 4, 3> rotated = leftSide * rotator;\n\n\tMatrix<T, 4, 1> translation = mat.template getSubMatrix<4, 1>(0, 3);\n\n\treturn joinHorizontal(rotated, translation);\n}\n\nMat4f ortho(float left, float right, float bottom, float top, float zNear, float zFar) {\n\tfloat r00 = 2.0f / (right - left);\n\tfloat r11 = 2.0f / (top - bottom);\n\tfloat r22 = -2.0f / (zFar - zNear);\n\tfloat r30 = (left + right) / (left - right);\n\tfloat r31 = (top + bottom) / (bottom - top);\n\tfloat r32 = (zFar + zNear) / (zNear - zFar);\n\tfloat r33 = 1.0f;\n\n\treturn Mat4f{\n\t\tr00, 0, 0, r30,\n\t\t0, r11, 0, r31,\n\t\t0, 0, r22, r32,\n\t\t0, 0, 0,   r33\n\t};\n}\n\nMat4f perspective(float fov, float aspect, float zNear, float zFar) {\n\tfloat t = tan(fov / 2);\n\tfloat r00 = 1 / (t * aspect);\n\tfloat r11 = 1 / t;\n\tfloat r22 = (zFar + zNear) / (zNear - zFar);\n\tfloat r32 = (zFar + zFar) * zNear / (zNear - zFar);\n\tfloat r23 = -1;\n\treturn Mat4f{\n\t\tr00, 0, 0, 0,\n\t\t0, r11, 0, 0,\n\t\t0, 0, r22, r32,\n\t\t0, 0, r23, 0\n\t};\n}\n\nMat4f lookAt(const Vec3f& from, const Vec3f& to, const Vec3f& up) {\n\n\t/*Vec3f z = normalize(to - from);\n\tVec3f x = normalize(up) % z;\n\tVec3f y = z % x;\n\n\treturn Mat4f {\n\t\tx.x, x.y, x.z, -from.x,\n\t\ty.x, y.y, y.z, -from.y,\n\t\t-z.x, -z.y, -z.z, from.z,\n\t\t0.0f, 0.0f, 0.0f, 1.0f\n\t};*/\n\n\tVec3f f = normalize(to - from);\n\tVec3f u = normalize(up);\n\tVec3f s = normalize(f % u);\n\tu = s % f;\n\n\treturn Mat4f{\n\t\t s.x,  s.y,  s.z, -dot(s, from),\n\t\t u.x,  u.y,  u.z, -dot(u, from),\n\t\t-f.x, -f.y, -f.z,  dot(f, from),\n\t\t 0.0f, 0.0f, 0.0f, 1.0f\n\t};\n}\n};"
  },
  {
    "path": "Physics3D/math/linalg/trigonometry.h",
    "content": "#pragma once\n\n#include \"vec.h\"\n#include \"mat.h\"\n#include \"quat.h\"\n\n#include <cmath>\n\nnamespace P3D {\n/*\n\tCreates a matrix such that for any vector x:\n\tv % x == createCrossProductEquivalent(v) * x\n*/\ntemplate<typename T>\nMatrix<T, 3, 3> createCrossProductEquivalent(const Vector<T, 3> & vec) {\n\treturn Matrix<T, 3, 3>{\n\t\t0, -vec.z, vec.y,\n\t\tvec.z, 0, -vec.x,\n\t\t-vec.y, vec.x, 0\n\t};\n}\n\n/*\n\tReturns a matrix equivalent to (v % (v % x)) = skewSymmetricSquared(v) * x\n\twhich is also equal to createCrossProductEquivalent(v)^2 = skewSymmetricSquared(v)\n*/\ntemplate<typename N>\nSymmetricMatrix<N, 3> skewSymmetricSquared(const Vector<N, 3> & v) {\n\tN x = v.x, y = v.y, z = v.z;\n\treturn SymmetricMatrix<N, 3>{\n\t\t-(y * y + z * z),\n\t\tx * y, -(x * x + z * z),\n\t\tx * z, y * z, -(x * x + y * y)\n\t};\n}\n\ntemplate<typename T>\nSymmetricMatrix<T, 3> transformBasis(const SymmetricMatrix<T, 3> & sm, const Matrix<T, 3, 3> & rotation) {\n\tMatrix<T, 3, 3> r = rotation * sm * ~rotation;\n\treturn SymmetricMatrix<T, 3>{\n\t\tr(0, 0),\n\t\tr(1, 0), r(1, 1),\n\t\tr(2, 0), r(2, 1), r(2, 2)\n\t};\n}\n\ntemplate<typename T>\nSymmetricMatrix<T, 3> transformBasis(const DiagonalMatrix<T, 3> & dm, const Matrix<T, 3, 3> & rotation) {\n\tMatrix<T, 3, 3> r = rotation * dm * ~rotation;\n\treturn SymmetricMatrix<T, 3>{\n\t\tr(0, 0),\n\t\tr(1, 0), r(1, 1),\n\t\tr(2, 0), r(2, 1), r(2, 2)\n\t};\n}\n\ntemplate<typename T>\nSymmetricMatrix<T, 3> multiplyLeftRight(const SymmetricMatrix<T, 3> & sm, const Matrix<T, 3, 3> & otherMat) {\n\tMatrix<T, 3, 3> r = otherMat * sm * otherMat.transpose();\n\treturn SymmetricMatrix<T, 3>{\n\t\tr(0, 0),\n\t\tr(1, 0), r(1, 1),\n\t\tr(2, 0), r(2, 1), r(2, 2)\n\t};\n}\n\ntemplate<typename T>\nUnitaryMatrix<T, 3> rotMatX(T angle) {\n\tT sina = sin(angle);\n\tT cosa = cos(angle);\n\treturn UnitaryMatrix<T, 3>{\n\t\t1, 0, 0,\n\t\t0, cosa, -sina,\n\t\t0, sina, cosa\n\t};\n}\ntemplate<typename T>\nUnitaryMatrix<T, 3> rotMatY(T angle) {\n\tT sina = sin(angle);\n\tT cosa = cos(angle);\n\treturn UnitaryMatrix<T, 3>{\n\t\tcosa, 0, sina,\n\t\t0, 1, 0,\n\t\t-sina, 0, cosa\n\t};\n}\ntemplate<typename T>\nUnitaryMatrix<T, 3> rotMatZ(T angle) {\n\tT sina = sin(angle);\n\tT cosa = cos(angle);\n\treturn UnitaryMatrix<T, 3>{\n\t\tcosa, -sina, 0,\n\t\tsina, cosa, 0,\n\t\t0, 0, 1\n\t};\n}\n\ntemplate<typename T>\nQuaternion<T> rotQuatX(T angle) {\n\treturn Quaternion<T>(std::cos(angle/2), std::sin(angle/2), 0, 0);\n}\ntemplate<typename T>\nQuaternion<T> rotQuatY(T angle) {\n\treturn Quaternion<T>(std::cos(angle/2), 0, std::sin(angle/2), 0);\n}\ntemplate<typename T>\nQuaternion<T> rotQuatZ(T angle) {\n\treturn Quaternion<T>(std::cos(angle/2), 0, 0, std::sin(angle/2));\n}\n\ntemplate<typename T>\nVector<T, 3> getPerpendicular(Vector<T, 3> v) {\n\tVector<T, 3> notInline(0, 0, 0);\n\tnotInline[getAbsMinElementIndex(v)] = 1;\n\treturn v % notInline;\n}\n\ntemplate<typename T>\nUnitaryMatrix<T, 3> faceMatX(Vector<T, 3> x, Vector<T, 3> yHint) {\n\tx = normalize(x);\n\tVector<T, 3> z = normalize(x % yHint);\n\tVector<T, 3> y = z % x;\n\n\treturn UnitaryMatrix<T, 3>::fromColumns({x, y, z});\n}\ntemplate<typename T>\nUnitaryMatrix<T, 3> faceMatX(Vector<T, 3> x) {\n\tVector<T, 3> yHint(0,0,0);\n\tyHint[getAbsMinElementIndex(x)] = 1;\n\treturn faceMatX(x, yHint);\n}\ntemplate<typename T>\nUnitaryMatrix<T, 3> faceMatY(Vector<T, 3> y, Vector<T, 3> zHint) {\n\ty = normalize(y);\n\tVector<T, 3> x = normalize(y % zHint);\n\tVector<T, 3> z = x % y;\n\n\treturn UnitaryMatrix<T, 3>::fromColumns({x, y, z});\n}\ntemplate<typename T>\nUnitaryMatrix<T, 3> faceMatY(Vector<T, 3> y) {\n\tVector<T, 3> zHint(0, 0, 0);\n\tzHint[getAbsMinElementIndex(y)] = 1;\n\treturn faceMatY(y, zHint);\n}\ntemplate<typename T>\nUnitaryMatrix<T, 3> faceMatZ(Vector<T, 3> z, Vector<T, 3> xHint) {\n\tz = normalize(z);\n\tVector<T, 3> y = normalize(z % xHint);\n\tVector<T, 3> x = y % z;\n\n\treturn UnitaryMatrix<T, 3>::fromColumns({x, y, z});\n}\ntemplate<typename T>\nUnitaryMatrix<T, 3> faceMatZ(Vector<T, 3> z) {\n\tVector<T, 3> xHint(0, 0, 0);\n\txHint[getAbsMinElementIndex(z)] = 1;\n\treturn faceMatZ(z, xHint);\n}\n\n/*\n\tProduces a rotation matrix from the provided euler angles\n\n\tEquivalent to rotMatZ(gamma) * rotMatX(alpha) * rotMatY(beta)\n*/\ntemplate<typename T>\nUnitaryMatrix<T, 3> rotationMatrixfromEulerAngles(T alpha, T beta, T gamma) {\n\treturn rotMatZ(gamma) * rotMatX(alpha) * rotMatY(beta);\n}\n\ntemplate<typename T>\nRotationMatrix<T, 3> rotationMatrixFromRotationVec(Vector<T, 3> rotVec) {\n\tT angleSq = lengthSquared(rotVec);\n\tT angle = std::sqrt(angleSq);\n\n\t// sinc(angle) = sin(angle) / angle\n\t// around angle=0 =~ 1 - angle^2 / 6 + angle^4 / 120 - angle^6 / 5040 \n\tT sincAngle = (angleSq > 1E-20) ? std::sin(angle) / angle : 1 - angleSq / 6;\n\n\tT cosAngle = std::cos(angle);\n\n\t// cosc(angle) = (cos(angle) - 1) / angle^2\n\t// around angle=0 =~ 1/2 - angle^2 / 24 + angle^4 / 720 - angle^6 / 40320\n\tT coscAngle = (angleSq > 1E-20) ? (1 - cosAngle) / angleSq : T(0.5) - angleSq / 24;\n\n\tVector<T, 3> sincVec = rotVec * sincAngle;\n\tMatrix<T, 3, 3> rotor{\n\t\t cosAngle,   -sincVec.z,   sincVec.y,\n\t\t sincVec.z,   cosAngle,   -sincVec.x,\n\t\t-sincVec.y,   sincVec.x,   cosAngle\n\t};\n\n\treturn outer(rotVec, rotVec) * coscAngle + rotor;\n}\n\ntemplate<typename T>\nQuaternion<T> rotationQuaternionFromRotationVec(Vector<T, 3> rotVec) {\n\tT angleSq = lengthSquared(rotVec);\n\tT angle = std::sqrt(angleSq);\n\n\t// sincDiv2(angle) = sin(angle/2) / angle\n\t// around angle=0 =~ 1 - angle^2 / 24 + angle^4 / 480 - angle^6 / 20160 \n\tT sincAngleDiv2 = (angleSq > 1E-20) ? std::sin(angle/2) / angle : 1 - angleSq / 24;\n\n\treturn Quaternion<T>(std::cos(angle/2), sincAngleDiv2 * rotVec);\n}\n\ntemplate<typename T>\nVector<T, 3> rotationVectorFromRotationMatrix(const RotationMatrix<T, 3>& m) {\n\tassert(isValidRotationMatrix(m));\n\tVector<T, 3> axisOfRotation(m(2, 1) - m(1, 2), m(0, 2) - m(2, 0), m(1, 0) - m(0, 1));\n\tif(axisOfRotation[0] == 0 && axisOfRotation[1] == 0 && axisOfRotation[2] == 0) return Vector<T, 3>(0, 0, 0);\n\tT trace = m(0, 0) + m(1, 1) + m(2, 2);\n\n\tT angle = std::acos((trace - 1) / 2);\n\n\treturn normalize(axisOfRotation) * angle;\n}\n\ntemplate<typename T>\nVector<T, 3> rotationVectorFromRotationQuaternion(const Quaternion<T>& q) {\n\tassert(isValidRotationQuaternion(q));\n\t\n\t// q.v = sin(length(result)) * normalize(result);\n\tVector<T, 3> axisOfRotation = q.v; // length is sin, still need to multiply by \n\tT sinAngleDiv2 = length(axisOfRotation);\n\tT cosAngleDiv2 = q.w;\n\n\t// asincAngle == asin(sinAngle) / sinAngle, though this incorporates the sign brought by the w term\n\t// atan is defined for +-infinity, and sin and cos can never be 0 at the same time, so no worry\n\tT asincAngleDiv2 = (sinAngleDiv2 > 1E-10) ? std::atan(sinAngleDiv2 / cosAngleDiv2) / sinAngleDiv2 : 1 / cosAngleDiv2;\n\n\treturn axisOfRotation * asincAngleDiv2 * T(2);\n}\n\ntemplate<typename T>\nMatrix<T, 3, 3> rotationMatrixFromQuaternion(const Quaternion<T>& quat) {\n\tassert(isValidRotationQuaternion(quat));\n\tVector<T, 3> quatVSq = elementWiseSquare(quat.v);\n\tVector<T, 3> diagElements = Vector<T, 3>(1,1,1) - T(2) * addSelfOpposites(quatVSq);\n\tVector<T, 3> selfMul = T(2) * mulSelfOpposites(quat.v);\n\tVector<T, 3> mvMul = (T(2)*quat.w) * quat.v;\n\n\treturn Matrix<T, 3, 3>{\n\t\tdiagElements.x, selfMul.z - mvMul.z, selfMul.y + mvMul.y,\n\t\tselfMul.z + mvMul.z, diagElements.y, selfMul.x - mvMul.x,\n\t\tselfMul.y - mvMul.y, selfMul.x + mvMul.x, diagElements.z\n\t};\n}\n};\n\n#include <iostream>\n\nnamespace P3D {\ntemplate<typename T>\nQuaternion<T> rotationQuaternionFromRotationMatrix(const Matrix<T, 3, 3>& a) {\n\tassert(isValidRotationMatrix(a));\n\n\tQuaternion<T> q;\n\tT trace = a(0, 0) + a(1, 1) + a(2, 2);\n\tif(trace > 0) {\n\t\tT s = T(0.5) / std::sqrt(trace + 1);\n\t\tq.w = T(0.25) / s;\n\t\tq.i = (a(2, 1) - a(1, 2)) * s;\n\t\tq.j = (a(0, 2) - a(2, 0)) * s;\n\t\tq.k = (a(1, 0) - a(0, 1)) * s;\n\t} else {\n\t\tif(a(0, 0) > a(1, 1) && a(0, 0) > a(2, 2)) {\n\t\t\tT s = T(2.0) * std::sqrt(1 + a(0, 0) - a(1, 1) - a(2, 2));\n\t\t\tq.w = (a(2, 1) - a(1, 2)) / s;\n\t\t\tq.i = T(0.25) * s;\n\t\t\tq.j = (a(0, 1) + a(1, 0)) / s;\n\t\t\tq.k = (a(0, 2) + a(2, 0)) / s;\n\t\t} else if(a(1, 1) > a(2, 2)) {\n\t\t\tT s = T(2.0) * std::sqrt(1 + a(1, 1) - a(0, 0) - a(2, 2));\n\t\t\tq.w = (a(0, 2) - a(2, 0)) / s;\n\t\t\tq.i = (a(0, 1) + a(1, 0)) / s;\n\t\t\tq.j = T(0.25) * s;\n\t\t\tq.k = (a(1, 2) + a(2, 1)) / s;\n\t\t} else {\n\t\t\tT s = T(2.0) * std::sqrt(1 + a(2, 2) - a(0, 0) - a(1, 1));\n\t\t\tq.w = (a(1, 0) - a(0, 1)) / s;\n\t\t\tq.i = (a(0, 2) + a(2, 0)) / s;\n\t\t\tq.j = (a(1, 2) + a(2, 1)) / s;\n\t\t\tq.k = T(0.25) * s;\n\t\t}\n\t}\n\treturn q;\n}\n\ntemplate<typename T>\nMatrix<T, 3, 3> rotateAround(T angle, Vector<T, 3> normal) {\n\t// Using Rodrigues rotation formula;\n\tnormal = normalize(normal);\n\tMatrix<T, 3, 3> W{\n\t\t 0,\t\t\t-normal.z, normal.y,\n\t\t normal.z,  0,\t\t   -normal.x,\n\t\t -normal.y, normal.x,  0\n\t};\n\n\tMatrix<T, 3, 3> W2 = W * W;\n\tT s = sin(angle);\n\tT s2 = sin(angle / 2);\n\n\tMatrix<T, 3, 3> R = Matrix<T, 3, 3>::IDENTITY() + W * s + W2 * (2 * s2 * s2);\n\n\treturn R;\n}\n\n\n// mat4\nMat4f ortho(float left, float right, float bottom, float top, float zNear, float zFar);\n\nMat4f perspective(float fov, float aspect, float zNear, float zFar);\n\nMat4f lookAt(const Vec3f& from, const Vec3f& to, const Vec3f& up = Vec3f(0, 1.0f, 0));\n\ntemplate<typename T>\nMatrix<T, 4, 4> rotate(const Matrix<T, 4, 4>&, T angle, T x, T y, T z);\n\ntemplate<typename T>\nMatrix<T, 4, 4> translate(const Matrix<T, 4, 4>& mat, T x, T y, T z) {\n\tMatrix<T, 4, 1> r{x, y, z, 1.0};\n\tMatrix<T, 4, 1> rr = mat * r;\n\treturn joinHorizontal(mat.template getSubMatrix<4, 3>(0, 0), rr);\n}\n\ntemplate<typename T>\nMatrix<T, 4, 4> scale(const Matrix<T, 4, 4>& mat, const Vector<T, 3>& scaleVec) {\n\tMatrix<T, 4, 4> result;\n\n\tfor(int i = 0; i < 3; i++) {\n\t\tfor(int j = 0; j < 4; j++) {\n\t\t\tresult(j, i) = mat(j, i) * scaleVec[i];\n\t\t}\n\t}\n\tfor(int j = 0; j < 4; j++) {\n\t\tresult(j, 3) = mat(j, 3);\n\t}\n\n\treturn result;\n}\n\ntemplate<typename T>\nMatrix<T, 4, 4> scale(const Matrix<T, 4, 4>& mat, T x, T y, T z) {\n\treturn scale(mat, Vector<T, 3>(x, y, z));\n}\n\ntemplate<typename T>\nMatrix<T, 4, 4> scale(const Matrix<T, 4, 4>& mat, T v) {\n\treturn scale(mat, v, v, v);\n}\n\ntemplate<typename T>\nMatrix<T, 4, 4> translate(const Matrix<T, 4, 4>& mat, const Vector<T, 3>& dv) {\n\treturn translate(mat, dv.x, dv.y, dv.z);\n}\n\ninline bool equalsApproximately(double value, double comparedTo) {\n\tauto delta = comparedTo - value;\n\treturn delta < 1E-8 && delta > -1E-8;\n}\ninline bool equalsApproximately(float value, float comparedTo) {\n\tauto delta = comparedTo - value;\n\treturn delta < 1E-4 && delta > -1E-4;\n}\ntemplate<typename T>\nbool isValidRotationMatrix(const Matrix<T, 3, 3>& mat) {\n\tconstexpr T zero = 0;\n\tconstexpr T one = 1;\n\tfor(int i = 0; i < 3; i++) {\n\t\tT rowLengthSq = lengthSquared(mat.getRow(i));\n\t\tT colLengthSq = lengthSquared(mat.getCol(i));\n\t\tif(!equalsApproximately(rowLengthSq, one)\n\t\t   || !equalsApproximately(colLengthSq, one)) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tfor(int i = 0; i < 3; i++) {\n\t\tfor(int j = 0; j < 3; j++) {\n\t\t\tif(i == j) continue;\n\n\t\t\tif(!equalsApproximately(mat.getRow(i) * mat.getRow(j), zero)\n\t\t\t   || !equalsApproximately(mat.getCol(i) * mat.getCol(j), zero)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n\n\tT detMat = det(mat);\n\tif(!equalsApproximately(detMat, one)) {\n\t\treturn false;\n\t}\n\treturn true;\n}\ntemplate<typename T>\nbool isValidRotationQuaternion(const Quaternion<T>& quat) {\n\treturn equalsApproximately(lengthSquared(quat), T(1));\n}\n};"
  },
  {
    "path": "Physics3D/math/linalg/vec.h",
    "content": "#pragma once\n\n#include <stddef.h>\n#include <cmath>\n#include <assert.h>\n\nnamespace P3D {\ntemplate<typename T, size_t Size>\nstruct Vector {\n\tT data[Size];\n\n\tconstexpr Vector() noexcept : data{} {\n\t\tfor(T& item : this->data) {\n\t\t\titem = 0;\n\t\t}\n\t}\n\n\ttemplate<typename OtherT>\n\tconstexpr operator Vector<OtherT, Size>() const noexcept {\n\t\tVector<OtherT, Size> result;\n\t\tfor(size_t i = 0; i < Size; i++) {\n\t\t\tresult.data[i] = static_cast<OtherT>(this->data[i]);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tconstexpr size_t size() const { return Size; }\n\n\tconstexpr T& operator[](size_t index) noexcept {\n\t\treturn data[index];\n\t}\n\n\tconstexpr const T& operator[](size_t index) const noexcept {\n\t\treturn data[index];\n\t}\n\n\tstatic constexpr Vector<T, Size> full(T v) noexcept {\n\t\tVector<T, Size> result;\n\t\tfor(size_t i = 0; i < Size; i++) {\n\t\t\tresult[i] = v;\n\t\t}\n\t\treturn result;\n\t}\n\n\ttemplate<size_t SubSize>\n\tconstexpr Vector<T, SubSize> getSubVector(size_t startingAt = 0) const noexcept {\n\t\tVector<T, SubSize> result;\n\t\tfor(size_t i = 0; i < SubSize; i++) {\n\t\t\tresult[i] = this->data[i + startingAt];\n\t\t}\n\t\treturn result;\n\t}\n};\n\ntemplate<typename T>\nstruct Vector<T, 1> {\n\tunion {\n\t\tT data[1];\n\t\tstruct { T x; };\n\t};\n\n\tconstexpr Vector() noexcept : data{0} {}\n\tconstexpr Vector(T x) noexcept : data{x} {}\n\n\ttemplate<typename OtherT>\n\tconstexpr operator Vector<OtherT, 1>() const noexcept {\n\t\treturn Vector<OtherT, 1>(static_cast<OtherT>(this->data[0]));\n\t}\n\n\tconstexpr size_t size() const { return 1; }\n\n\tconstexpr T& operator[](size_t index) noexcept {\n\t\treturn data[index];\n\t}\n\n\tconstexpr const T& operator[](size_t index) const noexcept {\n\t\treturn data[index];\n\t}\n\n\tstatic constexpr Vector<T, 1> full(T v) noexcept {\n\t\treturn Vector<T, 1>(v);\n\t}\n\n\ttemplate<size_t SubSize>\n\tconstexpr Vector<T, SubSize> getSubVector(size_t startingAt = 0) const noexcept {\n\t\tVector<T, SubSize> result;\n\t\tfor(size_t i = 0; i < SubSize; i++) {\n\t\t\tresult[i] = this->data[i + startingAt];\n\t\t}\n\t\treturn result;\n\t}\n\n\tconstexpr operator T() const { return data[0]; }\n};\n\ntemplate<typename T>\nstruct Vector<T, 2> {\n\tunion {\n\t\tT data[2];\n\t\tstruct { T x; T y; };\n\t};\n\n\tconstexpr Vector() noexcept : data{0, 0} {}\n\tconstexpr Vector(T x, T y) noexcept : data{x, y} {}\n\n\ttemplate<typename OtherT>\n\tconstexpr operator Vector<OtherT, 2>() const noexcept {\n\t\treturn Vector<OtherT, 2>(static_cast<OtherT>(this->data[0]), static_cast<OtherT>(this->data[1]));\n\t}\n\n\tconstexpr size_t size() const { return 2; }\n\n\tconstexpr T& operator[](size_t index) noexcept {\n\t\treturn data[index];\n\t}\n\n\tconstexpr const T& operator[](size_t index) const noexcept {\n\t\treturn data[index];\n\t}\n\n\tstatic constexpr Vector<T, 2> full(T v) noexcept {\n\t\treturn Vector<T, 2>(v, v);\n\t}\n\n\ttemplate<size_t SubSize>\n\tconstexpr Vector<T, SubSize> getSubVector(size_t startingAt = 0) const noexcept {\n\t\tVector<T, SubSize> result;\n\t\tfor(size_t i = 0; i < SubSize; i++) {\n\t\t\tresult[i] = this->data[i + startingAt];\n\t\t}\n\t\treturn result;\n\t}\n};\n\ntemplate<typename T>\nstruct Vector<T, 3> {\n\tunion {\n\t\tT data[3];\n\t\tstruct { T x; T y; T z; };\n\t};\n\n\tconstexpr Vector() noexcept : data{0, 0, 0} {}\n\tconstexpr Vector(T x, T y, T z) noexcept : data{x, y, z} {};\n\n\ttemplate<typename OtherT>\n\tconstexpr operator Vector<OtherT, 3>() const noexcept {\n\t\treturn Vector<OtherT, 3>(static_cast<OtherT>(this->data[0]), static_cast<OtherT>(this->data[1]), static_cast<OtherT>(this->data[2]));\n\t}\n\n\tconstexpr size_t size() const { return 3; }\n\n\tconstexpr T& operator[](size_t index) noexcept {\n\t\treturn data[index];\n\t}\n\n\tconstexpr const T& operator[](size_t index) const noexcept {\n\t\treturn data[index];\n\t}\n\n\tstatic constexpr Vector<T, 3> full(T v) noexcept {\n\t\treturn Vector<T, 3>(v, v, v);\n\t}\n\n\ttemplate<size_t SubSize>\n\tconstexpr Vector<T, SubSize> getSubVector(size_t startingAt = 0) const noexcept {\n\t\tVector<T, SubSize> result;\n\t\tfor(size_t i = 0; i < SubSize; i++) {\n\t\t\tresult[i] = this->data[i + startingAt];\n\t\t}\n\t\treturn result;\n\t}\n};\n\ntemplate<typename T>\nstruct Vector<T, 4> {\n\tunion {\n\t\tT data[4];\n\t\tstruct { T x; T y; T z; T w; };\n\t};\n\tconstexpr Vector() noexcept : data{0, 0, 0, 0} {}\n\tconstexpr Vector(T x, T y, T z, T w) noexcept : data{x, y, z, w} {}\n\n\ttemplate<typename OtherT>\n\tconstexpr operator Vector<OtherT, 4>() const noexcept {\n\t\treturn Vector<OtherT, 4>(static_cast<OtherT>(this->data[0]), static_cast<OtherT>(this->data[1]), static_cast<OtherT>(this->data[2]), static_cast<OtherT>(this->data[3]));\n\t}\n\n\tconstexpr size_t size() const { return 4; }\n\n\tconstexpr T& operator[](size_t index) noexcept {\n\t\treturn data[index];\n\t}\n\n\tconstexpr const T& operator[](size_t index) const noexcept {\n\t\treturn data[index];\n\t}\n\n\tstatic constexpr Vector<T, 4> full(T v) noexcept {\n\t\treturn Vector<T, 4>(v, v, v, v);\n\t}\n\n\ttemplate<size_t SubSize>\n\tconstexpr Vector<T, SubSize> getSubVector(size_t startingAt = 0) const noexcept {\n\t\tVector<T, SubSize> result;\n\t\tfor(size_t i = 0; i < SubSize; i++) {\n\t\t\tresult[i] = this->data[i + startingAt];\n\t\t}\n\t\treturn result;\n\t}\n};\n\ntypedef Vector<double, 1>\t\tVec1;\ntypedef Vector<float, 1>\t\tVec1f;\ntypedef Vector<long long, 1>\tVec1l;\ntypedef Vector<int, 1>\t\t\tVec1i;\n\ntypedef Vector<double, 2>\t\tVec2;\ntypedef Vector<float, 2>\t\tVec2f;\ntypedef Vector<long long, 2>\tVec2l;\ntypedef Vector<int, 2>\t\t\tVec2i;\n\ntypedef Vector<double, 3>\t\tVec3;\ntypedef Vector<float, 3>\t\tVec3f;\ntypedef Vector<long long, 3>\tVec3l;\ntypedef Vector<int, 3>\t\t\tVec3i;\n\ntypedef Vector<double, 4>\t\tVec4;\ntypedef Vector<float, 4>\t\tVec4f;\ntypedef Vector<long long, 4>\tVec4l;\ntypedef Vector<int, 4>\t\t\tVec4i;\n\ntypedef Vector<double, 5>\t\tVec5;\ntypedef Vector<float, 5>\t\tVec5f;\ntypedef Vector<long long, 5>\tVec5l;\ntypedef Vector<int, 5>\t\t\tVec5i;\n\ntypedef Vector<double, 6>\t\tVec6;\ntypedef Vector<float, 6>\t\tVec6f;\ntypedef Vector<long long, 6>\tVec6l;\ntypedef Vector<int, 6>\t\t\tVec6i;\n\n\ntemplate<typename T1, typename T2, size_t Size>\nconstexpr auto operator*(const Vector<T1, Size>& a, const Vector<T2, Size>& b) noexcept -> decltype(a[0] * b[0] + a[1] * b[1]) {\n\tdecltype(a[0] * b[0] + a[1] * b[1]) result = a[0] * b[0];\n\tfor(size_t i = 1; i < Size; i++) {\n\t\tresult += a[i] * b[i];\n\t}\n\treturn result;\n}\n\ntemplate<typename T1, typename T2, size_t Size>\nconstexpr auto dot(const Vector<T1, Size>& a, const Vector<T2, Size>& b) noexcept -> decltype(a[0] * b[0] + a[1] * b[1]) {\n\treturn a * b;\n}\n\ntemplate<typename T, size_t Size>\nconstexpr auto dot(const Vector<T, Size>& vec) noexcept -> decltype(vec[0] * vec[0] + vec[1] * vec[1]) {\n\treturn vec * vec;\n}\n\ntemplate<typename T1, typename T2, size_t Size>\nconstexpr auto operator+(const Vector<T1, Size>& a, const Vector<T2, Size>& b) noexcept -> Vector<decltype(a[0] + b[0]), Size> {\n\tVector<decltype(a[0] + b[0]), Size> result;\n\tfor(size_t i = 0; i < Size; i++) {\n\t\tresult[i] = a[i] + b[i];\n\t}\n\treturn result;\n}\n\ntemplate<typename T1, typename T2, size_t Size>\nconstexpr auto operator-(const Vector<T1, Size>& a, const Vector<T2, Size>& b) noexcept -> Vector<decltype(a[0] - b[0]), Size> {\n\tVector<decltype(a[0] - b[0]), Size> result;\n\tfor(size_t i = 0; i < Size; i++) {\n\t\tresult[i] = a[i] - b[i];\n\t}\n\treturn result;\n}\n\ntemplate<typename T1, typename T2, size_t Size>\nconstexpr auto operator*(const Vector<T1, Size>& vec, const T2& factor) noexcept -> Vector<decltype(vec[0] * factor), Size> {\n\tVector<decltype(vec[0] * factor), Size> result;\n\tfor(size_t i = 0; i < Size; i++) {\n\t\tresult[i] = vec[i] * factor;\n\t}\n\treturn result;\n}\n\ntemplate<typename T1, typename T2, size_t Size>\nconstexpr auto operator*(const T1& factor, const Vector<T2, Size>& vec) noexcept -> Vector<decltype(factor* vec[0]), Size> {\n\tVector<decltype(factor* vec[0]), Size> result;\n\tfor(size_t i = 0; i < Size; i++) {\n\t\tresult[i] = factor * vec[i];\n\t}\n\treturn result;\n}\n\ntemplate<typename T1, typename T2, size_t Size>\nconstexpr auto operator/(const Vector<T1, Size>& vec, const T2& factor) noexcept -> Vector<decltype(vec[0] / factor), Size> {\n\tVector<decltype(vec[0] / factor), Size> result;\n\tfor(size_t i = 0; i < Size; i++) {\n\t\tresult[i] = vec[i] / factor;\n\t}\n\treturn result;\n}\n\ntemplate<typename T, size_t Size>\nconstexpr Vector<T, Size> operator-(const Vector<T, Size>& vec) noexcept {\n\tVector<T, Size> result;\n\tfor(size_t i = 0; i < Size; i++) {\n\t\tresult[i] = -vec[i];\n\t}\n\treturn result;\n}\n\ntemplate<typename T1, typename T2, size_t Size>\nconstexpr Vector<T1, Size>& operator+=(Vector<T1, Size>& vec, const Vector<T2, Size>& other) noexcept {\n\tfor(size_t i = 0; i < Size; i++) {\n\t\tvec[i] += other[i];\n\t}\n\treturn vec;\n}\n\ntemplate<typename T1, typename T2, size_t Size>\nconstexpr Vector<T1, Size>& operator-=(Vector<T1, Size>& vec, const Vector<T2, Size>& other) noexcept {\n\tfor(size_t i = 0; i < Size; i++) {\n\t\tvec[i] -= other[i];\n\t}\n\treturn vec;\n}\n\ntemplate<typename T1, typename T2, size_t Size>\nconstexpr Vector<T1, Size>& operator*=(Vector<T1, Size>& vec, const T2& factor) noexcept {\n\tfor(size_t i = 0; i < Size; i++) {\n\t\tvec[i] *= factor;\n\t}\n\treturn vec;\n}\n\ntemplate<typename T1, typename T2, size_t Size>\nconstexpr Vector<T1, Size>& operator/=(Vector<T1, Size>& vec, const T2& factor) noexcept {\n\tfor(size_t i = 0; i < Size; i++) {\n\t\tvec[i] /= factor;\n\t}\n\treturn vec;\n}\n\ntemplate<typename T1, typename T2>\nconstexpr auto operator%(const Vector<T1, 2>& first, const Vector<T2, 2>& second) noexcept -> decltype(first[0] * second[1] - first[1] * second[0]) {\n\treturn first[0] * second[1] - first[1] * second[0];\n}\n\ntemplate<typename T1, typename T2>\nconstexpr auto cross(const Vector<T1, 2>& first, const Vector<T2, 2>& second) noexcept -> decltype(first[0] * second[1] - first[1] * second[0]) {\n\treturn first % second;\n}\n\ntemplate<typename T1, typename T2>\nconstexpr auto operator%(const Vector<T1, 3>& first, const Vector<T2, 3>& second) noexcept -> Vector<decltype(first[1] * second[2] - first[2] * second[1]), 3> {\n\treturn Vector<decltype(first[1] * second[2] - first[2] * second[1]), 3>{\n\t\tfirst[1] * second[2] - first[2] * second[1],\n\t\t\tfirst[2] * second[0] - first[0] * second[2],\n\t\t\tfirst[0] * second[1] - first[1] * second[0]\n\t};\n}\n\ntemplate<typename T1, typename T2>\nconstexpr auto cross(const Vector<T1, 3>& first, const Vector<T2, 3>& second) noexcept -> Vector<decltype(first[1] * second[2] - first[2] * second[1]), 3> {\n\treturn first % second;\n}\n\ntemplate<typename T, size_t Size>\nconstexpr bool operator==(const Vector<T, Size>& first, const Vector<T, Size>& second) noexcept {\n\tfor(size_t i = 0; i < Size; i++)\n\t\tif(first[i] != second[i])\n\t\t\treturn false;\n\n\treturn true;\n}\n\ntemplate<typename T, size_t Size>\nconstexpr bool operator!=(const Vector<T, Size>& first, const Vector<T, Size>& second) noexcept {\n\treturn !(first == second);\n}\n\n\ntemplate<typename T, size_t Size1, size_t Size2>\nconstexpr Vector<T, Size1 + Size2> join(const Vector<T, Size1>& first, const Vector<T, Size2>& second) noexcept {\n\tVector<T, Size1 + Size2> result;\n\tfor(size_t i = 0; i < Size1; i++) {\n\t\tresult[i] = first[i];\n\t}\n\tfor(size_t i = 0; i < Size2; i++) {\n\t\tresult[i + Size1] = second[i];\n\t}\n\treturn result;\n}\ntemplate<typename T, size_t Size>\nconstexpr Vector<T, Size + 1> join(const Vector<T, Size>& vec, const T& extraValue) noexcept {\n\tVector<T, Size + 1> result;\n\tfor(size_t i = 0; i < Size; i++) {\n\t\tresult[i] = vec[i];\n\t}\n\tresult[Size] = extraValue;\n\treturn result;\n}\ntemplate<typename T, size_t Size>\nconstexpr Vector<T, Size + 1> join(const T& extraValue, const Vector<T, Size>& vec) noexcept {\n\tVector<T, Size + 1> result;\n\tresult[0] = extraValue;\n\tfor(size_t i = 0; i < Size; i++) {\n\t\tresult[i + 1] = vec[i];\n\t}\n\treturn result;\n}\ntemplate<typename T, size_t Size>\nconstexpr Vector<T, Size - 1> withoutIndex(const Vector<T, Size>& vec, size_t indexToRemove) {\n\tassert(indexToRemove < Size);\n\tVector<T, Size - 1> result;\n\tfor(size_t i = 0; i < indexToRemove; i++) {\n\t\tresult[i] = vec[i];\n\t}\n\tfor(size_t i = indexToRemove + 1; i < Size; i++) {\n\t\tresult[i - 1] = vec[i];\n\t}\n\treturn result;\n}\n\n\n\ntemplate<typename T, size_t Size>\nconstexpr T lengthSquared(const Vector<T, Size>& vec) noexcept {\n\tT sum = vec[0] * vec[0];\n\n\tfor(size_t i = 1; i < Size; i++) {\n\t\tsum += vec[i] * vec[i];\n\t}\n\treturn sum;\n}\n\ntemplate<typename T, size_t Size>\nconstexpr T length(const Vector<T, Size>& vec) noexcept {\n\treturn std::sqrt(lengthSquared(vec));\n}\n\ntemplate<typename T>\nconstexpr T length(const Vector<T, 2>& vec) noexcept {\n\treturn std::hypot(vec[0], vec[1]);\n}\n\ntemplate<typename T1, typename T2, size_t Size>\nconstexpr bool isLongerThan(const Vector<T1, Size>& vec, const T2& length) noexcept {\n\treturn lengthSquared(vec) > length * length;\n}\n\ntemplate<typename T1, typename T2, size_t Size>\nconstexpr bool isShorterThan(const Vector<T1, Size>& vec, const T2& length) noexcept {\n\treturn lengthSquared(vec) < length * length;\n}\n\n// vec\ntemplate<typename T, size_t Size>\nconstexpr Vector<T, Size> withLength(const Vector<T, Size>& vec, const T& newLength) noexcept {\n\treturn vec * (newLength / length(vec));\n}\n\ntemplate<typename T, size_t Size>\nconstexpr Vector<T, Size> maxLength(const Vector<T, Size>& vec, const T& maxLength) noexcept {\n\tif(isLongerThan(vec, maxLength))\n\t\treturn withLength(vec, maxLength);\n\telse\n\t\treturn vec;\n}\n\ntemplate<typename T, size_t Size>\nconstexpr Vector<T, Size> minLength(const Vector<T, Size>& vec, const T& minLength) noexcept {\n\tif(isShorterThan(vec, minLength))\n\t\treturn withLength(vec, minLength);\n\telse\n\t\treturn vec;\n}\n\ntemplate<typename T, size_t Size>\nconstexpr Vector<T, Size> normalize(const Vector<T, Size>& vec) noexcept {\n\treturn vec / length(vec);\n}\n\ntemplate<typename T, size_t Size>\nconstexpr Vector<T, Size> abs(const Vector<T, Size>& vec) noexcept {\n\tVector<T, Size> result;\n\tfor(size_t i = 0; i < Size; i++)\n\t\tresult[i] = std::abs(vec[i]);\n\treturn result;\n}\n\n/**\n* used to project the result of a dotproduct back onto the original vector\n* @param v the result of dot(onto, otherVec)\n* @return vec * (v/lengthSquared(vec))\n*/\ntemplate<typename T, size_t Size>\nconstexpr Vector<T, Size> reProject(const Vector<T, Size>& onto, const T& v) noexcept {\n\treturn onto * v / lengthSquared(onto);\n}\n\n/**\n* projects vec onto onto\n* @param vec vector to be projected\n* @param onto vector to be projected on\n* @return a projected version of the given vector\n*/\ntemplate<typename T, size_t Size>\nconstexpr Vector<T, Size> project(const Vector<T, Size>& vec, const Vector<T, Size>& onto) noexcept {\n\treturn onto * ((onto * vec) / lengthSquared(onto));\n}\n\n\n/**\n* projects vec onto a plane with normal vector planeNormal\n* @param vec vector to be projected\n* @param planeNormal plane to be projected on\n* @return a projected version of the given vector\n*/\ntemplate<typename T, size_t Size>\nconstexpr Vector<T, Size> projectToPlaneNormal(const Vector<T, Size>& vec, const Vector<T, Size>& planeNormal) noexcept {\n\treturn vec - vec * planeNormal * planeNormal / lengthSquared(planeNormal);\n}\n\n/**\n* returns the distance of the given point to the line that goes through the origin along this vector\n* @param point\n* @return the distance\n*/\ntemplate<typename T, size_t Size>\nconstexpr T pointToLineDistance(const Vector<T, Size>& line, const Vector<T, Size>& point) noexcept {\n\treturn length(point - project(point, line));\n}\n\n/**\n* returns the squared distance of the given point to the line that goes through the origin along this vector\n* @param point\n* @return the square of the distance\n*/\ntemplate<typename T, size_t Size>\nconstexpr T pointToLineDistanceSquared(const Vector<T, Size>& line, const Vector<T, Size>& point) noexcept {\n\treturn lengthSquared(point - project(point, line));\n}\n\ntemplate<typename T, size_t Size>\nconstexpr Vector<T, Size> elementWiseMul(const Vector<T, Size>& first, const Vector<T, Size>& second) noexcept {\n\tVector<T, Size> result;\n\tfor(size_t i = 0; i < Size; i++)\n\t\tresult[i] = first[i] * second[i];\n\treturn result;\n}\n\ntemplate<typename T, size_t Size>\nconstexpr Vector<T, Size> elementWiseSquare(const Vector<T, Size>& vec) noexcept {\n\tVector<T, Size> result;\n\tfor(size_t i = 0; i < Size; i++)\n\t\tresult[i] = vec[i] * vec[i];\n\treturn result;\n}\n\ntemplate<typename T, size_t Size>\nconstexpr Vector<T, Size> elementWiseCube(const Vector<T, Size>& vec) noexcept {\n\tVector<T, Size> result;\n\tfor(size_t i = 0; i < Size; i++)\n\t\tresult[i] = vec[i] * vec[i] * vec[i];\n\treturn result;\n}\n\n/* computes (\n\ta.y * b.z + a.z * b.y,\n\ta.z * b.x + a.x * b.z,\n\ta.x * b.y + a.y * b.x\n)*/\ntemplate<typename T>\nconstexpr Vector<T, 3> mulOppositesBiDir(const Vector<T, 3>& a, const Vector<T, 3>& b) noexcept {\n\treturn Vector<T, 3>(\n\t\ta[1] * b[2] + a[2] * b[1],\n\t\ta[2] * b[0] + a[0] * b[2],\n\t\ta[0] * b[1] + a[1] * b[0]\n\t\t);\n}\n// computes (vec.y * vec.z, vec.z * vec.x, vec.x * vec.y)\ntemplate<typename T>\nconstexpr Vector<T, 3> mulSelfOpposites(const Vector<T, 3>& vec) noexcept {\n\treturn Vector<T, 3>(vec[1] * vec[2], vec[2] * vec[0], vec[0] * vec[1]);\n}\n// computes (vec.y + vec.z, vec.z + vec.x, vec.x + vec.y)\ntemplate<typename T>\nconstexpr Vector<T, 3> addSelfOpposites(const Vector<T, 3>& vec) noexcept {\n\treturn Vector<T, 3>(vec[1] + vec[2], vec[2] + vec[0], vec[0] + vec[1]);\n}\n\ntemplate<typename T, size_t Size>\nconstexpr size_t getMaxElementIndex(const Vector<T, Size>& vec) noexcept {\n\tsize_t max = 0;\n\n\tfor(size_t i = 1; i < Size; i++) {\n\t\tif(vec[i] > vec[max]) {\n\t\t\tmax = i;\n\t\t}\n\t}\n\treturn max;\n}\ntemplate<typename T, size_t Size>\nconstexpr size_t getMinElementIndex(const Vector<T, Size>& vec) noexcept {\n\tsize_t min = 0;\n\n\tfor(size_t i = 1; i < Size; i++) {\n\t\tif(vec[i] > vec[min]) {\n\t\t\tmin = i;\n\t\t}\n\t}\n\treturn min;\n}\ntemplate<typename T, size_t Size>\nconstexpr size_t getAbsMaxElementIndex(const Vector<T, Size>& vec) noexcept {\n\tsize_t max = 0;\n\n\tfor(size_t i = 1; i < Size; i++) {\n\t\tif(std::abs(vec[i]) > std::abs(vec[max])) {\n\t\t\tmax = i;\n\t\t}\n\t}\n\treturn max;\n}\n\ntemplate<typename T, size_t Size>\nconstexpr size_t getAbsMinElementIndex(const Vector<T, Size>& vec) noexcept {\n\tsize_t min = 0;\n\n\tfor(size_t i = 1; i < Size; i++) {\n\t\tif(std::abs(vec[i]) < std::abs(vec[min])) {\n\t\t\tmin = i;\n\t\t}\n\t}\n\treturn min;\n}\n\ntemplate<typename T, size_t Size>\nconstexpr T sumElements(const Vector<T, Size>& vec) noexcept {\n\tT sum = vec[0];\n\tfor(size_t i = 1; i < Size; i++) {\n\t\tsum += vec[i];\n\t}\n\treturn sum;\n}\n\ntemplate<typename T, size_t Size>\nconstexpr auto angleBetween(const Vector<T, Size>& first, const Vector<T, Size>& second) noexcept -> decltype(acos(normalize(first)* normalize(second))) {\n\treturn acos(normalize(first) * normalize(second));\n}\n\ntemplate<typename T, size_t Size>\nconstexpr Vector<T, Size> bisect(const Vector<T, Size>& first, const Vector<T, Size>& second) noexcept {\n\treturn first * length(second) + second * length(first);\n}\n};\n"
  },
  {
    "path": "Physics3D/math/mathUtil.h",
    "content": "#pragma once\n\n#include <cstdlib>\n\nnamespace P3D {\n/*\n\tReturns a random number between fMin and fMax\n*/\ninline double fRand(double fMin, double fMax) {\n\tdouble f = (double) rand() / RAND_MAX;\n\treturn fMin + f * (fMax - fMin);\n}\n\n/*\n\tReturns the amount of leading zeros \n*/\ninline uint32_t ctz(uint32_t n) {\n#ifdef _MSC_VER\n\tunsigned long ret = 0;\n\t_BitScanForward(&ret, static_cast<unsigned long>(n));\n\treturn static_cast<uint32_t>(ret);\n#else\n\treturn static_cast<uint32_t>(__builtin_ctz(n));\n#endif\n}\n\n/*\n\tReturns whether the given whole number is a power of 2\n*/\ntemplate<typename T>\nconstexpr bool powOf2(T n) {\n\treturn n && !(n & n - 1);\n}\n\ntemplate<typename T>\nconstexpr T bmask(char x) {\n\treturn static_cast<T>(1) << x;\n}\n\ntemplate<typename T, typename M>\nconstexpr void bmset(T& n, M mask) {\n\tn |= mask;\n}\n\ntemplate<typename T>\nconstexpr void bset(T& n, char x) {\n\tbmset(n, bmask<T>(x));\n}\n\ntemplate<typename T, typename M>\nconstexpr void bmclear(T& n, M mask) {\n\tn &= ~mask;\n}\n\ntemplate<typename T>\nconstexpr void bclear(T& n, char x) {\n\tbmclear(n, bmask<T>(x));\n}\n\ntemplate<typename T, typename M>\nconstexpr void bmflip(T& n, M mask) {\n\tn ^= mask;\n}\n\ntemplate<typename T>\nconstexpr void bflip(T& n, char x) {\n\tbmflip(n, bmask<T>(x));\n}\n\ntemplate<typename T, typename M>\nconstexpr bool bmtest(T n, M mask) {\n\treturn n & mask;\n}\n\ntemplate<typename T>\nconstexpr bool btest(T n, char x) {\n\treturn bmtest(n, bmask<T>(x));\n}\n};"
  },
  {
    "path": "Physics3D/math/position.h",
    "content": "#pragma once\n\n#include \"fix.h\"\n#include \"linalg/vec.h\"\n\nnamespace P3D {\ntypedef Vector<Fix<32>, 3> Vec3Fix;\n\ntemplate<typename T>\nstruct PositionTemplate {\n\tT x;\n\tT y;\n\tT z;\n\tconstexpr PositionTemplate() noexcept : x(), y(), z() {}\n\tconstexpr PositionTemplate(const PositionTemplate&) = default;\n\tconstexpr PositionTemplate& operator=(const PositionTemplate&) = default;\n\ttemplate<typename OtherT>\n\tconstexpr PositionTemplate(const PositionTemplate<OtherT>& other) : x(static_cast<T>(other.x)), y(static_cast<T>(other.y)), z(static_cast<T>(other.z)) {}\n\ttemplate<typename OtherT>\n\tconstexpr PositionTemplate& operator=(const PositionTemplate<OtherT>& other) {\n\t\tthis->x = static_cast<T>(other.x);\n\t\tthis->y = static_cast<T>(other.y);\n\t\tthis->z = static_cast<T>(other.z);\n\t\treturn *this;\n\t}\n\tconstexpr PositionTemplate(T x, T y, T z) noexcept : x(x), y(y), z(z) {}\n\tconstexpr PositionTemplate(double x, double y, double z) noexcept : x(T(x)), y(T(y)), z(T(z)) {}\n};\ntypedef PositionTemplate<Fix<32>> Position;\n\ntemplate<typename T>\nconstexpr Vector<T, 3> operator-(const PositionTemplate<T>& a, const PositionTemplate<T>& b) noexcept {\n\treturn Vector<T, 3>(a.x - b.x, a.y - b.y, a.z - b.z);\n}\ntemplate<typename PT, typename VT>\nconstexpr PositionTemplate<PT> operator+(const PositionTemplate<PT>& a, const Vector<VT, 3>& b) noexcept {\n\treturn PositionTemplate<PT>(a.x + b.x, a.y + b.y, a.z + b.z);\n}\ntemplate<typename PT, typename VT>\nconstexpr PositionTemplate<PT> operator-(const PositionTemplate<PT>& a, const Vector<VT, 3>& b) noexcept {\n\treturn PositionTemplate<PT>(a.x - b.x, a.y - b.y, a.z - b.z);\n}\ntemplate<typename PT, typename VT>\nconstexpr void operator+=(PositionTemplate<PT>& pos, const Vector<VT, 3>& offset) noexcept {\n//inline void operator+=(Position& pos, const Vec3Fix& offset) noexcept {\n\t//int64_t tester = offset.x.value;\n\tpos.x += offset.x;\n\tpos.y += offset.y;\n\tpos.z += offset.z;\n}\ntemplate<typename PT, typename VT>\nconstexpr void operator-=(PositionTemplate<PT>& pos, const Vector<VT, 3>& offset) noexcept {\n//inline void operator-=(Position& pos, const Vec3Fix& offset) noexcept {\n\t//int64_t tester = offset.x.value;\n\tpos.x -= offset.x;\n\tpos.y -= offset.y;\n\tpos.z -= offset.z;\n}\n\ntemplate<typename T>\nconstexpr bool operator==(const PositionTemplate<T>& first, const PositionTemplate<T>& second) noexcept {\n\treturn first.x == second.x && first.y == second.y && first.z == second.z;\n}\ntemplate<typename T>\nconstexpr bool operator!=(const PositionTemplate<T>& first, const PositionTemplate<T>& second) noexcept {\n\treturn first.x != second.x || first.y != second.y || first.z != second.z;\n}\n\ntemplate<typename T>\nconstexpr PositionTemplate<T> max(const PositionTemplate<T>& p1, const PositionTemplate<T>& p2) noexcept {\n\treturn PositionTemplate<T>(p1.x > p2.x ? p1.x : p2.x, p1.y > p2.y ? p1.y : p2.y, p1.z > p2.z ? p1.z : p2.z);\n}\ntemplate<typename T>\nconstexpr PositionTemplate<T> min(const PositionTemplate<T>& p1, const PositionTemplate<T>& p2) noexcept {\n\treturn PositionTemplate<T>(p1.x < p2.x ? p1.x : p2.x, p1.y < p2.y ? p1.y : p2.y, p1.z < p2.z ? p1.z : p2.z);\n}\ntemplate<typename T>\nconstexpr PositionTemplate<T> avg(const PositionTemplate<T>& first, const PositionTemplate<T>& second) noexcept {\n\treturn PositionTemplate<T>((first.x + second.x) / 2, (first.y + second.y) / 2, (first.z + second.z) / 2);\n}\n\n// unconventional operator, compares xyz individually, returns true if all are true\ntemplate<typename T>\nconstexpr bool operator>=(const PositionTemplate<T>& first, const PositionTemplate<T>& second) noexcept { return first.x >= second.x && first.y >= second.y && first.z >= second.z; }\n// unconventional operator, compares xyz individually, returns true if all are true\ntemplate<typename T>\nconstexpr bool operator<=(const PositionTemplate<T>& first, const PositionTemplate<T>& second) noexcept { return first.x <= second.x && first.y <= second.y && first.z <= second.z; }\n// unconventional operator, compares xyz individually, returns true if all are true\ntemplate<typename T>\nconstexpr bool operator>(const PositionTemplate<T>& first, const PositionTemplate<T>& second) noexcept { return first.x > second.x && first.y > second.y && first.z > second.z; }\n// unconventional operator, compares xyz individually, returns true if all are true\ntemplate<typename T>\nconstexpr bool operator<(const PositionTemplate<T>& first, const PositionTemplate<T>& second) noexcept { return first.x < second.x && first.y < second.y && first.z < second.z; }\n\n\n// cast Vec3 to Position, not recommended due to potential loss of precision\nconstexpr Position castVec3ToPosition(const Vec3& vec) noexcept {\n\treturn Position(vec.x, vec.y, vec.z);\n}\n// cast Vec3f to Position, not recommended due to potential loss of precision\nconstexpr Position castVec3fToPosition(const Vec3f& vec) noexcept {\n\treturn Position(vec.x, vec.y, vec.z);\n}\n// cast Position to Vec3, not recommended due to potential loss of precision\n// If possible, compute relative positions, eg: pos1-pos2 = vec3 delta\nconstexpr Vec3 castPositionToVec3(const Position& pos) noexcept {\n\treturn Vec3(static_cast<double>(pos.x), static_cast<double>(pos.y), static_cast<double>(pos.z));\n}\n// cast Position to Vec3f, not recommended due to potential loss of precision\n// If possible, compute relative positions, eg: pos1-pos2 = vec3f delta\nconstexpr Vec3f castPositionToVec3f(const Position& pos) noexcept {\n\treturn Vec3f(static_cast<float>(pos.x), static_cast<float>(pos.y), static_cast<float>(pos.z));\n}\n};"
  },
  {
    "path": "Physics3D/math/predefinedTaylorExpansions.h",
    "content": "#pragma once\n\n#include <cmath>\n#include <stddef.h>\n\n#include \"taylorExpansion.h\"\n#include \"linalg/trigonometry.h\"\n\nnamespace P3D {\ntemplate<typename T, std::size_t N>\nTaylorExpansion<T, N> generateTaylorForSinWave(T currentAngle, T frequencyMultiplier) {\n\tTaylorExpansion<T, N> result;\n\n\tT cosValue = std::cos(currentAngle * frequencyMultiplier);\n\tresult[0] = cosValue * frequencyMultiplier;\n\tif constexpr(N > 1) {\n\t\tT totalMultiplier = frequencyMultiplier;\n\t\tT sinValue = std::sin(currentAngle * frequencyMultiplier);\n\t\tT values[4]{cosValue, -sinValue, -cosValue, sinValue};\n\t\tfor(std::size_t i = 1; i < N; i++) {\n\t\t\ttotalMultiplier *= frequencyMultiplier;\n\t\t\tresult[i] = values[i % 4] * totalMultiplier;\n\t\t}\n\t}\n\n\treturn result;\n}\n\ntemplate<typename T, std::size_t N>\nTaylorExpansion<T, N> generateTaylorForCosWave(T currentAngle, T frequencyMultiplier) {\n\tTaylorExpansion<T, N> result;\n\n\tT sinValue = std::sin(currentAngle * frequencyMultiplier);\n\tresult[0] = -sinValue * frequencyMultiplier;\n\tif constexpr(N > 1) {\n\t\tT totalMultiplier = frequencyMultiplier;\n\t\tT cosValue = std::cos(currentAngle * frequencyMultiplier);\n\t\tT values[4]{-sinValue, -cosValue, sinValue, cosValue};\n\t\tfor(std::size_t i = 1; i < N; i++) {\n\t\t\ttotalMultiplier *= frequencyMultiplier;\n\t\t\tresult[i] = values[i % 4] * totalMultiplier;\n\t\t}\n\t}\n\n\treturn result;\n}\n\ntemplate<typename T, std::size_t N>\nFullTaylorExpansion<T, N> generateFullTaylorForSinWave(T currentAngle, T frequencyMultiplier) {\n\tT sinValue = std::sin(currentAngle * frequencyMultiplier);\n\tT cosValue = std::cos(currentAngle * frequencyMultiplier);\n\n\tFullTaylorExpansion<T, N> result{sinValue};\n\n\tT values[4]{cosValue, -sinValue, -cosValue, sinValue};\n\n\tT totalMultiplier = frequencyMultiplier;\n\tfor(std::size_t i = 0; i < N - 1; i++) {\n\t\tresult.setDerivative(i, values[i % 4] * totalMultiplier);\n\t\ttotalMultiplier *= frequencyMultiplier;\n\t}\n\n\treturn result;\n}\n\ntemplate<typename T, std::size_t N>\nFullTaylorExpansion<T, N> generateFullTaylorForCosWave(T currentAngle, T frequencyMultiplier) {\n\tT sinValue = std::sin(currentAngle * frequencyMultiplier);\n\tT cosValue = std::cos(currentAngle * frequencyMultiplier);\n\n\tFullTaylorExpansion<T, N> result{cosValue};\n\n\tT values[4]{-sinValue, -cosValue, sinValue, cosValue};\n\n\tT totalMultiplier = frequencyMultiplier;\n\tfor(std::size_t i = 0; i < N - 1; i++) {\n\t\tresult.setDerivative(i, values[i % 4] * totalMultiplier);\n\t\ttotalMultiplier *= frequencyMultiplier;\n\t}\n\n\treturn result;\n}\n\ntemplate<typename T, int Derivs>\nTaylorExpansion<SymmetricMatrix<T, 3>, Derivs - 1> generateTaylorForSkewSymmetricSquared(const FullTaylorExpansion<Vector<T, 3>, Derivs>& inputVector) {\n\tstatic_assert(Derivs >= 2 && Derivs <= 3);\n\n\tVector<T, 3> f = inputVector.getConstantValue();\n\n\tTaylorExpansion<SymmetricMatrix<T, 3>, Derivs - 1> result;\n\n\tif constexpr(Derivs >= 2) {\n\t\tVector<T, 3> ff = inputVector.getDerivative(0);\n\t\tVector<T, 3> ffxf = elementWiseMul(ff, f);\n\t\tVector<T, 3> ffMixed = mulOppositesBiDir(ff, f);\n\n\t\tresult[0] = SymmetricMatrix<T, 3>{\n\t\t\t-2 * (ffxf.y + ffxf.z),\n\t\t\tffMixed.z, -2 * (ffxf.x + ffxf.z),\n\t\t\tffMixed.y, ffMixed.x, -2 * (ffxf.x + ffxf.y)\n\t\t};\n\n\t\tif constexpr(Derivs >= 3) {\n\t\t\tVector<T, 3> fff = inputVector.getDerivative(1);\n\t\t\tVector<T, 3> fffxf = elementWiseSquare(ff) + elementWiseMul(fff, f);\n\t\t\tVector<T, 3> fffMixed = mulOppositesBiDir(f, fff) + mulSelfOpposites(ff) * T(2);\n\n\t\t\tresult[1] = SymmetricMatrix<T, 3>{\n\t\t\t\t-2 * (fffxf.y + fffxf.z),\n\t\t\t\tfffMixed.z, -2 * (fffxf.x + fffxf.z),\n\t\t\t\tfffMixed.y, fffMixed.x, -2 * (fffxf.x + fffxf.y)\n\t\t\t};\n\t\t}\n\t}\n\n\treturn result;\n}\n\ntemplate<typename T, int Derivs>\nFullTaylorExpansion<SymmetricMatrix<T, 3>, Derivs> generateFullTaylorForSkewSymmetricSquared(const FullTaylorExpansion<Vector<T, 3>, Derivs>& inputVector) {\n\treturn FullTaylorExpansion<SymmetricMatrix<T, 3>, Derivs>::fromConstantAndDerivatives(skewSymmetricSquared(inputVector.getConstantValue()), generateTaylorForSkewSymmetricSquared<double, Derivs>(inputVector));\n}\n\ntemplate<typename T, int Derivs>\nTaylorExpansion<Mat3, Derivs> generateTaylorForRotationMatrix(const TaylorExpansion<Vec3, Derivs>& rotationVecTaylor, const Matrix<T, 3, 3>& rotation) {\n\tMat3 angularVelEquiv = createCrossProductEquivalent(rotationVecTaylor[0]);\n\n\tTaylorExpansion<Mat3, Derivs> result;\n\tresult[0] = angularVelEquiv * rotation;\n\n\tif constexpr(Derivs >= 2) {\n\t\tMat3 angularAccelEquiv = createCrossProductEquivalent(rotationVecTaylor[1]);\n\t\tresult[1] = (angularAccelEquiv + angularVelEquiv * angularVelEquiv) * rotation;\n\t}\n\n\t// TODO add further derivatives\n\n\treturn result;\n}\n};"
  },
  {
    "path": "Physics3D/math/ray.h",
    "content": "#pragma once\n\n#include \"linalg/vec.h\"\n#include \"position.h\"\n#include \"bounds.h\"\n\nnamespace P3D {\n\nstruct Ray {\n\tconstexpr static double EPSILON = 0.0000001;\n\n\tPosition origin;\n\tVec3 direction;\n\n\tPosition intersect(double t) {\n\t\treturn origin + direction * t;\n\t}\n\n\tdouble hitPlane(const Position& point, const Vec3& normal) const {\n\t\tdouble denominator = direction * normal;\n\n\t\tif (std::abs(denominator) < EPSILON)\n\t\t\treturn std::numeric_limits<double>::infinity();\n\n\t\tdouble t = (point - origin) * normal / denominator;\n\n\t\treturn t;\n\t}\n\n\tdouble hitDisk(const Position& center, const Vec3& normal, double radius) {\n\t\tdouble t = hitPlane(center, normal);\n\n\t\tPosition intersection = intersect(t);\n\n\t\tif (lengthSquared(castPositionToVec3(intersection)) < radius * radius)\n\t\t\treturn std::numeric_limits<double>::infinity();\n\n\t\treturn t;\n\t}\n\n\tdouble hitSphere(const Position& center, double radius) {\n\t\tVec3 temp = origin - center;\n\t\tdouble a = direction * direction;\n\t\tdouble b = 2.0 * temp * direction;\n\t\tdouble c = temp * temp - radius * radius;\n\t\tdouble discriminant = b * b - 4.0 * a * c;\n\n\t\tif (discriminant < 0.0)\n\t\t\treturn std::numeric_limits<double>::infinity();\n\n\t\tdouble e = std::sqrt(discriminant);\n\t\tdouble t = (-b - e) / 2.0 / a;\n\n\t\tif (t > EPSILON)\n\t\t\treturn t;\n\n\t\tt = (-b + e) / 2.0 / a;\n\n\t\tif (t > EPSILON)\n\t\t\treturn t;\n\n\t\treturn std::numeric_limits<double>::infinity();\n\t}\n\n\tdouble hitTriangle(const Vec3& v0, const Vec3& v1, const Vec3& v2) const {\n\t\tdouble a = v0.x - v1.x;\n\t\tdouble b = v0.x - v2.x;\n\t\tdouble c = direction.x;\n\t\tdouble d = v0.x - origin.x;\n\n\t\tdouble e = v0.y - v1.y;\n\t\tdouble f = v0.y - v2.y;\n\t\tdouble g = direction.x;\n\t\tdouble h = v0.y - origin.y;\n\n\t\tdouble i = v0.z - v1.z;\n\t\tdouble j = v0.z - v2.z;\n\t\tdouble k = direction.z;\n\t\tdouble l = v0.z - origin.z;\n\n\t\tdouble m = f * k - g * j;\n\t\tdouble n = k * k - g * l;\n\t\tdouble p = f * l - h * j;\n\t\tdouble q = g * i - e * k;\n\t\tdouble s = e * j - f * i;\n\n\t\tdouble inverseDenominator = 1.0 * (a * m + b * q + c * s);\n\t\tdouble e1 = d * m - b * n - c * p;\n\t\tdouble beta = e1 * inverseDenominator;\n\n\t\tif (beta < 0.0)\n\t\t\treturn std::numeric_limits<double>::infinity();\n\n\t\tdouble r = e * l - h * i;\n\t\tdouble e2 = a * n + d * q + c * r;\n\t\tdouble gamma = e2 * inverseDenominator;\n\n\t\tif (gamma < 0.0)\n\t\t\treturn std::numeric_limits<double>::infinity();\n\n\t\tif (beta + gamma > 1.0)\n\t\t\treturn std::numeric_limits<double>::infinity();\n\n\t\tdouble e3 = a * p - b * r + d * s;\n\t\tdouble t = e3 * inverseDenominator;\n\n\t\tif (t < EPSILON)\n\t\t\treturn std::numeric_limits<double>::infinity();\n\n\t\treturn t;\n\t}\n};\n\n/*\n\tReturns true if the given ray intersects the given bounds. \n*/\ninline bool doRayAndBoundsIntersect(const Bounds& bounds, const Ray& ray) {\n\t// everything is computed relative to the ray origin\n\n\tVec3Fix lMin = bounds.min - ray.origin;\n\tVec3Fix lMax = bounds.max - ray.origin;\n\n\tVec3 dir = ray.direction;\n\n\t{\n\t\tVec3Fix intersectingSide = (dir.x > 0) ? lMin : lMax;\n\t\tdouble intersectionDistance = static_cast<double>(intersectingSide.x) / dir.x;\n\t\tVec3Fix intersect = dir * intersectionDistance;\n\t\tif (intersect.y >= lMin.y && intersect.z >= lMin.z && intersect.y <= lMax.y && intersect.z <= lMax.z) {\n\t\t\treturn true;\n\t\t}\n\t}\n\t{\n\t\tVec3Fix intersectingSide = (dir.y > 0) ? lMin : lMax;\n\t\tdouble intersectionDistance = static_cast<double>(intersectingSide.y) / dir.y;\n\t\tVec3Fix intersect = dir * intersectionDistance;\n\t\tif (intersect.x >= lMin.x && intersect.z >= lMin.z && intersect.x <= lMax.x && intersect.z <= lMax.z) {\n\t\t\treturn true;\n\t\t}\n\t}\n\t{\n\t\tVec3Fix intersectingSide = (dir.z > 0) ? lMin : lMax;\n\t\tdouble intersectionDistance = static_cast<double>(intersectingSide.z) / dir.z;\n\t\tVec3Fix intersect = dir * intersectionDistance;\n\t\tif (intersect.x >= lMin.x && intersect.y >= lMin.y && intersect.x <= lMax.x && intersect.y <= lMax.y) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n};"
  },
  {
    "path": "Physics3D/math/rotation.h",
    "content": "#pragma once\n\n#include \"linalg/mat.h\"\n#include \"linalg/trigonometry.h\"\n#include \"linalg/quat.h\"\n#include \"constants.h\"\n\n#include <assert.h>\n#include <cmath>\n\nnamespace P3D {\ntemplate<typename T>\nclass MatrixRotationTemplate {\n\tMatrix<T, 3, 3> rotationMatrix;\n\tconstexpr explicit MatrixRotationTemplate(const Matrix<T, 3, 3>& rotationMatrix) : rotationMatrix(rotationMatrix) {}\npublic:\n\n\tconstexpr MatrixRotationTemplate();\n\n\tVector<T, 3> localToGlobal(const Vector<T, 3>& vec) const;\n\tVector<T, 3> globalToLocal(const Vector<T, 3>& vec) const;\n\tMatrixRotationTemplate localToGlobal(const MatrixRotationTemplate<T>& rot) const;\n\tMatrixRotationTemplate globalToLocal(const MatrixRotationTemplate<T>& rot) const;\n\n\t/*\n\t\tTransforms the given symmetric matrix into the basis of this rotation\n\n\t\teffectively brings a local matrix into the global space\n\n\t\tdefined as   rot * sm * ~rot\n\n\t\trot.localToGlobal(sm * v) == rot.localToGlobal(sm) * rot.localToGlobal(v)\n\t\t== (rot * sm * ~rot) * rot * v == (rot * sm) * v == rot * (sm * v)\n\t*/\n\tSymmetricMatrix<T, 3> localToGlobal(const SymmetricMatrix<T, 3>& sm) const;\n\n\t/*\n\t\tTransforms the given symmetric matrix from the basis of this rotation\n\n\t\teffectively brings a global matrix into the local space\n\n\t\tdefined as   ~rot * sm * rot\n\n\t\trot.globalToLocal(sm * v) == rot.globalToLocal(sm) * rot.globalToLocal(v)\n\t\t== (~rot * sm * rot) * ~rot * v == (~rot * sm) * v == ~rot * (sm * v)\n\t*/\n\tSymmetricMatrix<T, 3> globalToLocal(const SymmetricMatrix<T, 3>& sm) const;\n\n\tMatrixRotationTemplate operator~() const;\n\tMatrixRotationTemplate operator*(const MatrixRotationTemplate& rot2) const;\n\tMatrixRotationTemplate& operator*=(const MatrixRotationTemplate& rot2);\n\tVector<T, 3> operator*(const Vector<T, 3>& vec) const;\n\n\t/* returns the projection of the x-axis\n\t\t== this->localToGlobal(Vec3(1,0,0)) */\n\tVector<T, 3> getX() const;\n\t/* returns the projection of the y-axis\n\t\t== this->localToGlobal(Vec3(0,1,0)) */\n\tVector<T, 3> getY() const;\n\t/* returns the projection of the z-axis\n\t\t== this->localToGlobal(Vec3(0,0,1)) */\n\tVector<T, 3> getZ() const;\n\n\tstatic MatrixRotationTemplate rotX(T angle);\n\tstatic MatrixRotationTemplate rotY(T angle);\n\tstatic MatrixRotationTemplate rotZ(T angle);\n\tstatic MatrixRotationTemplate fromEulerAngles(T alpha, T beta, T gamma) {\n\t\treturn MatrixRotationTemplate<T>::rotZ(gamma) * MatrixRotationTemplate<T>::rotX(alpha) * MatrixRotationTemplate<T>::rotY(beta);\n\t}\n\tstatic MatrixRotationTemplate fromDirection(const Vector<T, 3>& direction, const Vector<T, 3>& up = { 0, 1, 0 });\n\tstatic MatrixRotationTemplate fromRotationVector(const Vector<T, 3>& rotationVector);\n\tstatic MatrixRotationTemplate fromRotationMatrix(const Matrix<T, 3, 3>& rotationMatrix);\n\tstatic MatrixRotationTemplate fromRotationQuaternion(const Quaternion<T>& rotationQuaternion);\n\n\n\tstatic MatrixRotationTemplate faceX(Vector<T, 3> xDirection);\n\tstatic MatrixRotationTemplate faceX(Vector<T, 3> xDirection, Vector<T, 3> yHint);\n\tstatic MatrixRotationTemplate faceY(Vector<T, 3> yDirection);\n\tstatic MatrixRotationTemplate faceY(Vector<T, 3> yDirection, Vector<T, 3> zHint);\n\tstatic MatrixRotationTemplate faceZ(Vector<T, 3> zDirection);\n\tstatic MatrixRotationTemplate faceZ(Vector<T, 3> zDirection, Vector<T, 3> xHint);\n\n\tMatrix<T, 3, 3> asRotationMatrix() const;\n\tQuaternion<T> asRotationQuaternion() const;\n\tVector<T, 3> asRotationVector() const;\n\n\t/*operator Matrix<T, 3, 3>() const {\n\t\treturn this->asRotationMatrix();\n\t}*/\n\n\ttemplate<typename OtherT>\n\toperator MatrixRotationTemplate<OtherT>() const;\n\n\tstruct Predefined{\n\t\tstatic constexpr MatrixRotationTemplate<T> IDENTITY{Matrix<T, 3, 3>{1,0,0,0,1,0,0,0,1}};\n\n\t\tstatic constexpr MatrixRotationTemplate<T> X_90 {Matrix<T, 3, 3>{ 1, 0, 0, 0, 0,-1, 0, 1, 0}};\n\t\tstatic constexpr MatrixRotationTemplate<T> Y_90 {Matrix<T, 3, 3>{ 0, 0, 1, 0, 1, 0,-1, 0, 0}};\n\t\tstatic constexpr MatrixRotationTemplate<T> Z_90 {Matrix<T, 3, 3>{ 0,-1, 0, 1, 0, 0, 0, 0, 1}};\n\n\t\tstatic constexpr MatrixRotationTemplate<T> X_180{Matrix<T, 3, 3>{ 1, 0, 0, 0,-1, 0, 0, 0,-1}};\n\t\tstatic constexpr MatrixRotationTemplate<T> Y_180{Matrix<T, 3, 3>{-1, 0, 0, 0, 1, 0, 0, 0,-1}};\n\t\tstatic constexpr MatrixRotationTemplate<T> Z_180{Matrix<T, 3, 3>{-1, 0, 0, 0,-1, 0, 0, 0, 1}};\n\n\t\tstatic constexpr MatrixRotationTemplate<T> X_270{Matrix<T, 3, 3>{ 1, 0, 0, 0, 0, 1, 0,-1, 0}};\n\t\tstatic constexpr MatrixRotationTemplate<T> Y_270{Matrix<T, 3, 3>{ 0, 0,-1, 0, 1, 0, 1, 0, 0}};\n\t\tstatic constexpr MatrixRotationTemplate<T> Z_270{Matrix<T, 3, 3>{ 0, 1, 0,-1, 0, 0, 0, 0, 1}};\n\t};\n};\n\ntemplate<typename T>\nclass QuaternionRotationTemplate {\n\tQuaternion<T> rotationQuaternion;\n\tconstexpr explicit QuaternionRotationTemplate(const Quaternion<T>& rotationQuaternion) : rotationQuaternion(rotationQuaternion) {};\npublic:\n\n\tconstexpr QuaternionRotationTemplate();\n\n\tVector<T, 3> localToGlobal(const Vector<T, 3>& vec) const;\n\tVector<T, 3> globalToLocal(const Vector<T, 3>& vec) const;\n\tQuaternionRotationTemplate localToGlobal(const QuaternionRotationTemplate<T>& rot) const;\n\tQuaternionRotationTemplate globalToLocal(const QuaternionRotationTemplate<T>& rot) const;\n\n\t/*\n\t\tTransforms the given symmetric matrix into the basis of this rotation\n\n\t\teffectively brings a local matrix into the global space\n\n\t\tdefined as   q * sm * ~q\n\n\t\tq.localToGlobal(sm * v) == q.localToGlobal(sm) * q.localToGlobal(v)\n\t\t== (q * sm * ~q) * q * v * ~q == (q * sm) * v * ~q == q * (sm * v) * ~q\n\t*/\n\tSymmetricMatrix<T, 3> localToGlobal(const SymmetricMatrix<T, 3>& sm) const;\n\n\t/*\n\t\tTransforms the given symmetric matrix from the basis of this rotation\n\n\t\teffectively brings a global matrix into the local space\n\n\t\tdefined as   ~q * sm * q\n\n\t\tq.globalToLocal(sm * v) == q.globalToLocal(sm) * q.globalToLocal(v)\n\t\t== (~q * sm * q) * ~q * v * q == (~q * sm) * v * q == ~q * (sm * v) * q\n\t*/\n\tSymmetricMatrix<T, 3> globalToLocal(const SymmetricMatrix<T, 3>& sm) const;\n\n\tQuaternionRotationTemplate operator~() const;\n\tQuaternionRotationTemplate operator*(const QuaternionRotationTemplate& rot2) const;\n\tQuaternionRotationTemplate& operator*=(const QuaternionRotationTemplate& rot2);\n\tVector<T, 3> operator*(const Vector<T, 3>& vec) const;\n\t\n\t/* returns the projection of the x-axis\n\t\t== this->localToGlobal(Vec3(1,0,0)) */\n\tVector<T, 3> getX() const;\n\t/* returns the projection of the y-axis\n\t\t== this->localToGlobal(Vec3(0,1,0)) */\n\tVector<T, 3> getY() const;\n\t/* returns the projection of the z-axis\n\t\t== this->localToGlobal(Vec3(0,0,1)) */\n\tVector<T, 3> getZ() const;\n\n\tstatic QuaternionRotationTemplate rotX(T angle);\n\tstatic QuaternionRotationTemplate rotY(T angle);\n\tstatic QuaternionRotationTemplate rotZ(T angle);\n\tstatic QuaternionRotationTemplate fromEulerAngles(T alpha, T beta, T gamma) {\n\t\treturn QuaternionRotationTemplate<T>::rotZ(gamma) * QuaternionRotationTemplate<T>::rotX(alpha) * QuaternionRotationTemplate<T>::rotY(beta);\n\t}\n\tstatic QuaternionRotationTemplate fromRotationVec(const Vector<T, 3>& rotationVector);\n\tstatic QuaternionRotationTemplate fromRotationMatrix(const Matrix<T, 3, 3>& rotationMatrix);\n\tstatic QuaternionRotationTemplate fromRotationQuaternion(const Quaternion<T>& rotationQuaternion);\n\n\tstatic QuaternionRotationTemplate faceX(Vector<T, 3> xDirection);\n\tstatic QuaternionRotationTemplate faceX(Vector<T, 3> xDirection, Vector<T, 3> yHint);\n\tstatic QuaternionRotationTemplate faceY(Vector<T, 3> yDirection);\n\tstatic QuaternionRotationTemplate faceY(Vector<T, 3> yDirection, Vector<T, 3> zHint);\n\tstatic QuaternionRotationTemplate faceZ(Vector<T, 3> zDirection);\n\tstatic QuaternionRotationTemplate faceZ(Vector<T, 3> zDirection, Vector<T, 3> xHint);\n\n\tMatrix<T, 3, 3> asRotationMatrix() const;\n\tQuaternion<T> asRotationQuaternion() const;\n\tVector<T, 3> asRotationVector() const;\n\n\t/*operator Matrix<T, 3, 3>() const {\n\t\treturn this->asRotationMatrix();\n\t}*/\n\n\ttemplate<typename OtherT>\n\toperator QuaternionRotationTemplate<OtherT>() const;\n\n\tstruct Predefined{\n\t\tstatic constexpr QuaternionRotationTemplate<T> IDENTITY{Quaternion<T>(1,0,0,0)};\n\n\t\tstatic constexpr QuaternionRotationTemplate<T> X_90 {Quaternion<T>(sq2_2<T>(), sq2_2<T>(), 0, 0)};\n\t\tstatic constexpr QuaternionRotationTemplate<T> Y_90 {Quaternion<T>(sq2_2<T>(), 0, sq2_2<T>(), 0)};\n\t\tstatic constexpr QuaternionRotationTemplate<T> Z_90 {Quaternion<T>(sq2_2<T>(), 0, 0, sq2_2<T>())};\n\n\t\tstatic constexpr QuaternionRotationTemplate<T> X_180{Quaternion<T>(0, 1, 0, 0)};\n\t\tstatic constexpr QuaternionRotationTemplate<T> Y_180{Quaternion<T>(0, 0, 1, 0)};\n\t\tstatic constexpr QuaternionRotationTemplate<T> Z_180{Quaternion<T>(0, 0, 0, 1)};\n\n\t\tstatic constexpr QuaternionRotationTemplate<T> X_270{Quaternion<T>(sq2_2<T>(), -sq2_2<T>(), 0, 0)};\n\t\tstatic constexpr QuaternionRotationTemplate<T> Y_270{Quaternion<T>(sq2_2<T>(), 0, -sq2_2<T>(), 0)};\n\t\tstatic constexpr QuaternionRotationTemplate<T> Z_270{Quaternion<T>(sq2_2<T>(), 0, 0, -sq2_2<T>())};\n\t};\n};\n\n\n\ntemplate<typename T>\nconstexpr MatrixRotationTemplate<T>::MatrixRotationTemplate() : rotationMatrix(Matrix<T, 3, 3>::IDENTITY()) {}\n\ntemplate<typename T>\nVector<T, 3> MatrixRotationTemplate<T>::localToGlobal(const Vector<T, 3>& vec) const {\n\treturn rotationMatrix * vec;\n}\n\ntemplate<typename T>\nVector<T, 3> MatrixRotationTemplate<T>::globalToLocal(const Vector<T, 3>& vec) const {\n\treturn rotationMatrix.transpose() * vec;\n}\n\ntemplate<typename T>\nMatrixRotationTemplate<T> MatrixRotationTemplate<T>::localToGlobal(const MatrixRotationTemplate<T>& rot) const {\n\treturn MatrixRotationTemplate<T>(this->rotationMatrix * rot.rotationMatrix);\n}\n\ntemplate<typename T>\nMatrixRotationTemplate<T> MatrixRotationTemplate<T>::globalToLocal(const MatrixRotationTemplate<T>& rot) const {\n\treturn MatrixRotationTemplate<T>(this->rotationMatrix.transpose() * rot.rotationMatrix);\n}\n\ntemplate<typename T>\nSymmetricMatrix<T, 3> MatrixRotationTemplate<T>::localToGlobal(const SymmetricMatrix<T, 3>& sm) const {\n\treturn mulSymmetricLeftRightTranspose(sm, this->rotationMatrix);\n}\n\ntemplate<typename T>\nSymmetricMatrix<T, 3> MatrixRotationTemplate<T>::globalToLocal(const SymmetricMatrix<T, 3>& sm) const {\n\treturn mulSymmetricLeftTransposeRight(sm, this->rotationMatrix);\n}\n\ntemplate<typename T>\nMatrixRotationTemplate<T> MatrixRotationTemplate<T>::operator~() const {\n\treturn MatrixRotationTemplate<T>(rotationMatrix.transpose());\n}\n\ntemplate<typename T>\nMatrixRotationTemplate<T> MatrixRotationTemplate<T>::operator*(const MatrixRotationTemplate<T>& rot2) const {\n\treturn this->localToGlobal(rot2);\n}\n\ntemplate<typename T>\nVector<T, 3> MatrixRotationTemplate<T>::operator*(const Vector<T, 3>& vec) const {\n\treturn this->localToGlobal(vec);\n}\n\ntemplate<typename T>\nVector<T, 3> MatrixRotationTemplate<T>::getX() const {\n\treturn this->rotationMatrix.getCol(0);\n}\n\ntemplate<typename T>\nVector<T, 3> MatrixRotationTemplate<T>::getY() const {\n\treturn this->rotationMatrix.getCol(1);\n}\n\ntemplate<typename T>\nVector<T, 3> MatrixRotationTemplate<T>::getZ() const {\n\treturn this->rotationMatrix.getCol(2);\n}\n\ntemplate<typename T>\nMatrixRotationTemplate<T> MatrixRotationTemplate<T>::rotX(T angle) {\n\treturn MatrixRotationTemplate<T>(rotMatX(angle));\n}\ntemplate<typename T>\nMatrixRotationTemplate<T> MatrixRotationTemplate<T>::rotY(T angle) {\n\treturn MatrixRotationTemplate<T>(rotMatY(angle));\n}\ntemplate<typename T>\nMatrixRotationTemplate<T> MatrixRotationTemplate<T>::rotZ(T angle) {\n\treturn MatrixRotationTemplate<T>(rotMatZ(angle));\n}\n\n\ntemplate<typename T>\nMatrix<T, 3, 3> MatrixRotationTemplate<T>::asRotationMatrix() const {\n\treturn this->rotationMatrix;\n}\ntemplate<typename T>\nQuaternion<T> MatrixRotationTemplate<T>::asRotationQuaternion() const {\n\treturn rotationQuaternionFromRotationMatrix(this->rotationMatrix);\n}\ntemplate<typename T>\nVector<T, 3> MatrixRotationTemplate<T>::asRotationVector() const {\n\treturn rotationVectorFromRotationMatrix(this->rotationMatrix);\n}\n\ntemplate<typename T>\nMatrixRotationTemplate<T> MatrixRotationTemplate<T>::fromDirection(const Vector<T, 3>& direction, const Vector<T, 3>& up) {\n\tVector<T, 3> z = normalize(direction);\n\tVector<T, 3> x = normalize(z % up);\n\tVector<T, 3> y = normalize(x % z);\n\n\treturn fromRotationMatrix(Matrix<T, 3, 3> {\n\t\tx.x, y.x, -z.x,\n\t\tx.y, y.y, -z.y,\n\t\tx.z, y.z, -z.z\n\t});\n}\n\ntemplate<typename T>\nMatrixRotationTemplate<T> MatrixRotationTemplate<T>::fromRotationMatrix(const Matrix<T, 3, 3>& rotationMatrix) {\n\tassert(isValidRotationMatrix(rotationMatrix));\n\treturn MatrixRotationTemplate<T>(rotationMatrix);\n}\ntemplate<typename T>\nMatrixRotationTemplate<T> MatrixRotationTemplate<T>::fromRotationQuaternion(const Quaternion<T>& rotationQuaternion) {\n\tassert(isValidRotationQuaternion(rotationQuaternion));\n\treturn MatrixRotationTemplate<T>(rotationMatrixFromQuaternion(rotationQuaternion));\n}\ntemplate<typename T>\nMatrixRotationTemplate<T> MatrixRotationTemplate<T>::fromRotationVector(const Vector<T, 3>& rotationVector) {\n\treturn MatrixRotationTemplate<T>(rotationMatrixFromRotationVec(rotationVector));\n}\n\n\ntemplate<typename T>\nMatrixRotationTemplate<T> MatrixRotationTemplate<T>::faceX(Vector<T, 3> xDirection) {\n\treturn MatrixRotationTemplate<T>::fromRotationMatrix(faceMatX(xDirection));\n}\ntemplate<typename T>\nMatrixRotationTemplate<T> MatrixRotationTemplate<T>::faceX(Vector<T, 3> xDirection, Vector<T, 3> yHint) {\n\treturn MatrixRotationTemplate<T>::fromRotationMatrix(faceMatX(xDirection, yHint));\n}\ntemplate<typename T>\nMatrixRotationTemplate<T> MatrixRotationTemplate<T>::faceY(Vector<T, 3> yDirection) {\n\treturn MatrixRotationTemplate<T>::fromRotationMatrix(faceMatY(yDirection));\n}\ntemplate<typename T>\nMatrixRotationTemplate<T> MatrixRotationTemplate<T>::faceY(Vector<T, 3> yDirection, Vector<T, 3> zHint) {\n\treturn MatrixRotationTemplate<T>::fromRotationMatrix(faceMatY(yDirection, zHint));\n}\ntemplate<typename T>\nMatrixRotationTemplate<T> MatrixRotationTemplate<T>::faceZ(Vector<T, 3> zDirection) {\n\treturn MatrixRotationTemplate<T>::fromRotationMatrix(faceMatZ(zDirection));\n}\ntemplate<typename T>\nMatrixRotationTemplate<T> MatrixRotationTemplate<T>::faceZ(Vector<T, 3> zDirection, Vector<T, 3> xHint) {\n\treturn MatrixRotationTemplate<T>::fromRotationMatrix(faceMatZ(zDirection, xHint));\n}\n\ntemplate<typename T>\ntemplate<typename OtherT>\nMatrixRotationTemplate<T>::operator MatrixRotationTemplate<OtherT>() const {\n\treturn MatrixRotationTemplate<OtherT>::fromRotationMatrix(static_cast<Matrix<OtherT, 3, 3>>(this->rotationMatrix));\n}\n\n\n\ntemplate<typename T>\nconstexpr QuaternionRotationTemplate<T>::QuaternionRotationTemplate() : rotationQuaternion(1, 0, 0, 0) {}\n\ntemplate<typename T>\nVector<T, 3> QuaternionRotationTemplate<T>::localToGlobal(const Vector<T, 3>& v) const {\n\treturn mulQuaternionLeftRightConj(this->rotationQuaternion, v);\n}\n\ntemplate<typename T>\nVector<T, 3> QuaternionRotationTemplate<T>::globalToLocal(const Vector<T, 3>& v) const {\n\treturn mulQuaternionLeftConjRight(this->rotationQuaternion, v);\n}\n\ntemplate<typename T>\nQuaternionRotationTemplate<T> QuaternionRotationTemplate<T>::localToGlobal(const QuaternionRotationTemplate<T>& rot) const {\n\treturn QuaternionRotationTemplate<T>(this->rotationQuaternion * rot.rotationQuaternion);\n}\n\ntemplate<typename T>\nQuaternionRotationTemplate<T> QuaternionRotationTemplate<T>::globalToLocal(const QuaternionRotationTemplate<T>& rot) const {\n\treturn QuaternionRotationTemplate<T>(conj(this->rotationQuaternion) * rot.rotationQuaternion);\n}\n\ntemplate<typename T>\nSymmetricMatrix<T, 3> QuaternionRotationTemplate<T>::localToGlobal(const SymmetricMatrix<T, 3>& sm) const {\n\tSquareMatrix<T, 3> rotMat = this->asRotationMatrix();\n\treturn mulSymmetricLeftRightTranspose(sm, rotMat);\n}\n\ntemplate<typename T>\nSymmetricMatrix<T, 3> QuaternionRotationTemplate<T>::globalToLocal(const SymmetricMatrix<T, 3>& sm) const {\n\tSquareMatrix<T, 3> rotMat = this->asRotationMatrix();\n\treturn mulSymmetricLeftTransposeRight(sm, rotMat);\n}\n\ntemplate<typename T>\nQuaternionRotationTemplate<T> QuaternionRotationTemplate<T>::operator~() const {\n\treturn QuaternionRotationTemplate<T>(conj(rotationQuaternion));\n}\n\ntemplate<typename T>\nQuaternionRotationTemplate<T> QuaternionRotationTemplate<T>::operator*(const QuaternionRotationTemplate<T>& rot2) const {\n\treturn this->localToGlobal(rot2);\n}\n\ntemplate<typename T>\nVector<T, 3> QuaternionRotationTemplate<T>::operator*(const Vector<T, 3>& vec) const {\n\treturn this->localToGlobal(vec);\n}\n\ntemplate<typename T>\nVector<T, 3> QuaternionRotationTemplate<T>::getX() const {\n\tT w = this->rotationQuaternion.w;\n\tVector<T, 3> u = this->rotationQuaternion.v;\n\t\n\treturn Vector<T, 3>(\n\t\t1 - 2 * (u.y * u.y + u.z * u.z),\n\t\t2 * (u.y * u.z + w * u.z),\n\t\t2 * (u.z * u.x - w * u.y)\n\t);\n}\n\ntemplate<typename T>\nVector<T, 3> QuaternionRotationTemplate<T>::getY() const {\n\tT w = this->rotationQuaternion.w;\n\tVector<T, 3> u = this->rotationQuaternion.v;\n\t\n\treturn Vector<T, 3>(\n\t\t2 * (u.x * u.y - w * u.z),\n\t\t1 - 2 * (u.x * u.x + u.z * u.z),\n\t\t2 * (u.y * u.z + w * u.x)\n\t);\n}\n\ntemplate<typename T>\nVector<T, 3> QuaternionRotationTemplate<T>::getZ() const {\n\tT w = this->rotationQuaternion.w;\n\tVector<T, 3> u = this->rotationQuaternion.v;\n\t\n\treturn Vector<T, 3>(\n\t\t2 * (u.x * u.z + w * u.y),\n\t\t2 * (u.y * u.z - w * u.x),\n\t\t1 - 2 * (u.x * u.x + u.y * u.y)\n\t);\n}\n\ntemplate<typename T>\nQuaternionRotationTemplate<T> QuaternionRotationTemplate<T>::rotX(T angle) {\n\treturn QuaternionRotationTemplate<T>(rotQuatX(angle));\n}\ntemplate<typename T>\nQuaternionRotationTemplate<T> QuaternionRotationTemplate<T>::rotY(T angle) {\n\treturn QuaternionRotationTemplate<T>(rotQuatY(angle));\n}\ntemplate<typename T>\nQuaternionRotationTemplate<T> QuaternionRotationTemplate<T>::rotZ(T angle) {\n\treturn QuaternionRotationTemplate<T>(rotQuatZ(angle));\n}\n\n\ntemplate<typename T>\nMatrix<T, 3, 3> QuaternionRotationTemplate<T>::asRotationMatrix() const {\n\treturn rotationMatrixFromQuaternion(this->rotationQuaternion);\n}\ntemplate<typename T>\nQuaternion<T> QuaternionRotationTemplate<T>::asRotationQuaternion() const {\n\treturn this->rotationQuaternion;\n}\ntemplate<typename T>\nVector<T, 3> QuaternionRotationTemplate<T>::asRotationVector() const {\n\treturn rotationVectorFromRotationQuaternion(this->rotationQuaternion);\n}\n\ntemplate<typename T>\nQuaternionRotationTemplate<T> QuaternionRotationTemplate<T>::fromRotationMatrix(const Matrix<T, 3, 3>& rotationMatrix) {\n\tassert(isValidRotationMatrix(rotationMatrix));\n\treturn QuaternionRotationTemplate<T>(rotationQuaternionFromRotationMatrix(rotationMatrix));\n}\n\ntemplate<typename T>\nQuaternionRotationTemplate<T> QuaternionRotationTemplate<T>::fromRotationQuaternion(const Quaternion<T>& rotationQuaternion) {\n\tassert(isValidRotationQuaternion(rotationQuaternion));\n\treturn QuaternionRotationTemplate<T>(rotationQuaternion);\n}\n\ntemplate<typename T>\nQuaternionRotationTemplate<T> QuaternionRotationTemplate<T>::fromRotationVec(const Vector<T, 3>& rotationVector) {\n\treturn QuaternionRotationTemplate<T>(rotationQuaternionFromRotationVec(rotationVector));\n}\n\ntemplate<typename T>\nQuaternionRotationTemplate<T> QuaternionRotationTemplate<T>::faceX(Vector<T, 3> xDirection) {\n\treturn QuaternionRotationTemplate<T>::fromRotationMatrix(faceMatX(xDirection));\n}\ntemplate<typename T>\nQuaternionRotationTemplate<T> QuaternionRotationTemplate<T>::faceX(Vector<T, 3> xDirection, Vector<T, 3> yHint) {\n\treturn QuaternionRotationTemplate<T>::fromRotationMatrix(faceMatX(xDirection, yHint));\n}\ntemplate<typename T>\nQuaternionRotationTemplate<T> QuaternionRotationTemplate<T>::faceY(Vector<T, 3> yDirection) {\n\treturn QuaternionRotationTemplate<T>::fromRotationMatrix(faceMatY(yDirection));\n}\ntemplate<typename T>\nQuaternionRotationTemplate<T> QuaternionRotationTemplate<T>::faceY(Vector<T, 3> yDirection, Vector<T, 3> zHint) {\n\treturn QuaternionRotationTemplate<T>::fromRotationMatrix(faceMatY(yDirection, zHint));\n}\ntemplate<typename T>\nQuaternionRotationTemplate<T> QuaternionRotationTemplate<T>::faceZ(Vector<T, 3> zDirection) {\n\treturn QuaternionRotationTemplate<T>::fromRotationMatrix(faceMatZ(zDirection));\n}\ntemplate<typename T>\nQuaternionRotationTemplate<T> QuaternionRotationTemplate<T>::faceZ(Vector<T, 3> zDirection, Vector<T, 3> xHint) {\n\treturn QuaternionRotationTemplate<T>::fromRotationMatrix(faceMatZ(zDirection, xHint));\n}\n\ntemplate<typename T>\ntemplate<typename OtherT>\nQuaternionRotationTemplate<T>::operator QuaternionRotationTemplate<OtherT>() const {\n\treturn QuaternionRotationTemplate<OtherT>::fromRotationQuaternion(static_cast<Quaternion<OtherT>>(this->rotationQuaternion));\n}\n\n\ntemplate<typename T>\nusing RotationTemplate = MatrixRotationTemplate<T>;\ntypedef RotationTemplate<double> Rotation;\ntypedef RotationTemplate<float> Rotationf;\n};"
  },
  {
    "path": "Physics3D/math/taylorExpansion.h",
    "content": "#pragma once\n\n#include <assert.h>\n#include <stddef.h>\n#include <initializer_list>\n\nnamespace P3D {\ntemplate<typename T, std::size_t DerivationCount>\nstruct Derivatives {\n\tT data[DerivationCount];\n\n\tconstexpr const T& operator[](std::size_t index) const { assert(index >= 0 && index < DerivationCount); return data[index]; }\n\tconstexpr T& operator[](std::size_t index) { assert(index >= 0 && index < DerivationCount); return data[index]; }\n\n\tT* begin() { return data; }\n\tconst T* begin() const { return data; }\n\tT* end() { return data + DerivationCount; }\n\tconst T* end() const { return data + DerivationCount; }\n\n\ttemplate<typename Func>\n\tauto transform(const Func& transformFunc) const -> Derivatives<decltype(transformFunc(this->data[0])), DerivationCount> {\n\t\tDerivatives<decltype(transformFunc(this->data[0])), DerivationCount> result;\n\t\tfor(std::size_t i = 0; i < DerivationCount; i++) {\n\t\t\tresult[i] = transformFunc(this->data[i]);\n\t\t}\n\t\treturn result;\n\t}\n};\n\ntemplate<typename T, std::size_t DerivationCount>\nstruct TaylorExpansion {\n\tDerivatives<T, DerivationCount> derivs;\n\n\tconstexpr const T& operator[](std::size_t index) const { return derivs[index]; }\n\tconstexpr T& operator[](std::size_t index) { return derivs[index]; }\n\n\tT* begin() { return derivs.begin(); }\n\tconst T* begin() const { return derivs.begin(); }\n\tT* end() { return derivs.end(); }\n\tconst T* end() const { return derivs.end(); }\n\n\t/*\n\t\tEvaluates the taylor expansion at x\n\t\treturns (derivatives[0]+(derivatives[1]+(derivatives[2]+...)*(x/3))*(x/2))*x\n\t\t= derivatives[0]*x + derivatives[1]*x^2/2! + derivatives[2]*x^3/3! + derivatives[3]*x^4/4! + ...\n\t*/\n\ttemplate<typename T2>\n\tT operator()(const T2& x) const {\n\t\tT result = derivs[DerivationCount - 1];\n\t\t\n\t\tfor(std::size_t i = DerivationCount - 1; i > 0; i--) {\n\t\t\tresult *= x / (i+1);\n\t\t\tresult += derivs[i-1];\n\t\t}\n\t\tresult *= x;\n\t\treturn result;\n\t}\n\n\ttemplate<typename Func>\n\tauto transform(const Func& transformFunc) const -> TaylorExpansion<decltype(transformFunc(this->derivs[0])), DerivationCount> {\n\t\treturn TaylorExpansion<decltype(transformFunc(this->derivs[0])), DerivationCount>{this->derivs.transform(transformFunc)};\n\t}\n};\n\ntemplate<typename T, std::size_t DerivationCount>\nstruct FullTaylorExpansion {\n\tDerivatives<T, DerivationCount> derivs;\n\n\tinline const T& getConstantValue() const { return derivs[0]; }\n\tinline const T& getDerivative(std::size_t i) const { return derivs[i+1]; }\n\n\tinline void setConstantValue(const T& newConstValue) { derivs[0] = newConstValue; }\n\tinline void setDerivative(std::size_t i, const T& newDerivative) { derivs[i+1] = newDerivative; }\n\n\tinline TaylorExpansion<T, DerivationCount-1> getDerivatives() const {\n\t\tTaylorExpansion<T, DerivationCount - 1> result;\n\t\tfor(std::size_t i = 0; i < DerivationCount - 1; i++) {\n\t\t\tresult[i] = derivs[i+1];\n\t\t}\n\t\treturn result; \n\t}\n\n\tstatic FullTaylorExpansion<T, DerivationCount> fromConstantAndDerivatives(const T& constantValue, const TaylorExpansion<T, DerivationCount-1>& newDerivs) {\n\t\tFullTaylorExpansion<T, DerivationCount> result;\n\t\tresult.setConstantValue(constantValue);\n\t\tfor(std::size_t i = 0; i < DerivationCount - 1; i++) {\n\t\t\tresult.setDerivative(i, newDerivs[i]);\n\t\t}\n\t\treturn result;\n\t}\n\n\t/*\n\t\tEvaluates the taylor expansion at x\n\t\treturns constantValue + (derivatives[0]+(derivatives[1]+(derivatives[2]+...)*(x/3))*(x/2))*x\n\t\t= constantValue + derivatives[0]*x + derivatives[1]*x^2/2! + derivatives[2]*x^3/3! + derivatives[3]*x^4/4! + ...\n\t*/\n\ttemplate<typename T2>\n\tT operator()(const T2& x) const {\n\t\tstd::size_t NumberOfDerivs = DerivationCount - 1;\n\t\tT derivsFactor = this->getDerivative(NumberOfDerivs - 1);\n\n\t\tfor(std::size_t i = NumberOfDerivs - 1; i > 0; i--) {\n\t\t\tderivsFactor *= x / (i + 1);\n\t\t\tderivsFactor += this->getDerivative(i - 1);\n\t\t}\n\t\tderivsFactor *= x;\n\n\t\treturn this->getConstantValue() + derivsFactor;\n\t}\n\n\ttemplate<typename Func>\n\tauto transform(const Func& transformFunc) const -> FullTaylorExpansion<decltype(transformFunc(this->derivs[0])), DerivationCount> {\n\t\treturn FullTaylorExpansion<decltype(transformFunc(this->derivs[0])), DerivationCount>{this->derivs.transform(transformFunc)};\n\t}\n};\n\n\n\ntemplate<typename T, std::size_t DerivationCount>\nDerivatives<T, DerivationCount> operator-(const Derivatives<T, DerivationCount>& obj) {\n\tDerivatives<T, DerivationCount> result;\n\n\tfor(std::size_t i = 0; i < DerivationCount; i++) {\n\t\tresult[i] = -obj[i];\n\t}\n\n\treturn result;\n}\n\ntemplate<typename T, std::size_t DerivationCount>\nDerivatives<T, DerivationCount> operator+(const Derivatives<T, DerivationCount>& first, const Derivatives<T, DerivationCount>& second) {\n\tDerivatives<T, DerivationCount> result;\n\n\tfor(std::size_t i = 0; i < DerivationCount; i++) {\n\t\tresult[i] = first[i] + second[i];\n\t}\n\n\treturn result;\n}\ntemplate<typename T, std::size_t DerivationCount>\nDerivatives<T, DerivationCount> operator-(const Derivatives<T, DerivationCount>& first, const Derivatives<T, DerivationCount>& second) {\n\tDerivatives<T, DerivationCount> result;\n\n\tfor(std::size_t i = 0; i < DerivationCount; i++) {\n\t\tresult[i] = first[i] - second[i];\n\t}\n\n\treturn result;\n}\ntemplate<typename T, typename T2, std::size_t DerivationCount>\nDerivatives<T, DerivationCount> operator*(const T2& factor, const Derivatives<T, DerivationCount>& second) {\n\tDerivatives<T, DerivationCount> result;\n\n\tfor(std::size_t i = 0; i < DerivationCount; i++) {\n\t\tresult[i] = factor * second[i];\n\t}\n\n\treturn result;\n}\ntemplate<typename T, typename T2, std::size_t DerivationCount>\nDerivatives<T, DerivationCount> operator*(const Derivatives<T, DerivationCount>& first, const T2& factor) {\n\tDerivatives<T, DerivationCount> result;\n\n\tfor(std::size_t i = 0; i < DerivationCount; i++) {\n\t\tresult[i] = first[i] * factor;\n\t}\n\n\treturn result;\n}\ntemplate<typename T, typename T2, std::size_t DerivationCount>\nDerivatives<T, DerivationCount> operator/(const Derivatives<T, DerivationCount>& first, const T2& factor) {\n\tDerivatives<T, DerivationCount> result;\n\n\tfor(std::size_t i = 0; i < DerivationCount; i++) {\n\t\tresult[i] = first[i] / factor;\n\t}\n\n\treturn result;\n}\n\ntemplate<typename T, std::size_t DerivationCount>\nDerivatives<T, DerivationCount>& operator+=(Derivatives<T, DerivationCount>& first, const Derivatives<T, DerivationCount>& second) {\n\tfor(std::size_t i = 0; i < DerivationCount; i++) {\n\t\tfirst[i] += second[i];\n\t}\n\n\treturn first;\n}\ntemplate<typename T, std::size_t DerivationCount>\nDerivatives<T, DerivationCount>& operator-=(Derivatives<T, DerivationCount>& first, const Derivatives<T, DerivationCount>& second) {\n\tfor(std::size_t i = 0; i < DerivationCount; i++) {\n\t\tfirst[i] -= second[i];\n\t}\n\n\treturn first;\n}\ntemplate<typename T, typename T2, std::size_t DerivationCount>\nDerivatives<T, DerivationCount>& operator*=(Derivatives<T, DerivationCount>& first, const T2& factor) {\n\tfor(std::size_t i = 0; i < DerivationCount; i++) {\n\t\tfirst[i] *= factor;\n\t}\n\n\treturn first;\n}\ntemplate<typename T, typename T2, std::size_t DerivationCount>\nDerivatives<T, DerivationCount>& operator/=(Derivatives<T, DerivationCount>& first, const T2& factor) {\n\tfor(std::size_t i = 0; i < DerivationCount; i++) {\n\t\tfirst[i] /= factor;\n\t}\n\n\treturn first;\n}\n\n\ntemplate<typename T, std::size_t DerivationCount>\nTaylorExpansion<T, DerivationCount> operator-(const TaylorExpansion<T, DerivationCount>& obj) {\n\treturn TaylorExpansion<T, DerivationCount>{-obj.derivs};\n}\n\ntemplate<typename T, std::size_t DerivationCount>\nTaylorExpansion<T, DerivationCount> operator+(const TaylorExpansion<T, DerivationCount>& first, const TaylorExpansion<T, DerivationCount>& second) {\n\treturn TaylorExpansion<T, DerivationCount>{first.derivs + second.derivs};\n}\n\ntemplate<typename T, std::size_t DerivationCount>\nTaylorExpansion<T, DerivationCount> operator-(const TaylorExpansion<T, DerivationCount>& first, const TaylorExpansion<T, DerivationCount>& second) {\n\treturn TaylorExpansion<T, DerivationCount>{first.derivs - second.derivs};\n}\n\ntemplate<typename T, typename T2, std::size_t DerivationCount>\nTaylorExpansion<T, DerivationCount> operator*(const TaylorExpansion<T, DerivationCount>& first, const T2& second) {\n\treturn TaylorExpansion<T, DerivationCount>{first.derivs * second};\n}\n\ntemplate<typename T, typename T2, std::size_t DerivationCount>\nTaylorExpansion<T, DerivationCount> operator*(const T2& first, const TaylorExpansion<T, DerivationCount>& second) {\n\treturn TaylorExpansion<T, DerivationCount>{first * second.derivs};\n}\n\ntemplate<typename T, typename T2, std::size_t DerivationCount>\nTaylorExpansion<T, DerivationCount> operator/(const TaylorExpansion<T, DerivationCount>& first, const T2& second) {\n\treturn TaylorExpansion<T, DerivationCount>{first.derivs / second};\n}\n\ntemplate<typename T, std::size_t DerivationCount>\nTaylorExpansion<T, DerivationCount>& operator+=(TaylorExpansion<T, DerivationCount>& first, const TaylorExpansion<T, DerivationCount>& second) {\n\tfirst.derivs += second.derivs;\n\treturn first;\n}\n\ntemplate<typename T, std::size_t DerivationCount>\nTaylorExpansion<T, DerivationCount>& operator-=(TaylorExpansion<T, DerivationCount>& first, const TaylorExpansion<T, DerivationCount>& second) {\n\tfirst.derivs -= second.derivs;\n\treturn first;\n}\n\ntemplate<typename T, typename T2, std::size_t DerivationCount>\nTaylorExpansion<T, DerivationCount>& operator*=(TaylorExpansion<T, DerivationCount>& first, const T2& second) {\n\tfirst.derivs *= second;\n\treturn first;\n}\n\ntemplate<typename T, typename T2, std::size_t DerivationCount>\nTaylorExpansion<T, DerivationCount>& operator/=(TaylorExpansion<T, DerivationCount>& first, const T2& second) {\n\tfirst.derivs /= second;\n\treturn first;\n}\n\n\n\ntemplate<typename T, std::size_t DerivationCount>\nFullTaylorExpansion<T, DerivationCount> operator-(const FullTaylorExpansion<T, DerivationCount>& obj) {\n\treturn FullTaylorExpansion<T, DerivationCount>{-obj.derivs};\n}\n\ntemplate<typename T, std::size_t DerivationCount>\nFullTaylorExpansion<T, DerivationCount> operator+(const FullTaylorExpansion<T, DerivationCount>& first, const FullTaylorExpansion<T, DerivationCount>& second) {\n\treturn FullTaylorExpansion<T, DerivationCount>{first.derivs + second.derivs};\n}\n\ntemplate<typename T, std::size_t DerivationCount>\nFullTaylorExpansion<T, DerivationCount> operator-(const FullTaylorExpansion<T, DerivationCount>& first, const FullTaylorExpansion<T, DerivationCount>& second) {\n\treturn FullTaylorExpansion<T, DerivationCount>{first.derivs - second.derivs};\n}\n\ntemplate<typename T, std::size_t DerivationCount>\nFullTaylorExpansion<T, DerivationCount> operator+(const FullTaylorExpansion<T, DerivationCount>& first, const T& second) {\n\tFullTaylorExpansion<T, DerivationCount> result = first;\n\tresult.derivs[0] += second;\n\treturn result;\n}\n\ntemplate<typename T, std::size_t DerivationCount>\nFullTaylorExpansion<T, DerivationCount> operator-(const FullTaylorExpansion<T, DerivationCount>& first, const T& second) {\n\tFullTaylorExpansion<T, DerivationCount> result = first;\n\tresult.derivs[0] -= second;\n\treturn result;\n}\n\ntemplate<typename T, typename T2, std::size_t DerivationCount>\nFullTaylorExpansion<T, DerivationCount> operator*(const FullTaylorExpansion<T, DerivationCount>& first, const T2& second) {\n\treturn FullTaylorExpansion<T, DerivationCount>{first.derivs * second};\n}\n\ntemplate<typename T, typename T2, std::size_t DerivationCount>\nFullTaylorExpansion<T, DerivationCount> operator*(const T2& first, const FullTaylorExpansion<T, DerivationCount>& second) {\n\treturn FullTaylorExpansion<T, DerivationCount>{first * second.derivs};\n}\n\ntemplate<typename T, typename T2, std::size_t DerivationCount>\nFullTaylorExpansion<T, DerivationCount> operator/(const FullTaylorExpansion<T, DerivationCount>& first, const T2& second) {\n\treturn FullTaylorExpansion<T, DerivationCount>{first.derivs / second};\n}\n\ntemplate<typename T, std::size_t DerivationCount>\nFullTaylorExpansion<T, DerivationCount>& operator+=(FullTaylorExpansion<T, DerivationCount>& first, const FullTaylorExpansion<T, DerivationCount>& second) {\n\tfirst.derivs += second.derivs;\n\treturn first;\n}\n\ntemplate<typename T, std::size_t DerivationCount>\nFullTaylorExpansion<T, DerivationCount>& operator-=(FullTaylorExpansion<T, DerivationCount>& first, const FullTaylorExpansion<T, DerivationCount>& second) {\n\tfirst.derivs -= second.derivs;\n\treturn first;\n}\n\ntemplate<typename T, std::size_t DerivationCount>\nFullTaylorExpansion<T, DerivationCount>& operator+=(FullTaylorExpansion<T, DerivationCount>& first, const T& second) {\n\tfirst.derivs[0] += second;\n\treturn first;\n}\n\ntemplate<typename T, std::size_t DerivationCount>\nFullTaylorExpansion<T, DerivationCount>& operator-=(FullTaylorExpansion<T, DerivationCount>& first, const T& second) {\n\tfirst.derivs[0] -= second;\n\treturn first;\n}\n\ntemplate<typename T, typename T2, std::size_t DerivationCount>\nFullTaylorExpansion<T, DerivationCount>& operator*=(FullTaylorExpansion<T, DerivationCount>& first, const T2& second) {\n\tfirst.derivs *= second;\n\treturn first;\n}\n\ntemplate<typename T, typename T2, std::size_t DerivationCount>\nFullTaylorExpansion<T, DerivationCount>& operator/=(FullTaylorExpansion<T, DerivationCount>& first, const T2& second) {\n\tfirst.derivs /= second;\n\treturn first;\n}\n\n/*\n\tPascal indices for constructing derivatives of multiplications\n\t     1\n\t\t1 1\n\t   1 2 1\n\t  1 3 3 1\n\t 1 4 6 4 1\n*/\ntemplate<int Layer, int Index>\nstruct PascalIndex {\n\tenum { value = PascalIndex<Layer-1,Index-1>::value + PascalIndex<Layer - 1, Index>::value};\n};\n\ntemplate<int Index>\nstruct PascalIndex<0, Index> {\n\tenum { value = 1 };\n};\n\ntemplate<int Layer>\nstruct PascalIndex<Layer, 0> {\n\tenum { value = 1 };\n};\n\ntemplate<int Layer>\nstruct PascalIndex<Layer, Layer> {\n\tenum { value = 1 };\n};\n\n// get the pascal triangle index of this layer and index\n// should always get optimized to a constant expression\nconstexpr int pascalIndex(int layer, int index) {\n\tif (layer == 0 || index == 0 || index == layer) {\n\t\treturn 1;\n\t} else {\n\t\treturn pascalIndex(layer - 1, index - 1) + pascalIndex(layer - 1, index);\n\t}\n}\n\ntemplate<typename T1, typename T2, std::size_t Size, std::size_t Layer, std::size_t Index>\nauto computeDerivativeForIndex(const Derivatives<T1, Size>& first, const Derivatives<T2, Size>& second) -> decltype(first[0] * second[0]) {\n\tdecltype(first[0] * second[0]) thisStepResult = first[Index] * second[Layer - Index];\n\tif constexpr(Index == 0) {\n\t\treturn thisStepResult;\n\t} else if constexpr(Index == Layer) {\n\t\treturn thisStepResult + computeDerivativeForIndex<T1, T2, Size, Layer, Index - 1>(first, second);\n\t} else {\n\t\treturn static_cast<int>(PascalIndex<Layer, Index>::value) * thisStepResult + computeDerivativeForIndex<T1, T2, Size, Layer, Index - 1>(first, second);\n\t}\n}\n\ntemplate<typename T1, typename T2, std::size_t Size, std::size_t CurDerivative>\nvoid computeDerivatives(const Derivatives<T1, Size>& first, const Derivatives<T2, Size>& second, Derivatives<decltype(first[0] * second[0]), Size>& result) {\n\tif constexpr(CurDerivative > 0) {\n\t\tcomputeDerivatives<T1, T2, Size, CurDerivative - 1>(first, second, result);\n\t}\n\tresult[CurDerivative] = computeDerivativeForIndex<T1, T2, Size, CurDerivative, CurDerivative>(first, second);\n}\n\n// multiplication-like derivatives\ntemplate<typename T1, typename T2, std::size_t Size>\nauto derivsOfMultiplication(const Derivatives<T1, Size>& first, const Derivatives<T2, Size>& second) -> Derivatives<decltype(first[0] * second[0]), Size> {\n\tDerivatives<decltype(first[0] * second[0]), Size> result;\n\n\tcomputeDerivatives<T1, T2, Size, Size - 1>(first, second, result);\n\n\treturn result;\n}\n// multiplication-like derivatives\ntemplate<typename T1, typename T2, std::size_t Size>\nauto derivsOfMultiplication(const FullTaylorExpansion<T1, Size>& first, const FullTaylorExpansion<T2, Size>& second) -> FullTaylorExpansion<decltype(first.derivs[0] * second.derivs[0]), Size> {\n\treturn FullTaylorExpansion<decltype(first.derivs[0] * second.derivs[0]), Size>{derivsOfMultiplication(first.derivs, second.derivs)};\n}\n\n#define DEFAULT_TAYLOR_LENGTH 2\n\ntemplate<typename T>\nusing Taylor = TaylorExpansion<T, DEFAULT_TAYLOR_LENGTH>;\n\ntemplate<typename T>\nusing FullTaylor = FullTaylorExpansion<T, DEFAULT_TAYLOR_LENGTH + 1>;\n};"
  },
  {
    "path": "Physics3D/math/transform.h",
    "content": "#pragma once\n\n#include \"linalg/vec.h\"\n#include \"linalg/mat.h\"\n#include \"cframe.h\"\n\nnamespace P3D {\ntemplate<typename T>\nclass TransformTemplate {\npublic:\n\tVector<T, 3> position;\n\tMatrix<T, 3, 3> transform;\n\n\tTransformTemplate(const Vector<T, 3>& position, const Matrix<T, 3, 3>& transform) : position(position), transform(transform) {}\n\texplicit TransformTemplate(const Vector<T, 3>& position) : position(position), transform(Mat3::IDENTITY()) {}\n\texplicit TransformTemplate(const T& x, const T& y, const T& z) : position(x, y, z), transform(Mat3::IDENTITY()) {}\n\texplicit TransformTemplate(const Matrix<T, 3, 3>& transform) : position(0, 0, 0), transform(transform) {}\n\tTransformTemplate() : position(0, 0, 0), transform(Mat3::IDENTITY()) {}\n\n\ttemplate<typename OtherT>\n\tTransformTemplate(const TransformTemplate<OtherT>& other) : \n\t\tposition(Vector<T, 3>(other.position)),\n\t\ttransform(Matrix<T, 3, 3>(other.transform)) {}\n\n\ttemplate<typename OtherT>\n\tTransformTemplate(const CFrameTemplate<OtherT>& other) : \n\t\tposition(Vector<T, 3>(other.position)),\n\t\ttransform(Matrix<T, 3, 3>(other.rotation)) {}\n\n\n\tinline Vector<T, 3> localToGlobal(const Vector<T, 3>& lVec) const {\n\t\treturn transform * lVec + position;\n\t}\n\n\tinline Vector<T, 3> globalToLocal(const Vector<T, 3>& gVec) const {\n\t\treturn ~transform * (gVec - position);\n\t}\n\n\tinline Vector<T, 3> localToRelative(const Vector<T, 3>& lVec) const {\n\t\treturn transform * lVec;\n\t}\n\n\tinline Vector<T, 3> relativeToLocal(const Vector<T, 3>& rVec) const {\n\t\treturn ~transform * rVec;\n\t}\n\n\tinline TransformTemplate<T> localToGlobal(TransformTemplate<T> lFrame) const {\n\t\treturn TransformTemplate<T>(position + transform * lFrame.position, transform * lFrame.transform);\n\t}\n\n\tinline TransformTemplate<T> globalToLocal(const TransformTemplate<T>& gFrame) const {\n\t\treturn TransformTemplate<T>(~transform * (gFrame.position - position), ~transform * gFrame.transform);\n\t}\n\n\tinline TransformTemplate<T> localToRelative(const TransformTemplate<T>& lFrame) const {\n\t\treturn TransformTemplate<T>(transform * lFrame.position, transform * lFrame.transform);\n\t}\n\n\tinline TransformTemplate<T> relativeToLocal(const TransformTemplate<T>& rFrame) const {\n\t\treturn TransformTemplate<T>(~transform * rFrame.position, ~transform * rFrame.transform);\n\t}\n\n\tinline Matrix<T, 3, 3> localToGlobal(const Matrix<T, 3, 3>& localRot) const {\n\t\treturn transform * localRot;\n\t}\n\n\tinline Matrix<T, 3, 3> globalToLocal(const Matrix<T, 3, 3>& globalRot) const {\n\t\treturn ~transform * globalRot;\n\t}\n\n\tinline TransformTemplate<T> operator~() const {\n\t\treturn TransformTemplate<T>(~transform * -position, ~transform);\n\t}\n\n\tinline Vector<T, 3> getPosition() const {\n\t\treturn position;\n\t}\n\n\tinline Matrix<T, 3, 3> getLocalTransformation() const {\n\t\treturn transform;\n\t}\n\n\tinline TransformTemplate<T>& operator+=(const Vector<T, 3>& delta) {\n\t\tposition += delta;\n\t\treturn *this;\n\t}\n\n\tinline TransformTemplate<T>& operator-=(const Vector<T, 3>& delta) {\n\t\tposition -= delta;\n\t\treturn *this;\n\t}\n\n\tvoid translate(const Vector<T, 3>& translation) {\n\t\tposition += translation;\n\t}\n\n\tvoid transformGlobalSide(const Matrix<T, 3, 3>& transformation) {\n\t\ttransform = transformation * transform;\n\t}\n\n\tvoid transformLocalSide(const Matrix<T, 3, 3>& transformation) {\n\t\ttransform = transform * transformation;\n\t}\n};\n\n\ntemplate<typename T>\nTransformTemplate<T> Mat4ToTransform(const Matrix<T, 4, 4>& mat) {\n\treturn TransformTemplate<T>(toVector(mat.getSubMatrix<3, 1>(0, 3)), mat.getSubMatrix<3, 3>(0, 0));\n\tassert(mat[3][0] == 0.0);\n\tassert(mat[3][1] == 0.0);\n\tassert(mat[3][2] == 0.0);\n\tassert(mat[3][3] == 1.0);\n};\ntemplate<typename T>\nMatrix<T, 4, 4> TransformToMat4(const TransformTemplate<T>& transform) {\n\treturn Matrix<T, 4, 4>(Matrix<T, 3, 3>(transform.transform), transform.position, Vector<T, 3>(0, 0, 0), 1.0);\n}\n\ntypedef TransformTemplate<double> Transform;\ntypedef TransformTemplate<float> Transformf;\n};"
  },
  {
    "path": "Physics3D/math/utils.h",
    "content": "#pragma once\n\n#include \"linalg/vec.h\"\n\nnamespace P3D {\n/*\n\tComputes the intersection of a line along <r> starting at r0\n\tand the surface with normalvec n starting at s0\n\n\tWith relativePos == s0-r0\n\n\tRay expression: r0+t*r\n\tPlane equation: n*(p-s0) == 0\n\n\tReturns t from the ray expression\n\tTo get the actual intersection point: p=r0+t*r\n*/\ntemplate<typename N>\ninline N lineSurfaceIntersection(Vector<N, 3> relativePos, Vector<N, 3> r, Vector<N, 3> n) {\n\treturn (relativePos * n) / (r * n);\n}\n\n/*\n\tSee rayTriangleIntersection\n*/\ntemplate<typename T>\nstruct RayIntersection {\n\tT d, s, t;\n\tinline bool lineIntersectsTriangle() { return s >= 0 && t >= 0 && s + t <= 1; }\n\tinline bool rayIntersectsTriangle() { return d >= 0 && lineIntersectsTriangle(); }\n};\n\n/*\n\tRay is defined as: P0 + r*P\n\tTriangle surface is defined by: S0 + s*U + t*V\n\n\tTo solve:\n\tP0 + r*P = S0 + s*U + t*V\n\t=> s*U + t*V - r*P + R0 = 0\n\twith R0 = P0-S0\n\n\tSolving the system yields:\n\td = -R0 * u%v / n*P\n\ts = -P * R0%u / n*P\n\tt =  P * R0%v / n*P\n*/\ntemplate<typename T>\ninline RayIntersection<T> rayTriangleIntersection(Vector<T, 3> point, Vector<T, 3> ray, Vector<T, 3> v0, Vector<T, 3> v1, Vector<T, 3> v2) {\n\tVector<T, 3> u = v1 - v0;\n\tVector<T, 3> v = v2 - v0;\n\n\tVector<T, 3> n = u%v;\n\tVector<T, 3> surfacePos = v0;\n\n\tVector<T, 3> relPoint = point - v0;\n\n\tT d = -relPoint * n / (n*ray); // lineSurfaceIntersection(relPoint, P, n);\n\tT s = -ray * (relPoint%u) / (n*ray);\n\tT t = ray * (relPoint%v) / (n*ray);\n\n\treturn RayIntersection<T>{d, s, t};\n}\n\n/*\n\tComputes the squared distance of a point at relativePoint to a plane going through the origin, with normal planeNormal\n\t\n\t(planeNormal * relativePoint)*(planeNormal * relativePoint) / planeNormal.lengthSquared();\n*/\ninline double pointToPlaneDistanceSquared(Vec3 planeNormal, Vec3 relativePoint) {\n\treturn (planeNormal * relativePoint)*(planeNormal * relativePoint) / lengthSquared(planeNormal);\n}\n\ninline float pointToPlaneDistanceSquared(Vec3f planeNormal, Vec3f relativePoint) {\n\treturn (planeNormal * relativePoint)*(planeNormal * relativePoint) / lengthSquared(planeNormal);\n}\n\nstruct CrossOverPoint {\n\tdouble s;\n\tdouble t;\n};\n\n/*\n\tGet where the two lines are closest to eachother\n\tP := P0+s*U\n\tQ := Q0+t*V\n\n\tWith W0 = P0-Q0\n*/\ninline CrossOverPoint getNearestCrossoverOfRays(Vec3 U, Vec3 V, Vec3 W0) {\n\tdouble a = U*U;\n\tdouble b = U*V;\n\tdouble c = V*V;\n\tdouble d = U*W0;\n\tdouble e = V*W0;\n\n\tdouble s = (b*e - c*d) / (a*c - b*b);\n\tdouble t = (a*e - b*d) / (a*c - b*b);\n\n\treturn CrossOverPoint{s, t};\n}\n};"
  },
  {
    "path": "Physics3D/misc/catchable_assert.h",
    "content": "#pragma once\n\n#include <exception>\n#include <string>\n\nnamespace P3D {\nclass assertion_error : public std::exception {\n\tconst char* file;\n\tint line;\npublic:\n\tassertion_error(const char* file, int line) : std::exception(), file(file), line(line) {}\n};\n\n#ifndef NDEBUG\n#define catchable_assert(condition) if(!(condition)) throw assertion_error(__FILE__, __LINE__)\n#else\n#define catchable_assert(condition)\n#endif\n};\n"
  },
  {
    "path": "Physics3D/misc/cpuid.cpp",
    "content": "#include \"cpuid.h\"\n\n#ifdef _WIN32\n#include <intrin.h>\n#endif\n\n#include <stdint.h>\n\nnamespace P3D {\nclass CPUID {\n\tuint32_t regs[4];\n\npublic:\n\texplicit CPUID(unsigned i, unsigned ecx) {\n#ifdef _WIN32\n\t\t__cpuidex(( int*) regs, ( int) i, ( int) ecx);\n\n#else\n\t\tasm volatile\n\t\t\t(\"cpuid\" : \"=a\" (regs[0]), \"=b\" (regs[1]), \"=c\" (regs[2]), \"=d\" (regs[3])\n\t\t\t : \"a\" (i), \"c\" (ecx));\n#endif\n\t}\n\n\tconst uint32_t& EAX() const { return regs[0]; }\n\tconst uint32_t& EBX() const { return regs[1]; }\n\tconst uint32_t& ECX() const { return regs[2]; }\n\tconst uint32_t& EDX() const { return regs[3]; }\n};\n\nCPUIDCheck::CPUIDCheck() : available(0) {\n\tCPUID cpuid0(0, 0);\n\tif(cpuid0.EAX() >= 1) {\n\t\tCPUID cpuid1(1, 0);\n\n\t\tif(cpuid1.EDX() & (1 << 23)) this->available |= MMX;\n\t\tif(cpuid1.EDX() & (1 << 25)) this->available |= SSE;\n\t\tif(cpuid1.EDX() & (1 << 26)) this->available |= SSE2;\n\t\tif(cpuid1.ECX() & (1 << 0)) this->available |= SSE3;\n\t\tif(cpuid1.ECX() & (1 << 9)) this->available |= SSSE3;\n\t\tif(cpuid1.ECX() & (1 << 19)) this->available |= SSE4_1;\n\t\tif(cpuid1.ECX() & (1 << 20)) this->available |= SSE4_2;\n\t\tif(cpuid1.ECX() & (1 << 28)) this->available |= AVX;\n\t\tif(cpuid1.ECX() & (1 << 12)) this->available |= FMA;\n\t}\n\n\tif(cpuid0.EAX() >= 7) {\n\t\tCPUID cpuid7(7, 0);\n\n\t\tif(cpuid7.EBX() & (1 << 5)) this->available |= AVX2;\n\t\tif(cpuid7.EBX() & (1 << 16)) this->available |= AVX512_F;\n\t}\n}\n\nCPUIDCheck CPUIDCheck::availableCPUHardware;\n};\n"
  },
  {
    "path": "Physics3D/misc/cpuid.h",
    "content": "#pragma once\n\nnamespace P3D {\nclass CPUIDCheck {\n\tunsigned int available;\n\n\tCPUIDCheck();\n\n\tstatic CPUIDCheck availableCPUHardware; // statically initialized\n\npublic:\n\tstatic constexpr unsigned int MMX = 1 << 0;\n\tstatic constexpr unsigned int SSE = 1 << 1;\n\tstatic constexpr unsigned int SSE2 = 1 << 2;\n\tstatic constexpr unsigned int SSE3 = 1 << 3;\n\tstatic constexpr unsigned int SSSE3 = 1 << 4;\n\tstatic constexpr unsigned int SSE4_1 = 1 << 5;\n\tstatic constexpr unsigned int SSE4_2 = 1 << 6;\n\tstatic constexpr unsigned int AVX = 1 << 7;\n\tstatic constexpr unsigned int AVX2 = 1 << 8;\n\tstatic constexpr unsigned int FMA = 1 << 9;\n\tstatic constexpr unsigned int AVX512_F = 1 << 10;\n\n\tstatic constexpr int TECHNOLOGY_COUNT = 11;\n\tstatic constexpr const char* NAMES[TECHNOLOGY_COUNT]{\"MMX\", \"SSE\", \"SSE2\", \"SSE3\", \"SSSE3\", \"SSE4_1\", \"SSE4_2\", \"AVX\", \"AVX2\", \"FMA\", \"AVX512_F\"};\n\n\t// usage: hasTechnology(SSE | SSE2 | AVX | FMA)\n\t// returns true if all given technologies are available\n\tinline static bool hasTechnology(unsigned int technologies) {\n\t\treturn (availableCPUHardware.available & technologies) == technologies;\n\t}\n\n\tinline static void enableTechnology(unsigned int technologies) {\n\t\tavailableCPUHardware.available |= technologies;\n\t}\n\n\tinline static void disableTechnology(unsigned int technologies) {\n\t\tavailableCPUHardware.available &= ~technologies;\n\t}\n};\n\n};\n"
  },
  {
    "path": "Physics3D/misc/debug.cpp",
    "content": "#include \"debug.h\"\n\n#include \"../geometry/shape.h\"\n#include \"../part.h\"\n\n#include \"serialization/serialization.h\"\n#include \"toString.h\"\n\n#include <fstream>\n#include <chrono>\n#include <sstream>\n\nnamespace P3D {\nnamespace Debug {\nvoid(*logVecAction)(Position, Vec3, VectorType) = [](Position, Vec3, VectorType) {};\nvoid(*logPointAction)(Position, PointType) = [](Position, PointType) {};\nvoid(*logCFrameAction)(CFrame, CFrameType) = [](CFrame, CFrameType) {};\nvoid(*logShapeAction)(const Polyhedron&, const GlobalCFrame&) = [](const Polyhedron&, const GlobalCFrame&) {};\nvoid(*logAction)(const char*, std::va_list) = [](const char* format, std::va_list args) { vprintf(format, args); };\nvoid(*logWarnAction)(const char*, std::va_list) = [](const char* format, std::va_list args) { std::cout << \"WARN: \";  vprintf(format, args); };\nvoid(*logErrorAction)(const char*, std::va_list) = [](const char* format, std::va_list args) { std::cout << \"ERROR: \";  vprintf(format, args); };\n\nvoid logVector(Position origin, Vec3 vec, VectorType type) { logVecAction(origin, vec, type); };\nvoid logPoint(Position point, PointType type) { logPointAction(point, type); }\nvoid logCFrame(CFrame frame, CFrameType type) { logCFrameAction(frame, type); };\nvoid logShape(const Polyhedron& shape, const GlobalCFrame& location) { logShapeAction(shape, location); };\nvoid log(const char* format, ...) {\n\tstd::va_list args;\n\tva_start(args, format);\n\tlogAction(format, args);\n\tva_end(args);\n}\nvoid logWarn(const char* format, ...) {\n\tstd::va_list args;\n\tva_start(args, format);\n\tlogWarnAction(format, args);\n\tva_end(args);\n}\nvoid logError(const char* format, ...) {\n\tstd::va_list args;\n\tva_start(args, format);\n\tlogErrorAction(format, args);\n\tva_end(args);\n}\n\nvoid setVectorLogAction(void(*logger)(Position origin, Vec3 vec, VectorType type)) { logVecAction = logger; };\nvoid setPointLogAction(void(*logger)(Position point, PointType type)) { logPointAction = logger; }\nvoid setCFrameLogAction(void(*logger)(CFrame frame, CFrameType type)) { logCFrameAction = logger; };\nvoid setShapeLogAction(void(*logger)(const Polyhedron& shape, const GlobalCFrame& location)) { logShapeAction = logger; }\nvoid setLogAction(void(*logger)(const char* format, std::va_list args)) { logAction = logger; }\nvoid setLogWarnAction(void(*logger)(const char* format, std::va_list args)) { logWarnAction = logger; }\nvoid setLogErrorAction(void(*logger)(const char* format, std::va_list args)) { logErrorAction = logger; }\n\n\nvoid saveIntersectionError(const Part& first, const Part& second, const char* reason) {\n\tlogWarn(\"First cframe: %s\", str(first.getCFrame()).c_str());\n\tlogWarn(\"Second cframe: %s\", str(second.getCFrame()).c_str());\n\n\tstd::ofstream file;\n\tstd::stringstream name;\n\tname << \"../\";\n\tname << reason;\n\tname << \".nativeParts\";\n\tfile.open(name.str().c_str(), std::ios::binary | std::ios::out);\n\n\tSerializationSessionPrototype session;\n\tconst Part* parts[2]{&first, &second};\n\tsession.serializeParts(parts, 2, file);\n\n\tfile.close();\n}\n};\n};"
  },
  {
    "path": "Physics3D/misc/debug.h",
    "content": "#pragma once\n\n#include <cstdarg>\n\n#include \"../math/linalg/vec.h\"\n#include \"../math/position.h\"\n#include \"../math/cframe.h\"\n#include \"../math/globalCFrame.h\"\n\nnamespace P3D {\nclass Part;\n\nclass Polyhedron;\n\nnamespace Debug {\n\nenum VectorType {\n\tINFO_VEC,\n\tFORCE,\n\tMOMENT,\n\tIMPULSE,\n\tANGULAR_IMPULSE,\n\tPOSITION,\n\tVELOCITY,\n\tACCELERATION,\n\tANGULAR_VELOCITY,\n};\n\nenum PointType {\n\tINFO_POINT,\n\tCENTER_OF_MASS,\n\tINTERSECTION,\n};\n\nenum CFrameType {\n\tOBJECT_CFRAME,\n\tINERTIAL_CFRAME\n};\n\nvoid logVector(Position origin, Vec3 vec, VectorType type);\nvoid logPoint(Position point, PointType type);\nvoid logCFrame(CFrame frame, CFrameType type);\nvoid logShape(const Polyhedron& shape, const GlobalCFrame& location);\nvoid log(const char* format, ...);\nvoid logWarn(const char* format, ...);\nvoid logError(const char* format, ...);\n\nvoid setVectorLogAction(void(*logger)(Position origin, Vec3 vec, VectorType type));\nvoid setPointLogAction(void(*logger)(Position point, PointType type));\nvoid setCFrameLogAction(void(*logger)(CFrame frame, CFrameType type));\nvoid setShapeLogAction(void(*logger)(const Polyhedron& shape, const GlobalCFrame& location));\nvoid setLogAction(void(*logger)(const char* format, std::va_list args));\nvoid setLogWarnAction(void(*logger)(const char* format, std::va_list args));\nvoid setLogErrorAction(void(*logger)(const char* format, std::va_list args));\n\nvoid saveIntersectionError(const Part& first, const Part& second, const char* reason);\n};\n};"
  },
  {
    "path": "Physics3D/misc/physicsProfiler.cpp",
    "content": "#include \"physicsProfiler.h\"\n\nnamespace P3D {\nconst char * physicsLabels[]{\n\t\"GJK Col\",\n\t\"GJK No Col\",\n\t\"EPA\",\n\t\"Collision\",\n\t\"Externals\",\n\t\"Col. Handling\",\n\t\"Constraints\",\n\t\"Tree Bounds\",\n\t\"Tree Structure\",\n\t\"Wait for lock\",\n\t\"Updates\",\n\t\"Queue\",\n\t\"Other\"\n};\n\nconst char * intersectionLabels[]{\n\t\"Colission\",\n\t\"GJK Reject\",\n\t\"Part Dist Reject\",\n\t\"Part Bound Reject\"\n};\n\nconst char* iterationLabels[]{\n\t\"0\",\n\t\"1\",\n\t\"2\",\n\t\"3\",\n\t\"4\",\n\t\"5\",\n\t\"6\",\n\t\"7\",\n\t\"8\",\n\t\"9\",\n\t\"10\",\n\t\"11\",\n\t\"12\",\n\t\"13\",\n\t\"14\",\n\t\"15+\",\n\t\"MAX\",\n};\n\nBreakdownAverageProfiler<PhysicsProcess> physicsMeasure(physicsLabels, 100);\nHistoricTally<long long, IntersectionResult> intersectionStatistics(intersectionLabels, 1);\nCircularBuffer<int> gjkCollideIterStats(1);\nCircularBuffer<int> gjkNoCollideIterStats(1);\n\nHistoricTally<long long, IterationTime> GJKCollidesIterationStatistics(iterationLabels, 1);\nHistoricTally<long long, IterationTime> GJKNoCollidesIterationStatistics(iterationLabels, 1);\nHistoricTally<long long, IterationTime> EPAIterationStatistics(iterationLabels, 1);\n};"
  },
  {
    "path": "Physics3D/misc/physicsProfiler.h",
    "content": "#pragma once\n\n#include \"profiling.h\"\n\nnamespace P3D {\nenum class PhysicsProcess {\n\tGJK_COL,\n\tGJK_NO_COL,\n\tEPA,\n\tCOLISSION_OTHER,\n\tEXTERNALS,\n\tCOLISSION_HANDLING,\n\tCONSTRAINTS,\n\tUPDATE_TREE_BOUNDS,\n\tUPDATE_TREE_STRUCTURE,\n\tWAIT_FOR_LOCK,\n\tUPDATING,\n\tQUEUE,\n\tOTHER,\n\tCOUNT\n};\n\nenum class IntersectionResult {\n\tCOLISSION,\n\tGJK_REJECT,\n\tPART_DISTANCE_REJECT,\n\tPART_BOUNDS_REJECT,\n\tCOUNT\n};\n\nenum class IterationTime {\n\tINSTANT_QUIT = 0,\n\tONE_ITER = 1,\n\tTOOMANY = 15,\n\tLIMIT_REACHED = 16,\n\tCOUNT = 17\n};\n\nextern BreakdownAverageProfiler<PhysicsProcess> physicsMeasure;\nextern HistoricTally<long long, IntersectionResult> intersectionStatistics;\nextern CircularBuffer<int> gjkCollideIterStats;\nextern CircularBuffer<int> gjkNoCollideIterStats;\nextern HistoricTally<long long, IterationTime> GJKCollidesIterationStatistics;\nextern HistoricTally<long long, IterationTime> GJKNoCollidesIterationStatistics;\nextern HistoricTally<long long, IterationTime> EPAIterationStatistics;\n};"
  },
  {
    "path": "Physics3D/misc/profiling.h",
    "content": "#pragma once\n\n#include <chrono>\n#include <map>\n\n#include \"../datastructures/buffers.h\"\n#include \"../datastructures/parallelArray.h\"\n\nnamespace P3D {\nclass TimerMeasure {\n\tstd::chrono::high_resolution_clock::time_point lastClock = std::chrono::high_resolution_clock::now();\npublic:\n\tCircularBuffer<std::chrono::nanoseconds> pastTickLengths;\n\tCircularBuffer<std::chrono::nanoseconds> pastBetweenTimes;\n\n\tTimerMeasure(size_t capacity) : pastTickLengths(capacity), pastBetweenTimes(capacity) {}\n\n\tinline void start() {\n\t\tstd::chrono::high_resolution_clock::time_point curTime = std::chrono::high_resolution_clock::now();\n\t\tstd::chrono::nanoseconds timeSinceLast = curTime - lastClock;\n\t\tpastBetweenTimes.add(timeSinceLast);\n\t\tlastClock = curTime;\n\t}\n\tinline void end() {\n\t\tstd::chrono::nanoseconds timeTaken = std::chrono::high_resolution_clock::now() - lastClock;\n\t\tpastTickLengths.add(timeTaken);\n\t}\n};\n\ntemplate<typename Unit, typename Category>\nclass HistoricTally {\n\tParallelArray<Unit, static_cast<size_t>(Category::COUNT)> currentTally;\npublic:\n\tchar const* labels[static_cast<size_t>(Category::COUNT)];\n\tCircularBuffer<ParallelArray<Unit, static_cast<size_t>(Category::COUNT)>> history;\n\n\tinline HistoricTally(char const* const labels[static_cast<size_t>(Category::COUNT)], size_t size) : history(size) {\n\t\tfor(size_t i = 0; i < static_cast<size_t>(Category::COUNT); i++) {\n\t\t\tthis->labels[i] = labels[i];\n\t\t}\n\t\tclearCurrentTally();\n\t}\n\n\tinline void addToTally(Category category, Unit amount) {\n\t\tcurrentTally[static_cast<size_t>(category)] += amount;\n\t}\n\n\tinline void clearCurrentTally() {\n\t\tfor(size_t i = 0; i < static_cast<size_t>(Category::COUNT); i++) {\n\t\t\tcurrentTally[i] = Unit(0);\n\t\t}\n\t}\n\n\tinline void nextTally() {\n\t\thistory.add(currentTally);\n\t\tclearCurrentTally();\n\t}\n\n\tconstexpr inline size_t size() const {\n\t\treturn static_cast<size_t>(Category::COUNT);\n\t}\n};\n\ntemplate<typename ProcessType>\nclass BreakdownAverageProfiler : public HistoricTally<std::chrono::nanoseconds, ProcessType> {\n\tstd::chrono::high_resolution_clock::time_point startTime = std::chrono::high_resolution_clock::now();\n\tProcessType currentProcess = static_cast<ProcessType>(-1);\n\n\npublic:\n\tCircularBuffer<std::chrono::high_resolution_clock::time_point> tickHistory;\n\n\tinline BreakdownAverageProfiler(char const* const labels[static_cast<size_t>(ProcessType::COUNT)], size_t capacity) : HistoricTally<std::chrono::nanoseconds, ProcessType>(labels, capacity), tickHistory(capacity) {}\n\n\tinline void mark(ProcessType process) {\n\t\tstd::chrono::high_resolution_clock::time_point curTime = std::chrono::high_resolution_clock::now();\n\t\tif(currentProcess != static_cast<ProcessType>(-1)) {\n\t\t\tHistoricTally<std::chrono::nanoseconds, ProcessType>::addToTally(currentProcess, curTime - startTime);\n\t\t}\n\t\tstartTime = curTime;\n\t\tcurrentProcess = process;\n\t}\n\n\tinline void mark(ProcessType process, ProcessType overrideOldProcess) {\n\t\tstd::chrono::high_resolution_clock::time_point curTime = std::chrono::high_resolution_clock::now();\n\t\tif(currentProcess != static_cast<ProcessType>(-1)) {\n\t\t\tHistoricTally<std::chrono::nanoseconds, ProcessType>::addToTally(overrideOldProcess, curTime - startTime);\n\t\t}\n\t\tstartTime = curTime;\n\t\tcurrentProcess = process;\n\t}\n\n\tinline void end() {\n\t\tstd::chrono::high_resolution_clock::time_point curTime = std::chrono::high_resolution_clock::now();\n\t\tthis->addToTally(currentProcess, curTime - startTime);\n\t\ttickHistory.add(curTime);\n\n\t\tcurrentProcess = static_cast<ProcessType>(-1);\n\t\tthis->nextTally();\n\t}\n\n\tinline double getAvgTPS() {\n\t\tsize_t numTicks = tickHistory.size();\n\t\tif(numTicks != 0) {\n\t\t\tstd::chrono::high_resolution_clock::time_point firstTime = tickHistory.tail();\n\t\t\tstd::chrono::high_resolution_clock::time_point lastTime = tickHistory.front();\n\t\t\tstd::chrono::nanoseconds delta = lastTime - firstTime;\n\n\t\t\tdouble timeTaken = delta.count() * 1E-9;\n\n\t\t\treturn (numTicks - 1) / timeTaken;\n\t\t}\n\t\treturn 0.0;\n\t}\n};\n};"
  },
  {
    "path": "Physics3D/misc/serialization/dynamicSerialize.h",
    "content": "#pragma once\n\n#include \"serializeBasicTypes.h\"\n\nnamespace P3D {\ntypedef uint32_t ClassIDType;\ntemplate<typename BaseType, typename... ArgsToInstantiate>\nclass DynamicSerializerRegistry {\npublic:\n\tstruct DynamicSerializer {\n\t\tClassIDType serializerID;\n\n\t\tDynamicSerializer(ClassIDType serializerID) : serializerID(serializerID) {}\n\n\t\tvirtual void serialize(const BaseType& object, std::ostream& ostream) const = 0;\n\t\tvirtual BaseType* deserialize(std::istream& istream, ArgsToInstantiate... args) const = 0;\n\t};\n\n\ttemplate<typename ConcreteType>\n\tclass ConcreteDynamicSerializer : public DynamicSerializer {\n\t\tvoid (*serializeFunc)(const ConcreteType&, std::ostream&);\n\t\tConcreteType* (*deserializeFunc)(std::istream&, ArgsToInstantiate...);\n\tpublic:\n\t\tConcreteDynamicSerializer(void (*sf)(const ConcreteType&, std::ostream&), ConcreteType* (*dsf)(std::istream&, ArgsToInstantiate...), ClassIDType serializerID) :\n\t\t\tDynamicSerializer(serializerID), serializeFunc(sf), deserializeFunc(dsf) {}\n\n\t\tvirtual void serialize(const BaseType& object, std::ostream& ostream) const override {\n\t\t\tconst ConcreteType& concreteObject = static_cast<const ConcreteType&>(object);\n\t\t\tthis->serializeFunc(concreteObject, ostream);\n\t\t}\n\t\tvirtual BaseType* deserialize(std::istream& istream, ArgsToInstantiate... args) const override {\n\t\t\treturn this->deserializeFunc(istream, args...);\n\t\t}\n\t};\n\nprivate:\n\tstd::unordered_map<std::type_index, const DynamicSerializer*> serializeRegistry;\n\tstd::map<ClassIDType, const DynamicSerializer*> deserializeRegistry;\n\npublic:\n\tDynamicSerializerRegistry() = default;\n\tDynamicSerializerRegistry(std::initializer_list<std::pair<std::type_index, const DynamicSerializer*>> initList) : serializeRegistry(), deserializeRegistry() {\n\t\tfor(const std::pair<std::type_index, const DynamicSerializer*>& item : initList) {\n\t\t\tconst DynamicSerializer* ds = item.second;\n\t\t\tserializeRegistry.emplace(item.first, ds);\n\t\t\tif(deserializeRegistry.find(ds->serializerID) != deserializeRegistry.end()) throw std::logic_error(\"Duplicate serializerID?\");\n\t\t\tdeserializeRegistry.emplace(ds->serializerID, ds);\n\t\t}\n\t}\n\n\ttemplate<typename ConcreteType, typename = typename std::enable_if<std::is_base_of<BaseType, ConcreteType>::value, ClassIDType>::type>\n\tvoid registerSerializerDeserializer(void (*serializeFunc)(const ConcreteType&, std::ostream&), ConcreteType* (*deserializeFunc)(std::istream&), ClassIDType serializerID) {\n\t\tif(deserializeRegistry.find(serializerID) != deserializeRegistry.end()) {\n\t\t\tthrow std::logic_error(\"A serializer with this id has already been defined!\");\n\t\t}\n\n\t\tstd::type_index ti = typeid(ConcreteType);\n\t\tif(serializeRegistry.find(ti) != serializeRegistry.end()) {\n\t\t\tthrow std::logic_error(\"A serializer for this type has already been defined!\");\n\t\t}\n\n\t\tConcreteDynamicSerializer<ConcreteType>* newSerializer = new ConcreteDynamicSerializer<ConcreteType>(serializeFunc, deserializeFunc, serializerID);\n\n\t\tserializeRegistry.emplace(ti, newSerializer);\n\t\tdeserializeRegistry.emplace(serializerID, newSerializer);\n\t}\n\n\ttemplate<typename ConcreteType, typename = typename std::enable_if<std::is_base_of<BaseType, ConcreteType>::value, ClassIDType>::type>\n\tvoid registerSerializerDeserializer(void (*serialize)(const ConcreteType&, std::ostream&), ConcreteType* (*deserialize)(std::istream&)) {\n\t\tClassIDType i = 0;\n\t\twhile(deserializeRegistry.find(i++) != deserializeRegistry.end());\n\n\t\tregisterSerializerDeserializer(serialize, deserialize, i);\n\t}\n\n\tvoid serialize(const BaseType& object, std::ostream& ostream) const {\n\t\tauto location = serializeRegistry.find(typeid(object));\n\t\tif(location == serializeRegistry.end()) {\n\t\t\tthrow SerializationException(\"This class is not in the serialization registry!\");\n\t\t}\n\t\tconst DynamicSerializer* serializer = (*location).second;\n\t\tserializeBasicTypes<ClassIDType>(serializer->serializerID, ostream);\n\t\tserializer->serialize(object, ostream);\n\t}\n\n\tBaseType* deserialize(std::istream& istream, ArgsToInstantiate... args) const {\n\t\tClassIDType serialID = deserializeBasicTypes<ClassIDType>(istream);\n\t\tauto location = deserializeRegistry.find(serialID);\n\t\tif(location == deserializeRegistry.end()) {\n\t\t\tthrow SerializationException(\"Invalid dynamic class ID!\");\n\t\t}\n\t\tconst DynamicSerializer* deserializer = (*location).second;\n\t\treturn deserializer->deserialize(istream, args...);\n\t}\n};\n};"
  },
  {
    "path": "Physics3D/misc/serialization/serialization.cpp",
    "content": "#include \"serialization.h\"\n\n#include <map>\n#include <set>\n#include <limits.h>\n#include <string>\n#include <iostream>\n\n#include \"../../geometry/polyhedron.h\"\n#include \"../../geometry/builtinShapeClasses.h\"\n#include \"../../geometry/shape.h\"\n#include \"../../geometry/shapeClass.h\"\n#include \"../../part.h\"\n#include \"../../world.h\"\n#include \"../../layer.h\"\n#include \"../../hardconstraints/hardConstraint.h\"\n#include \"../../hardconstraints/fixedConstraint.h\"\n#include \"../../hardconstraints/motorConstraint.h\"\n#include \"../../hardconstraints/sinusoidalPistonConstraint.h\"\n#include \"../../constraints/ballConstraint.h\"\n#include \"../../constraints/hingeConstraint.h\"\n#include \"../../constraints/barConstraint.h\"\n#include \"../../externalforces/directionalGravity.h\"\n\nnamespace P3D {\n#define CURRENT_VERSION_ID 2\n\n#pragma region serializeComponents\n\nvoid serializePolyhedron(const Polyhedron& poly, std::ostream& ostream) {\n\tserializeBasicTypes<int>(poly.vertexCount, ostream);\n\tserializeBasicTypes<int>(poly.triangleCount, ostream);\n\n\tfor(int i = 0; i < poly.vertexCount; i++) {\n\t\tserializeBasicTypes<Vec3f>(poly.getVertex(i), ostream);\n\t}\n\tfor(int i = 0; i < poly.triangleCount; i++) {\n\t\tserializeBasicTypes<Triangle>(poly.getTriangle(i), ostream);\n\t}\n}\nPolyhedron deserializePolyhedron(std::istream& istream) {\n\tuint32_t vertexCount = deserializeBasicTypes<uint32_t>(istream);\n\tuint32_t triangleCount = deserializeBasicTypes<uint32_t>(istream);\n\n\tVec3f* vertices = new Vec3f[vertexCount];\n\tTriangle* triangles = new Triangle[triangleCount];\n\n\tfor(uint32_t i = 0; i < vertexCount; i++) {\n\t\tvertices[i] = deserializeBasicTypes<Vec3f>(istream);\n\t}\n\tfor(uint32_t i = 0; i < triangleCount; i++) {\n\t\ttriangles[i] = deserializeBasicTypes<Triangle>(istream);\n\t}\n\n\tPolyhedron result(vertices, triangles, vertexCount, triangleCount);\n\tdelete[] vertices;\n\tdelete[] triangles;\n\treturn result;\n}\n\nvoid ShapeSerializer::include(const Shape& shape) {\n\tsharedShapeClassSerializer.include(shape.baseShape.get());\n}\n\nvoid ShapeSerializer::serializeShape(const Shape& shape, std::ostream& ostream) const {\n\tsharedShapeClassSerializer.serializeIDFor(shape.baseShape.get(), ostream);\n\tserializeBasicTypes<double>(shape.getWidth(), ostream);\n\tserializeBasicTypes<double>(shape.getHeight(), ostream);\n\tserializeBasicTypes<double>(shape.getDepth(), ostream);\n}\n\nShape ShapeDeserializer::deserializeShape(std::istream& istream) const {\n\tconst ShapeClass* baseShape = sharedShapeClassDeserializer.deserializeObject(istream);\n\tdouble width = deserializeBasicTypes<double>(istream);\n\tdouble height = deserializeBasicTypes<double>(istream);\n\tdouble depth = deserializeBasicTypes<double>(istream);\n\treturn Shape(intrusive_ptr<const ShapeClass>(baseShape), width, height, depth);\n}\n\nvoid serializeFixedConstraint(const FixedConstraint& object, std::ostream& ostream) {}\nFixedConstraint* deserializeFixedConstraint(std::istream& istream) { return new FixedConstraint(); }\n\nvoid serializeMotorConstraint(const ConstantSpeedMotorConstraint& constraint, std::ostream& ostream) {\n\tserializeBasicTypes<double>(constraint.speed, ostream);\n\tserializeBasicTypes<double>(constraint.currentAngle, ostream);\n}\nConstantSpeedMotorConstraint* deserializeMotorConstraint(std::istream& istream) {\n\tdouble speed = deserializeBasicTypes<double>(istream);\n\tdouble currentAngle = deserializeBasicTypes<double>(istream);\n\n\treturn new ConstantSpeedMotorConstraint(speed, currentAngle);\n}\n\nvoid serializePistonConstraint(const SinusoidalPistonConstraint& constraint, std::ostream& ostream) {\n\tserializeBasicTypes<double>(constraint.minValue, ostream);\n\tserializeBasicTypes<double>(constraint.maxValue, ostream);\n\tserializeBasicTypes<double>(constraint.period, ostream);\n\tserializeBasicTypes<double>(constraint.currentStepInPeriod, ostream);\n}\nSinusoidalPistonConstraint* deserializePistonConstraint(std::istream& istream) {\n\tdouble minLength = deserializeBasicTypes<double>(istream);\n\tdouble maxLength = deserializeBasicTypes<double>(istream);\n\tdouble period = deserializeBasicTypes<double>(istream);\n\tdouble currentStepInPeriod = deserializeBasicTypes<double>(istream);\n\n\tSinusoidalPistonConstraint* newConstraint = new SinusoidalPistonConstraint(minLength, maxLength, period);\n\tnewConstraint->currentStepInPeriod = currentStepInPeriod;\n\n\treturn newConstraint;\n}\nvoid serializeSinusoidalMotorConstraint(const MotorConstraintTemplate<SineWaveController>& constraint, std::ostream& ostream) {\n\tserializeBasicTypes<double>(constraint.minValue, ostream);\n\tserializeBasicTypes<double>(constraint.maxValue, ostream);\n\tserializeBasicTypes<double>(constraint.period, ostream);\n\tserializeBasicTypes<double>(constraint.currentStepInPeriod, ostream);\n}\nMotorConstraintTemplate<SineWaveController>* deserializeSinusoidalMotorConstraint(std::istream& istream) {\n\tdouble minLength = deserializeBasicTypes<double>(istream);\n\tdouble maxLength = deserializeBasicTypes<double>(istream);\n\tdouble period = deserializeBasicTypes<double>(istream);\n\tdouble currentStepInPeriod = deserializeBasicTypes<double>(istream);\n\n\tMotorConstraintTemplate<SineWaveController>* newConstraint = new MotorConstraintTemplate<SineWaveController>(minLength, maxLength, period);\n\tnewConstraint->currentStepInPeriod = currentStepInPeriod;\n\n\treturn newConstraint;\n}\n\nvoid serializeBallConstraint(const BallConstraint& constraint, std::ostream& ostream) {\n\tserializeBasicTypes<Vec3>(constraint.attachA, ostream);\n\tserializeBasicTypes<Vec3>(constraint.attachB, ostream);\n}\n\nBallConstraint* deserializeBallConstraint(std::istream& istream) {\n\tVec3 attachA = deserializeBasicTypes<Vec3>(istream);\n\tVec3 attachB = deserializeBasicTypes<Vec3>(istream);\n\n\treturn new BallConstraint(attachA, attachB);\n}\n\nvoid serializeHingeConstraint(const HingeConstraint& constraint, std::ostream& ostream) {\n\tserializeBasicTypes<Vec3>(constraint.attachA, ostream);\n\tserializeBasicTypes<Vec3>(constraint.axisA, ostream);\n\tserializeBasicTypes<Vec3>(constraint.attachB, ostream);\n\tserializeBasicTypes<Vec3>(constraint.axisB, ostream);\n}\n\nHingeConstraint* deserializeHingeConstraint(std::istream& istream) {\n\tVec3 attachA = deserializeBasicTypes<Vec3>(istream);\n\tVec3 axisA = deserializeBasicTypes<Vec3>(istream);\n\tVec3 attachB = deserializeBasicTypes<Vec3>(istream);\n\tVec3 axisB = deserializeBasicTypes<Vec3>(istream);\n\n\treturn new HingeConstraint(attachA, axisA, attachB, axisB);\n}\n\nvoid serializeBarConstraint(const BarConstraint& constraint, std::ostream& ostream) {\n\tserializeBasicTypes<Vec3>(constraint.attachA, ostream);\n\tserializeBasicTypes<Vec3>(constraint.attachB, ostream);\n\tserializeBasicTypes<double>(constraint.barLength, ostream);\n}\n\nBarConstraint* deserializeBarConstraint(std::istream& istream) {\n\tVec3 attachA = deserializeBasicTypes<Vec3>(istream);\n\tVec3 attachB = deserializeBasicTypes<Vec3>(istream);\n\tdouble length = deserializeBasicTypes<double>(istream);\n\n\treturn new BarConstraint(attachA, attachB, length);\n}\n\nvoid serializePolyhedronShapeClass(const PolyhedronShapeClass& polyhedron, std::ostream& ostream) {\n\tserializePolyhedron(polyhedron.asPolyhedron(), ostream);\n}\nPolyhedronShapeClass* deserializePolyhedronShapeClass(std::istream& istream) {\n\tPolyhedron poly = deserializePolyhedron(istream);\n\tPolyhedronShapeClass* result = new PolyhedronShapeClass(std::move(poly));\n\treturn result;\n}\n\nvoid serializeDirectionalGravity(const DirectionalGravity& gravity, std::ostream& ostream) {\n\tserializeBasicTypes<Vec3>(gravity.gravity, ostream);\n}\nDirectionalGravity* deserializeDirectionalGravity(std::istream& istream) {\n\tVec3 g = deserializeBasicTypes<Vec3>(istream);\n\treturn new DirectionalGravity(g);\n}\n\n#pragma endregion\n\n#pragma region serializePartPhysicalAndRelated\n\nstatic void serializeLayer(const Part& part, std::ostream& ostream) {\n\tserializeBasicTypes<uint32_t>(part.getLayerID(), ostream);\n}\nstatic WorldLayer* deserializeLayer(std::vector<ColissionLayer>& knownLayers, std::istream& istream) {\n\tuint32_t id = deserializeBasicTypes<uint32_t>(istream);\n\treturn getLayerByID(knownLayers, id);\n}\n\n\nvoid SerializationSessionPrototype::serializePartData(const Part& part, std::ostream& ostream) {\n\tshapeSerializer.serializeShape(part.hitbox, ostream);\n\tserializeBasicTypes<PartProperties>(part.properties, ostream);\n\tthis->serializePartExternalData(part, ostream);\n}\nvoid SerializationSessionPrototype::serializePartExternalData(const Part& part, std::ostream& ostream) {\n\t// no extra data by default\n}\nPart* DeSerializationSessionPrototype::deserializePartData(const GlobalCFrame& cframe, WorldLayer* layer, std::istream& istream) {\n\tShape shape = shapeDeserializer.deserializeShape(istream);\n\tPartProperties properties = deserializeBasicTypes<PartProperties>(istream);\n\tPart* result = this->deserializePartExternalData(Part(shape, cframe, properties), istream);\n\tresult->layer = layer;\n\treturn result;\n}\nPart* DeSerializationSessionPrototype::deserializePartExternalData(Part&& part, std::istream& istream) {\n\treturn new Part(std::move(part));\n}\n\nvoid SerializationSessionPrototype::serializeRigidBodyInContext(const RigidBody& rigidBody, std::ostream& ostream) {\n\tserializeLayer(*rigidBody.mainPart, ostream);\n\tserializePartData(*rigidBody.mainPart, ostream);\n\tserializeBasicTypes<uint32_t>(static_cast<uint32_t>(rigidBody.parts.size()), ostream);\n\tfor(const AttachedPart& atPart : rigidBody.parts) {\n\t\tserializeBasicTypes<CFrame>(atPart.attachment, ostream);\n\t\tserializeLayer(*atPart.part, ostream);\n\t\tserializePartData(*atPart.part, ostream);\n\t}\n}\n\nRigidBody DeSerializationSessionPrototype::deserializeRigidBodyWithContext(const GlobalCFrame& cframeOfMain, std::vector<ColissionLayer>& layers, std::istream& istream) {\n\tWorldLayer* layer = deserializeLayer(layers, istream);\n\tPart* mainPart = deserializePartData(cframeOfMain, layer, istream);\n\tRigidBody result(mainPart);\n\tuint32_t size = deserializeBasicTypes<uint32_t>(istream);\n\tresult.parts.reserve(size);\n\tfor(uint32_t i = 0; i < size; i++) {\n\t\tCFrame attach = deserializeBasicTypes<CFrame>(istream);\n\t\tWorldLayer* layer = deserializeLayer(layers, istream); \n\t\tPart* newPart = deserializePartData(cframeOfMain.localToGlobal(attach), layer, istream);\n\t\tresult.parts.push_back(AttachedPart{attach, newPart});\n\t}\n\treturn result;\n}\n\n\nvoid SerializationSessionPrototype::serializeConstraintInContext(const PhysicalConstraint& constraint, std::ostream& ostream) {\n\tstd::uint32_t indexA = this->physicalIndexMap[constraint.physA];\n\tstd::uint32_t indexB = this->physicalIndexMap[constraint.physB];\n\n\tserializeBasicTypes<std::uint32_t>(indexA, ostream);\n\tserializeBasicTypes<std::uint32_t>(indexB, ostream);\n\n\tdynamicConstraintSerializer.serialize(*constraint.constraint, ostream);\n}\n\nPhysicalConstraint DeSerializationSessionPrototype::deserializeConstraintInContext(std::istream& istream) {\n\tstd::uint32_t indexA = deserializeBasicTypes<std::uint32_t>(istream);\n\tstd::uint32_t indexB = deserializeBasicTypes<std::uint32_t>(istream);\n\n\tPhysical* physA = indexToPhysicalMap[indexA];\n\tPhysical* physB = indexToPhysicalMap[indexB];\n\n\treturn PhysicalConstraint(physA, physB, dynamicConstraintSerializer.deserialize(istream));\n}\n\n\nstatic void serializeHardPhysicalConnection(const HardPhysicalConnection& connection, std::ostream& ostream) {\n\tserializeBasicTypes<CFrame>(connection.attachOnChild, ostream);\n\tserializeBasicTypes<CFrame>(connection.attachOnParent, ostream);\n\n\tdynamicHardConstraintSerializer.serialize(*connection.constraintWithParent, ostream);\n}\n\nstatic HardPhysicalConnection deserializeHardPhysicalConnection(std::istream& istream) {\n\tCFrame attachOnChild = deserializeBasicTypes<CFrame>(istream);\n\tCFrame attachOnParent = deserializeBasicTypes<CFrame>(istream);\n\n\tHardConstraint* constraint = dynamicHardConstraintSerializer.deserialize(istream);\n\n\treturn HardPhysicalConnection(std::unique_ptr<HardConstraint>(constraint), attachOnChild, attachOnParent);\n}\n\nvoid SerializationSessionPrototype::serializePhysicalInContext(const Physical& phys, std::ostream& ostream) {\n\tphysicalIndexMap.emplace(&phys, currentPhysicalIndex++);\n\tserializeRigidBodyInContext(phys.rigidBody, ostream);\n\tserializeBasicTypes<uint32_t>(static_cast<uint32_t>(phys.childPhysicals.size()), ostream);\n\tfor(const ConnectedPhysical& p : phys.childPhysicals) {\n\t\tserializeHardPhysicalConnection(p.connectionToParent, ostream);\n\t\tserializePhysicalInContext(p, ostream);\n\t}\n}\n\nvoid SerializationSessionPrototype::serializeMotorizedPhysicalInContext(const MotorizedPhysical& phys, std::ostream& ostream) {\n\tserializeBasicTypes<Motion>(phys.motionOfCenterOfMass, ostream);\n\tserializeBasicTypes<GlobalCFrame>(phys.getMainPart()->getCFrame(), ostream);\n\n\tserializePhysicalInContext(phys, ostream);\n}\n\nvoid DeSerializationSessionPrototype::deserializeConnectionsOfPhysicalWithContext(std::vector<ColissionLayer>& layers, Physical& physToPopulate, std::istream& istream) {\n\tuint32_t childrenCount = deserializeBasicTypes<uint32_t>(istream);\n\tphysToPopulate.childPhysicals.reserve(childrenCount);\n\tfor(uint32_t i = 0; i < childrenCount; i++) {\n\t\tHardPhysicalConnection connection = deserializeHardPhysicalConnection(istream);\n\t\tGlobalCFrame cframeOfConnectedPhys = physToPopulate.getCFrame().localToGlobal(connection.getRelativeCFrameToParent());\n\t\tRigidBody b = deserializeRigidBodyWithContext(cframeOfConnectedPhys, layers, istream);\n\t\tphysToPopulate.childPhysicals.emplace_back(std::move(b), &physToPopulate, std::move(connection));\n\t\tConnectedPhysical& currentlyWorkingOn = physToPopulate.childPhysicals.back();\n\t\tindexToPhysicalMap.push_back(static_cast<Physical*>(&currentlyWorkingOn));\n\t\tdeserializeConnectionsOfPhysicalWithContext(layers, currentlyWorkingOn, istream);\n\t}\n}\n\nMotorizedPhysical* DeSerializationSessionPrototype::deserializeMotorizedPhysicalWithContext(std::vector<ColissionLayer>& layers, std::istream& istream) {\n\tMotion motion = deserializeBasicTypes<Motion>(istream);\n\tGlobalCFrame cf = deserializeBasicTypes<GlobalCFrame>(istream);\n\tMotorizedPhysical* mainPhys = new MotorizedPhysical(deserializeRigidBodyWithContext(cf, layers, istream));\n\tindexToPhysicalMap.push_back(static_cast<Physical*>(mainPhys));\n\tmainPhys->motionOfCenterOfMass = motion;\n\n\tdeserializeConnectionsOfPhysicalWithContext(layers, *mainPhys, istream);\n\n\tmainPhys->refreshPhysicalProperties();\n\treturn mainPhys;\n}\n\n#pragma endregion\n\n#pragma region serializeWorld\n\n#pragma region information collection\n\nvoid SerializationSessionPrototype::collectPartInformation(const Part& part) {\n\tthis->shapeSerializer.include(part.hitbox);\n}\n\nvoid SerializationSessionPrototype::collectPhysicalInformation(const Physical& phys) {\n\tfor(const Part& p : phys.rigidBody) {\n\t\tcollectPartInformation(p);\n\t}\n\n\tfor(const ConnectedPhysical& p : phys.childPhysicals) {\n\t\tcollectConnectedPhysicalInformation(p);\n\t}\n}\n\nvoid SerializationSessionPrototype::collectMotorizedPhysicalInformation(const MotorizedPhysical& motorizedPhys) {\n\tcollectPhysicalInformation(motorizedPhys);\n}\nvoid SerializationSessionPrototype::collectConnectedPhysicalInformation(const ConnectedPhysical& connectedPhys) {\n\tcollectPhysicalInformation(connectedPhys);\n}\n\n#pragma endregion\n\nstatic void serializeVersion(std::ostream& ostream) {\n\tserializeBasicTypes<int32_t>(CURRENT_VERSION_ID, ostream);\n}\n\nstatic void assertVersionCorrect(std::istream& istream) {\n\tuint32_t readVersionID = deserializeBasicTypes<uint32_t>(istream);\n\tif(readVersionID != CURRENT_VERSION_ID) {\n\t\tthrow SerializationException(\n\t\t\t\"This serialization version is outdated and cannot be read! Current \" +\n\t\t\tstd::to_string(CURRENT_VERSION_ID) +\n\t\t\t\" version from stream: \" +\n\t\t\tstd::to_string(readVersionID)\n\t\t);\n\t}\n}\n\n\nvoid SerializationSessionPrototype::serializeWorldLayer(const WorldLayer& layer, std::ostream& ostream) {\n\tuint32_t numberOfUnPhysicaledPartsInLayer = 0;\n\tlayer.tree.forEach([&numberOfUnPhysicaledPartsInLayer](const Part& p) {\n\t\tif(p.getPhysical() == nullptr) {\n\t\t\tnumberOfUnPhysicaledPartsInLayer++;\n\t\t}\n\t});\n\n\tserializeBasicTypes<uint32_t>(numberOfUnPhysicaledPartsInLayer, ostream);\n\tlayer.tree.forEach([this, &ostream](const Part& p) {\n\t\tif(p.getPhysical() == nullptr) {\n\t\t\tserializeBasicTypes<GlobalCFrame>(p.getCFrame(), ostream);\n\t\t\tthis->serializePartData(p, ostream);\n\t\t}\n\t});\n}\n\nvoid SerializationSessionPrototype::serializeWorld(const WorldPrototype& world, std::ostream& ostream) {\n\tfor(const MotorizedPhysical* p : world.physicals) {\n\t\tcollectMotorizedPhysicalInformation(*p);\n\t}\n\tfor(const ColissionLayer& clayer : world.layers) {\n\t\tfor(const WorldLayer& layer : clayer.subLayers) {\n\t\t\tlayer.tree.forEach([this](const Part& p) {\n\t\t\t\tif(p.getPhysical() == nullptr) {\n\t\t\t\t\tcollectPartInformation(p);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tserializeCollectedHeaderInformation(ostream);\n\t\n\n\t// actually serialize the world\n\n\tserializeBasicTypes<uint64_t>(world.age, ostream);\n\n\tserializeBasicTypes<uint32_t>(world.getLayerCount(), ostream);\n\tfor(int i = 0; i < world.getLayerCount(); i++) {\n\t\tfor(int j = 0; j <= i; j++) {\n\t\t\tserializeBasicTypes<bool>(world.doLayersCollide(i, j), ostream);\n\t\t}\n\t}\n\n\tfor(const ColissionLayer& layer : world.layers) {\n\t\tserializeWorldLayer(layer.subLayers[ColissionLayer::TERRAIN_PARTS_LAYER], ostream);\n\t}\n\n\tserializeBasicTypes<uint32_t>(static_cast<uint32_t>(world.physicals.size()), ostream);\n\tfor(const MotorizedPhysical* p : world.physicals) {\n\t\tserializeMotorizedPhysicalInContext(*p, ostream);\n\t}\n\n\tserializeBasicTypes<std::uint32_t>(static_cast<std::uint32_t>(world.constraints.size()), ostream);\n\tfor(const ConstraintGroup& cg : world.constraints) {\n\t\tserializeBasicTypes<std::uint32_t>(static_cast<std::uint32_t>(cg.constraints.size()), ostream);\n\t\tfor(const PhysicalConstraint& c : cg.constraints) {\n\t\t\tthis->serializeConstraintInContext(c, ostream);\n\t\t}\n\t}\n\tserializeBasicTypes<uint32_t>(static_cast<uint32_t>(world.externalForces.size()), ostream);\n\tfor(ExternalForce* force : world.externalForces) {\n\t\tdynamicExternalForceSerializer.serialize(*force, ostream);\n\t}\n}\n\nvoid DeSerializationSessionPrototype::deserializeWorldLayer(WorldLayer& layer, std::istream& istream) {\n\tuint32_t extraPartsInLayer = deserializeBasicTypes<uint32_t>(istream);\n\tfor(uint32_t i = 0; i < extraPartsInLayer; i++) {\n\t\tGlobalCFrame cf = deserializeBasicTypes<GlobalCFrame>(istream);\n\t\tlayer.tree.add(deserializePartData(cf, &layer, istream));\n\t}\n}\n\nvoid DeSerializationSessionPrototype::deserializeWorld(WorldPrototype& world, std::istream& istream) {\n\tthis->deserializeAndCollectHeaderInformation(istream);\n\n\tworld.age = deserializeBasicTypes<uint64_t>(istream);\n\n\tworld.layers.clear();\n\tuint32_t layerCount = deserializeBasicTypes<uint32_t>(istream);\n\tworld.layers.reserve(layerCount);\n\tfor(uint32_t i = 0; i < layerCount; i++) {\n\t\tworld.layers.emplace_back(&world, false);\n\t}\n\tfor(int i = 0; i < world.getLayerCount(); i++) {\n\t\tfor(int j = 0; j <= i; j++) {\n\t\t\tbool layersCollide = deserializeBasicTypes<bool>(istream);\n\t\t\tworld.setLayersCollide(i, j, layersCollide);\n\t\t}\n\t}\n\tfor(ColissionLayer& layer : world.layers) {\n\t\tdeserializeWorldLayer(layer.subLayers[ColissionLayer::TERRAIN_PARTS_LAYER], istream);\n\t}\n\n\tuint32_t numberOfPhysicals = deserializeBasicTypes<uint32_t>(istream);\n\tworld.physicals.reserve(numberOfPhysicals);\n\tfor(uint32_t i = 0; i < numberOfPhysicals; i++) {\n\t\tworld.addPhysicalWithExistingLayers(deserializeMotorizedPhysicalWithContext(world.layers, istream));\n\t}\n\n\tstd::uint32_t constraintCount = deserializeBasicTypes<std::uint32_t>(istream);\n\tworld.constraints.reserve(constraintCount);\n\tfor(std::uint32_t cg = 0; cg < constraintCount; cg++) {\n\t\tConstraintGroup group;\n\t\tstd::uint32_t numberOfConstraintsInGroup = deserializeBasicTypes<std::uint32_t>(istream);\n\t\tfor(std::uint32_t c = 0; c < numberOfConstraintsInGroup; c++) {\n\t\t\tgroup.constraints.push_back(this->deserializeConstraintInContext(istream));\n\t\t}\n\t\tworld.constraints.push_back(std::move(group));\n\t}\n\tuint32_t forceCount = deserializeBasicTypes<uint32_t>(istream);\n\tworld.externalForces.reserve(forceCount);\n\tfor(uint32_t i = 0; i < forceCount; i++) {\n\t\tExternalForce* force = dynamicExternalForceSerializer.deserialize(istream);\n\t\tworld.externalForces.push_back(force);\n\t}\n}\n\nvoid SerializationSessionPrototype::serializeParts(const Part* const parts[], size_t partCount, std::ostream& ostream) {\n\tfor(size_t i = 0; i < partCount; i++) {\n\t\tcollectPartInformation(*(parts[i]));\n\t}\n\tserializeCollectedHeaderInformation(ostream);\n\tserializeBasicTypes<uint32_t>(static_cast<uint32_t>(partCount), ostream);\n\tfor(size_t i = 0; i < partCount; i++) {\n\t\tserializeBasicTypes<GlobalCFrame>(parts[i]->getCFrame(), ostream);\n\t\tserializePartData(*(parts[i]), ostream);\n\t}\n}\n\nstd::vector<Part*> DeSerializationSessionPrototype::deserializeParts(std::istream& istream) {\n\tdeserializeAndCollectHeaderInformation(istream);\n\tsize_t numberOfParts = deserializeBasicTypes<uint32_t>(istream);\n\tstd::vector<Part*> result;\n\tresult.reserve(numberOfParts);\n\tfor(size_t i = 0; i < numberOfParts; i++) {\n\t\tGlobalCFrame cframeOfPart = deserializeBasicTypes<GlobalCFrame>(istream);\n\t\tPart* newPart = deserializePartData(cframeOfPart, nullptr, istream);\n\t\tresult.push_back(newPart);\n\t}\n\treturn result;\n}\n\n\nvoid SerializationSessionPrototype::serializeCollectedHeaderInformation(std::ostream& ostream) {\n\tserializeVersion(ostream);\n\tthis->shapeSerializer.sharedShapeClassSerializer.serializeRegistry([](const ShapeClass* sc, std::ostream& ostream) {dynamicShapeClassSerializer.serialize(*sc, ostream); }, ostream);\n}\n\nvoid DeSerializationSessionPrototype::deserializeAndCollectHeaderInformation(std::istream& istream) {\n\tassertVersionCorrect(istream);\n\tshapeDeserializer.sharedShapeClassDeserializer.deserializeRegistry([](std::istream& istream) {return dynamicShapeClassSerializer.deserialize(istream); }, istream);\n}\n\nstatic const ShapeClass* builtinKnownShapeClasses[]{&CubeClass::instance, &SphereClass::instance, &CylinderClass::instance};\nSerializationSessionPrototype::SerializationSessionPrototype(const std::vector<const ShapeClass*>& knownShapeClasses) : shapeSerializer(builtinKnownShapeClasses) {\n\tfor(const ShapeClass* sc : knownShapeClasses) {\n\t\tshapeSerializer.sharedShapeClassSerializer.addPredefined(sc);\n\t}\n}\n\nDeSerializationSessionPrototype::DeSerializationSessionPrototype(const std::vector<const ShapeClass*>& knownShapeClasses) : shapeDeserializer(builtinKnownShapeClasses) {\n\tfor(const ShapeClass* sc : knownShapeClasses) {\n\t\tshapeDeserializer.sharedShapeClassDeserializer.addPredefined(sc);\n\t}\n}\n\n#pragma endregion\n\n#pragma region dynamic serializers\n\nstatic DynamicSerializerRegistry<HardConstraint>::ConcreteDynamicSerializer<FixedConstraint> fixedConstraintSerializer\n(serializeFixedConstraint, deserializeFixedConstraint, 0);\nstatic DynamicSerializerRegistry<HardConstraint>::ConcreteDynamicSerializer<ConstantSpeedMotorConstraint> motorConstraintSerializer\n(serializeMotorConstraint, deserializeMotorConstraint, 1);\nstatic DynamicSerializerRegistry<HardConstraint>::ConcreteDynamicSerializer<SinusoidalPistonConstraint> pistonConstraintSerializer\n(serializePistonConstraint, deserializePistonConstraint, 2);\nstatic DynamicSerializerRegistry<HardConstraint>::ConcreteDynamicSerializer<MotorConstraintTemplate<SineWaveController>> sinusiodalMotorConstraintSerializer\n(serializeSinusoidalMotorConstraint, deserializeSinusoidalMotorConstraint, 3);\n\nstatic DynamicSerializerRegistry<Constraint>::ConcreteDynamicSerializer<BallConstraint> ballConstraintSerializer\n(serializeBallConstraint, deserializeBallConstraint, 0);\nstatic DynamicSerializerRegistry<Constraint>::ConcreteDynamicSerializer<HingeConstraint> hingeConstraintSerializer\n(serializeHingeConstraint, deserializeHingeConstraint, 1);\nstatic DynamicSerializerRegistry<Constraint>::ConcreteDynamicSerializer<BarConstraint> barConstraintSerializer\n(serializeBarConstraint, deserializeBarConstraint, 2);\n\nstatic DynamicSerializerRegistry<ShapeClass>::ConcreteDynamicSerializer<PolyhedronShapeClass> polyhedronSerializer\n(serializePolyhedronShapeClass, deserializePolyhedronShapeClass, 0);\n\nstatic DynamicSerializerRegistry<ExternalForce>::ConcreteDynamicSerializer<DirectionalGravity> gravitySerializer\n(serializeDirectionalGravity, deserializeDirectionalGravity, 0);\n\nDynamicSerializerRegistry<Constraint> dynamicConstraintSerializer{\n\t{typeid(BallConstraint), &ballConstraintSerializer},\n\t{typeid(HingeConstraint), &hingeConstraintSerializer},\n\t{typeid(BarConstraint), &barConstraintSerializer}\n};\nDynamicSerializerRegistry<HardConstraint> dynamicHardConstraintSerializer{\n\t{typeid(FixedConstraint), &fixedConstraintSerializer},\n\t{typeid(ConstantSpeedMotorConstraint), &motorConstraintSerializer},\n\t{typeid(SinusoidalPistonConstraint), &pistonConstraintSerializer},\n\t{typeid(MotorConstraintTemplate<SineWaveController>), &sinusiodalMotorConstraintSerializer}\n};\nDynamicSerializerRegistry<ShapeClass> dynamicShapeClassSerializer{\n\t{typeid(PolyhedronShapeClass), &polyhedronSerializer}\n};\nDynamicSerializerRegistry<ExternalForce> dynamicExternalForceSerializer{\n\t{typeid(DirectionalGravity), &gravitySerializer}\n};\n\n#pragma endregion\n};"
  },
  {
    "path": "Physics3D/misc/serialization/serialization.h",
    "content": "#pragma once\n\n#include <typeinfo>\n#include <typeindex>\n#include <iostream>\n#include <fstream>\n#include <vector>\n#include <set>\n#include <map>\n#include <unordered_map>\n\n#include \"../../math/fix.h\"\n#include \"../../math/linalg/vec.h\"\n#include \"../../math/linalg/mat.h\"\n#include \"../../math/cframe.h\"\n#include \"../../math/globalCFrame.h\"\n#include \"../../geometry/polyhedron.h\"\n#include \"../../geometry/shape.h\"\n#include \"../../part.h\"\n#include \"../../world.h\"\n#include \"../../physical.h\"\n#include \"../../hardconstraints/hardConstraint.h\"\n#include \"../../hardconstraints/fixedConstraint.h\"\n#include \"../../hardconstraints/motorConstraint.h\"\n#include \"../../constraints/ballConstraint.h\"\n#include \"../../externalforces/directionalGravity.h\"\n\n#include \"serializeBasicTypes.h\"\n#include \"sharedObjectSerializer.h\"\n#include \"dynamicSerialize.h\"\n\nnamespace P3D {\nvoid serializePolyhedron(const Polyhedron& poly, std::ostream& ostream);\nPolyhedron deserializePolyhedron(std::istream& istream);\n\nvoid serializeFixedConstraint(const FixedConstraint& object, std::ostream& ostream);\nFixedConstraint* deserializeFixedConstraint(std::istream& istream);\n\nvoid serializeMotorConstraint(const ConstantSpeedMotorConstraint& constraint, std::ostream& ostream);\nConstantSpeedMotorConstraint* deserializeMotorConstraint(std::istream& istream);\n\nvoid serializeDirectionalGravity(const DirectionalGravity& gravity, std::ostream& ostream);\nDirectionalGravity* deserializeDirectionalGravity(std::istream& istream);\n\n\nclass ShapeSerializer {\npublic:\n\tSharedObjectSerializer<const ShapeClass*> sharedShapeClassSerializer;\n\tShapeSerializer() = default;\n\ttemplate<typename List>\n\tinline ShapeSerializer(const List& knownShapeClasses) : sharedShapeClassSerializer(knownShapeClasses) {}\n\n\tvoid include(const Shape& shape);\n\tvoid serializeShape(const Shape& shape, std::ostream& ostream) const;\n};\nclass ShapeDeserializer {\npublic:\n\tSharedObjectDeserializer<const ShapeClass*> sharedShapeClassDeserializer;\n\tShapeDeserializer() = default;\n\ttemplate<typename List>\n\tinline ShapeDeserializer(const List& knownShapeClasses) : sharedShapeClassDeserializer(knownShapeClasses) {}\n\n\tShape deserializeShape(std::istream& ostream) const;\n};\n\n\nclass SerializationSessionPrototype {\nprotected:\n\tShapeSerializer shapeSerializer;\n\tstd::map<const Physical*, std::uint32_t> physicalIndexMap;\n\tstd::uint32_t currentPhysicalIndex = 0;\n\nprivate:\n\tvoid collectMotorizedPhysicalInformation(const MotorizedPhysical& motorizedPhys);\n\tvoid collectConnectedPhysicalInformation(const ConnectedPhysical& connectedPhys);\n\tvoid collectPhysicalInformation(const Physical& phys);\n\n\tvoid serializeMotorizedPhysicalInContext(const MotorizedPhysical& motorizedPhys, std::ostream& ostream);\n\tvoid serializePhysicalInContext(const Physical& phys, std::ostream& ostream);\n\tvoid serializeRigidBodyInContext(const RigidBody& rigidBody, std::ostream& ostream);\n\n\tvoid serializeWorldLayer(const WorldLayer& layer, std::ostream& ostream);\n\tvoid serializeConstraintInContext(const PhysicalConstraint& constraint, std::ostream& ostream);\n\nprotected:\n\tvirtual void collectPartInformation(const Part& part);\n\tvirtual void serializeCollectedHeaderInformation(std::ostream& ostream);\n\n\t// serializes everything but the part's cframe and layer index, to be done by the calling code as needed\n\t// calls serializePartExternalData for extending this serialization\n\tvoid serializePartData(const Part& part, std::ostream& ostream);\n\tvirtual void serializePartExternalData(const Part& part, std::ostream& ostream);\npublic:\n\t/*initializes the SerializationSession with the given ShapeClasses as \"known\" at deserialization, making it unneccecary to serialize them.\n\tImplicitly the builtin ShapeClasses from the physics engine, such as cubeClass and sphereClass are also included in this list */\n\tSerializationSessionPrototype(const std::vector<const ShapeClass*>& knownShapeClasses = std::vector<const ShapeClass*>());\n\n\tvoid serializeWorld(const WorldPrototype& world, std::ostream& ostream);\n\tvoid serializeParts(const Part* const parts[], size_t partCount, std::ostream& ostream);\n};\n\nclass DeSerializationSessionPrototype {\nprivate:\n\tMotorizedPhysical* deserializeMotorizedPhysicalWithContext(std::vector<ColissionLayer>& layers, std::istream& istream);\n\tvoid deserializeConnectionsOfPhysicalWithContext(std::vector<ColissionLayer>& layers, Physical& physToPopulate, std::istream& istream);\n\tRigidBody deserializeRigidBodyWithContext(const GlobalCFrame& cframeOfMain, std::vector<ColissionLayer>& layers, std::istream& istream);\n\tPhysicalConstraint deserializeConstraintInContext(std::istream& istream);\n\tvoid deserializeWorldLayer(WorldLayer& layer, std::istream& istream);\nprotected:\n\tShapeDeserializer shapeDeserializer;\n\tstd::vector<Physical*> indexToPhysicalMap;\n\n\t// creates a part with the given cframe, layer, and extra data it deserializes\n\t// calls deserializePartExternalData for extending this deserialization\n\tPart* deserializePartData(const GlobalCFrame& cframe, WorldLayer* layer, std::istream& istream);\n\tvirtual Part* deserializePartExternalData(Part&& part, std::istream& istream);\n\n\tvirtual void deserializeAndCollectHeaderInformation(std::istream& istream);\n\npublic:\n\t/*initializes the DeSerializationSession with the given ShapeClasses as \"known\" at deserialization, these are used along with the deserialized ShapeClasses\n\tImplicitly the builtin ShapeClasses from the physics engine, such as cubeClass and sphereClass are also included in this list */\n\tDeSerializationSessionPrototype(const std::vector<const ShapeClass*>& knownShapeClasses = std::vector<const ShapeClass*>());\n\n\n\tvoid deserializeWorld(WorldPrototype& world, std::istream& istream);\n\tstd::vector<Part*> deserializeParts(std::istream& istream);\n};\n\ntemplate<typename NewType, typename OriginalType>\nstd::vector<NewType*> castVector(std::vector<OriginalType*>&& old) {\n\tstd::vector<NewType*> result(old.size());\n\tfor(size_t i = 0; i < old.size(); i++) {\n\t\tresult[i] = static_cast<NewType*>(old[i]);\n\t}\n\treturn result;\n}\n\ntemplate<typename ExtendedPartType>\nclass SerializationSession : private SerializationSessionPrototype {\nprotected:\n\tusing SerializationSessionPrototype::shapeSerializer;\n\tusing SerializationSessionPrototype::serializeCollectedHeaderInformation;\n\n\tvirtual void collectExtendedPartInformation(const ExtendedPartType& part) {}\n\tvirtual void serializePartExternalData(const ExtendedPartType& part, std::ostream& ostream) {}\n\nprivate:\n\tvirtual void collectPartInformation(const Part& part) final override {\n\t\tSerializationSessionPrototype::collectPartInformation(part);\n\t\tconst ExtendedPartType& p = static_cast<const ExtendedPartType&>(part);\n\t\tcollectExtendedPartInformation(p);\n\t}\n\n\tvirtual void serializePartExternalData(const Part& part, std::ostream& ostream) final override {\n\t\tconst ExtendedPartType& p = static_cast<const ExtendedPartType&>(part);\n\t\tserializePartExternalData(p, ostream);\n\t}\npublic:\n\tusing SerializationSessionPrototype::SerializationSessionPrototype;\n\n\n\tvoid serializeWorld(const World<ExtendedPartType>& world, std::ostream& ostream) {\n\t\tSerializationSessionPrototype::serializeWorld(world, ostream);\n\t}\n\n\tvoid serializeParts(const ExtendedPartType* const parts[], size_t partCount, std::ostream& ostream) {\n\t\tstd::vector<const Part*> baseParts(partCount);\n\t\tfor(size_t i = 0; i < partCount; i++) {\n\t\t\tbaseParts[i] = parts[i];\n\t\t}\n\n\t\tSerializationSessionPrototype::serializeParts(&baseParts[0], partCount, ostream);\n\t}\n};\n\ntemplate<typename ExtendedPartType>\nclass DeSerializationSession : private DeSerializationSessionPrototype {\nprotected:\n\tusing DeSerializationSessionPrototype::shapeDeserializer;\n\tusing DeSerializationSessionPrototype::deserializeAndCollectHeaderInformation;\n\n\tvirtual ExtendedPartType* deserializeExtendedPart(Part&& partPrototype, std::istream& istream) = 0;\n\nprivate:\n\tinline virtual Part* deserializePartExternalData(Part&& part, std::istream& istream) final override { return deserializeExtendedPart(std::move(part), istream); }\n\npublic:\n\tusing DeSerializationSessionPrototype::DeSerializationSessionPrototype;\n\n\tvoid deserializeWorld(World<ExtendedPartType>& world, std::istream& istream) { DeSerializationSessionPrototype::deserializeWorld(world, istream); }\n\tstd::vector<ExtendedPartType*> deserializeParts(std::istream& istream) {\n\t\treturn castVector<ExtendedPartType>(DeSerializationSessionPrototype::deserializeParts(istream));\n\t}\n};\n\nextern DynamicSerializerRegistry<Constraint> dynamicConstraintSerializer;\nextern DynamicSerializerRegistry<HardConstraint> dynamicHardConstraintSerializer;\nextern DynamicSerializerRegistry<ShapeClass> dynamicShapeClassSerializer;\nextern DynamicSerializerRegistry<ExternalForce> dynamicExternalForceSerializer;\n};"
  },
  {
    "path": "Physics3D/misc/serialization/serializeBasicTypes.cpp",
    "content": "#include \"serializeBasicTypes.h\"\n\n#include <sstream>\n\nnamespace P3D {\nvoid serializeBasicTypes(const char* data, size_t size, std::ostream& ostream) {\n\tostream.write(data, size);\n}\n\nvoid deserializeBasicTypes(char* buf, size_t size, std::istream& istream) {\n\tistream.read(buf, size);\n}\n\ntemplate<>\nvoid serializeBasicTypes<char>(const char& c, std::ostream& ostream) {\n\tostream << c;\n}\ntemplate<>\nchar deserializeBasicTypes<char>(std::istream& istream) {\n\treturn istream.get();\n}\n\ntemplate<>\nvoid serializeBasicTypes<bool>(const bool& b, std::ostream& ostream) {\n\tserializeBasicTypes<char>(b ? 255 : 0, ostream);\n}\ntemplate<>\nbool deserializeBasicTypes<bool>(std::istream& istream) {\n\treturn deserializeBasicTypes<char>(istream) != 0;\n}\n\nvoid serializeString(const std::string& str, std::ostream& ostream) {\n\tserializeBasicTypes(str.c_str(), str.length(), ostream);\n\tserializeBasicTypes<char>('\\0', ostream);\n}\n\nstd::string deserializeString(std::istream& istream) {\n\tstd::stringstream sstream;\n\n\twhile(char c = istream.get()) {\n\t\tsstream << c;\n\t}\n\n\treturn sstream.str();\n}\n};"
  },
  {
    "path": "Physics3D/misc/serialization/serializeBasicTypes.h",
    "content": "#pragma once\n\n#include <iostream>\n#include <exception>\n#include <string>\n#include <type_traits>\n\nnamespace P3D {\nclass SerializationException : public std::exception {\n\tstd::string message;\npublic:\n\tSerializationException() = default;\n\tSerializationException(std::string message) : message(message) {}\n\n\tvirtual const char* what() const noexcept override {\n\t\treturn message.c_str();\n\t}\n};\n\nvoid serializeBasicTypes(const char* data, size_t size, std::ostream& ostream);\nvoid deserializeBasicTypes(char* buf, size_t size, std::istream& istream);\n\n/*\n\tTrivial value serialization\n\tIncluded are: char, int, float, double, long, Fix, Vector, Matrix, SymmetricMatrix, DiagonalMatrix, CFrame, Transform, GlobalCFrame, GlobalTransform, Bounds, GlobalBounds\n*/\ntemplate<typename T, std::enable_if_t<std::is_trivially_copyable<T>::value, int> = 0>\nvoid serializeBasicTypes(const T& i, std::ostream& ostream) {\n\tserializeBasicTypes(reinterpret_cast<const char*>(&i), sizeof(T), ostream);\n}\n\n/*\n\tTrivial value deserialization\n\tIncluded are: char, int, float, double, long, Fix, Vector, Matrix, SymmetricMatrix, DiagonalMatrix, CFrame, Transform, GlobalCFrame, GlobalTransform, Bounds, GlobalBounds\n*/\ntemplate<typename T, std::enable_if_t<std::is_trivially_copyable<T>::value, int> = 0>\nT deserializeBasicTypes(std::istream& istream) {\n\tunion {\n\t\tchar buf[sizeof(T)];\n\t\tT value;\n\t} un{};\n\tdeserializeBasicTypes(un.buf, sizeof(T), istream);\n\treturn un.value;\n}\n\ntemplate<>\nvoid serializeBasicTypes<char>(const char& c, std::ostream& ostream);\ntemplate<>\nchar deserializeBasicTypes<char>(std::istream& istream);\n\ntemplate<>\nvoid serializeBasicTypes<bool>(const bool& b, std::ostream& ostream);\ntemplate<>\nbool deserializeBasicTypes<bool>(std::istream& istream);\n\nvoid serializeString(const std::string& str, std::ostream& ostream);\nstd::string deserializeString(std::istream& istream);\n\ntemplate<typename T>\nvoid serializeArray(const T* data, size_t size, std::ostream& ostream) {\n\tfor(size_t i = 0; i < size; i++) {\n\t\tserializeBasicTypes<T>(data[i], ostream);\n\t}\n}\n\ntemplate<typename T>\nvoid deserializeArray(T* buf, size_t size, std::istream& istream) {\n\tfor(size_t i = 0; i < size; i++) {\n\t\tbuf[i] = deserializeBasicTypes<T>(istream);\n\t}\n}\n};\n"
  },
  {
    "path": "Physics3D/misc/serialization/sharedObjectSerializer.h",
    "content": "#pragma once\n\n#include <map>\n#include <vector>\n#include <assert.h>\n#include <limits>\n\n#include \"serializeBasicTypes.h\"\n\nnamespace P3D {\ntemplate<typename T, typename SerializeID = uint32_t>\nclass SharedObjectSerializer {\n\tSerializeID curPredefinedID = std::numeric_limits<SerializeID>::max();\n\tSerializeID curDynamicID = 0;\n\n\tstd::vector<T> itemsYetToSerialize;\npublic:\n\tstd::map<T, SerializeID> objectToIDMap;\n\n\tSharedObjectSerializer() = default;\n\ttemplate<typename ListType>\n\tSharedObjectSerializer(const ListType& knownObjects) {\n\t\tfor(const T& obj : knownObjects) {\n\t\t\taddPredefined(obj);\n\t\t}\n\t}\n\n\tvoid addPredefined(const T& obj) {\n\t\tassert(objectToIDMap.find(obj) == objectToIDMap.end());\n\t\tobjectToIDMap.emplace(obj, curPredefinedID);\n\t\tcurPredefinedID--;\n\t}\n\n\tvoid include(const T& obj) {\n\t\tif(objectToIDMap.find(obj) == objectToIDMap.end()) {\n\t\t\titemsYetToSerialize.push_back(obj);\n\t\t\tobjectToIDMap.emplace(obj, curDynamicID);\n\t\t\tcurDynamicID++;\n\t\t}\n\t}\n\n\t// The given deserializer must be of the form 'serialize(T, std::ostream&)'. The object may be passed by ref or const ref\n\ttemplate<typename Serializer>\n\tvoid serializeRegistry(Serializer serialize, std::ostream& ostream) {\n\t\tserializeBasicTypes<SerializeID>(static_cast<SerializeID>(itemsYetToSerialize.size()), ostream);\n\t\tfor(const T& item : itemsYetToSerialize) {\n\t\t\tserialize(item, ostream);\n\t\t}\n\t\titemsYetToSerialize.clear();\n\t}\n\n\tvoid serializeIDFor(const T& obj, std::ostream& ostream) const {\n\t\tauto found = objectToIDMap.find(obj);\n\t\tif(found == objectToIDMap.end()) throw SerializationException(\"The given object was not registered!\");\n\n\t\tserializeBasicTypes<SerializeID>((*found).second, ostream);\n\t}\n};\n\ntemplate<typename T, typename SerializeID = uint32_t>\nclass SharedObjectDeserializer {\n\tSerializeID curPredefinedID = std::numeric_limits<SerializeID>::max();\n\tSerializeID curDynamicID = 0;\n\npublic:\n\tstd::map<SerializeID, T> IDToObjectMap;\n\n\tSharedObjectDeserializer() = default;\n\ttemplate<typename ListType>\n\tSharedObjectDeserializer(const ListType& knownObjects) {\n\t\tfor(const T& obj : knownObjects) {\n\t\t\taddPredefined(obj);\n\t\t}\n\t}\n\n\tvoid addPredefined(const T& obj) {\n\t\tIDToObjectMap.emplace(curPredefinedID, obj);\n\t\tcurPredefinedID--;\n\t}\n\n\t// The given deserializer must be of the form 'T deserialize(std::istream&)', it may return references or const refs. \n\ttemplate<typename Deserializer>\n\tvoid deserializeRegistry(Deserializer deserialize, std::istream& istream) {\n\t\tsize_t numberOfObjectsToDeserialize = deserializeBasicTypes<SerializeID>(istream);\n\t\tfor(size_t i = 0; i < numberOfObjectsToDeserialize; i++) {\n\t\t\tT object = deserialize(istream);\n\t\t\tIDToObjectMap.emplace(curDynamicID, object);\n\t\t\tcurDynamicID++;\n\t\t}\n\t}\n\n\tT deserializeObject(std::istream& istream) const {\n\t\tSerializeID id = deserializeBasicTypes<SerializeID>(istream);\n\n\t\tauto found = IDToObjectMap.find(id);\n\t\tif(found == IDToObjectMap.end()) throw SerializationException(\"There is no associated object for the id \" + std::to_string(id));\n\n\t\treturn (*found).second;\n\t}\n};\n\n\ntemplate<typename T, typename SerializeID = uint32_t>\nclass FixedSharedObjectSerializerDeserializer {\n\tstd::map<T, SerializeID> objectToIDMap;\n\tstd::map<SerializeID, T> IDToObjectMap;\n\tSerializeID currentID = 0;\n\npublic:\n\tvoid registerObject(const T& object) {\n\t\tobjectToIDMap.emplace(object, currentID);\n\t\tIDToObjectMap.emplace(currentID, object);\n\t\tcurrentID++;\n\t}\n\tvoid removeObject(const T& object) {\n\t\tauto iter = objectToIDMap.find(object);\n\t\tSerializeID id = iter.second();\n\t\tIDToObjectMap.erase(id);\n\t\tobjectToIDMap.erase(object);\n\t}\n\tFixedSharedObjectSerializerDeserializer(std::initializer_list<T> list) {\n\t\tfor(const T& item : list) {\n\t\t\tregisterObject(item);\n\t\t}\n\t}\n\n\tvoid serialize(const T& object, std::ostream& ostream) const {\n\t\tauto iter = objectToIDMap.find(object);\n\t\tif(iter != objectToIDMap.end()) {\n\t\t\tserializeBasicTypes<SerializeID>((*iter).second, ostream);\n\t\t} else {\n\t\t\tthrow SerializationException(\"The given object was not registered\");\n\t\t}\n\t}\n\tT deserialize(std::istream& istream) const {\n\t\tSerializeID id = deserializeBasicTypes<SerializeID>(istream);\n\t\tauto iter = IDToObjectMap.find(id);\n\t\tif(iter != IDToObjectMap.end()) {\n\t\t\treturn (*iter).second;\n\t\t} else {\n\t\t\tthrow SerializationException(\"There is no registered object matching id \" + std::to_string(id));\n\t\t}\n\t}\n};\n};"
  },
  {
    "path": "Physics3D/misc/toString.h",
    "content": "#pragma once\n\n#include <string>\n#include <sstream>\n#include <stddef.h>\n#include <iomanip>\n\n#include \"../math/linalg/vec.h\"\n#include \"../math/linalg/mat.h\"\n#include \"../math/linalg/eigen.h\"\n#include \"../math/linalg/largeMatrix.h\"\n#include \"../math/cframe.h\"\n#include \"../math/position.h\"\n#include \"../math/globalCFrame.h\"\n#include \"../math/taylorExpansion.h\"\n#include \"../math/boundingBox.h\"\n#include \"../motion.h\"\n#include \"../relativeMotion.h\"\n\nnamespace P3D {\ntemplate<typename T>\ninline std::ostream& operator<<(std::ostream& os, const P3D::UnmanagedLargeMatrix<T>& matrix) {\n\tfor(int i = 0; i < matrix.h; i++) {\n\t\tfor(int j = 0; j < matrix.w; j++) {\n\t\t\tos << matrix(i, j) << '\\t';\n\t\t}\n\t\tos << '\\n';\n\t}\n\n\treturn os;\n}\n\ntemplate<typename T, size_t Rows>\ninline std::ostream& operator<<(std::ostream& os, const P3D::UnmanagedVerticalFixedMatrix<T, Rows>& matrix) {\n\tfor(int i = 0; i < Rows; i++) {\n\t\tfor(int j = 0; j < matrix.cols; j++) {\n\t\t\tos << matrix(i, j) << '\\t';\n\t\t}\n\t\tos << '\\n';\n\t}\n\n\treturn os;\n}\n\ntemplate<typename T, size_t Cols>\ninline std::ostream& operator<<(std::ostream& os, const P3D::UnmanagedHorizontalFixedMatrix<T, Cols>& matrix) {\n\tfor(int i = 0; i < matrix.rows; i++) {\n\t\tfor(int j = 0; j < Cols; j++) {\n\t\t\tos << matrix(i, j) << '\\t';\n\t\t}\n\t\tos << '\\n';\n\t}\n\n\treturn os;\n}\n\ntemplate<typename T>\ninline std::ostream& operator<<(std::ostream& os, const P3D::UnmanagedLargeVector<T>& vector) {\n\tfor(int i = 0; i < vector.n; i++) {\n\t\tos << vector[i] << ',';\n\t}\n\n\treturn os;\n}\n\ntemplate<typename T, size_t Size>\ninline std::ostream& operator<<(std::ostream& os, const P3D::Vector<T, Size>& vector) {\n\tos << std::fixed << std::setprecision(4);\n\tos << '(';\n\tfor(size_t i = 0; i < Size - 1; i++) {\n\t\tif (vector[i] >= 0)\n\t\t\tos << \"+\";\n\t\tos << vector[i] << \", \";\n\t}\n\n\tif (vector[Size - 1] >= 0)\n\t\tos << \"+\";\n\t\n\tos << vector[Size - 1] << \")\";\n\treturn os;\n}\n\ntemplate<int64_t N>\ninline std::ostream& operator<<(std::ostream& os, P3D::Fix<N> f) {\n\tint64_t intPart = f.value >> N;\n\tint64_t frac = f.value & ((1ULL << N) - 1);\n\n\tif(intPart < 0) {\n\t\tif(frac == 0) {\n\t\t\tintPart = -intPart;\n\t\t} else {\n\t\t\tintPart = -intPart-1;\n\t\t\tfrac = (1ULL << N) - frac;\n\t\t}\n\t\tos << '-';\n\t}\n\tstd::streamsize prec = os.precision();\n\t\n\tfor(int i = 0; i < prec; i++) {\n\t\tfrac *= 5; // multiply by powers of 10, dividing out the /2 with the shifts\n\t\t// multiply by 5 instead of 10, to stay away from the integer limit just a little longer\n\t}\n\n\tfrac = frac >> (N - prec - 1); // shift right, but minus the divisions previously done, except for last bit, which is used for rounding\n\tif(frac & 1) {\n\t\tfrac = (frac >> 1) + 1;\n\n\t\tint64_t maxFrac = 1;\n\t\tfor(int i = 0; i < prec; i++) {\n\t\t\tmaxFrac *= 10;\n\t\t}\n\t\tif(frac >= maxFrac) {\n\t\t\tfrac = 0;\n\t\t\t++intPart;\n\t\t}\n\t} else {\n\t\tfrac = frac >> 1;\n\t}\n\n\tbool fixed = os.flags() & std::ios::fixed;\n\n\tos << intPart;\n\tif(frac == 0) {\n\t\tif(fixed) {\n\t\t\tos << '.';\n\t\t\tfor(int i = 0; i < prec; i++) {\n\t\t\t\tos << '0';\n\t\t\t}\n\t\t}\n\t} else {\n\t\tos << '.';\n\t\tstd::streamsize digits = 1;\n\t\tint64_t digitCounter = 10;\n\t\twhile(frac >= digitCounter) {\n\t\t\tdigitCounter *= 10;\n\t\t\tdigits++;\n\t\t}\n\t\tstd::streamsize leadingZeros = prec - digits;\n\t\tfor(int i = 0; i < leadingZeros; i++) {\n\t\t\tos << '0';\n\t\t}\n\t\tif(!fixed) {\n\t\t\twhile(frac % 10 == 0) {\n\t\t\t\tfrac /= 10;\n\t\t\t}\n\t\t}\n\t\tos << frac;\n\t}\n\n\treturn os;\n}\n\ninline std::ostream& operator<<(std::ostream& os, P3D::Position position) {\n\tos << \"(\" << position.x << \", \" << position.y << \", \" << position.z << \")\";\n\treturn os;\n}\n\ninline std::ostream& operator<<(std::ostream& os, P3D::BoundingBox box) {\n\tos << \"BoundingBox(\" << box.min << \", \" << box.max << \")\";\n\treturn os;\n}\n\ntemplate<typename N, size_t Width, size_t Height>\ninline std::ostream& operator<<(std::ostream& os, const P3D::Matrix<N, Height, Width>& matrix) {\n\tos << \"(\";\n\n\tfor(size_t row = 0; row < Height; row++) {\n\t\tfor(size_t col = 0; col < Width - 1; col++) {\n\t\t\tos << matrix(row, col) << \", \";\n\t\t}\n\t\tos << matrix(row, Width - 1) << \"; \";\n\t}\n\tos << \")\";\n\n\treturn os;\n}\n\ntemplate<typename N, size_t Size>\ninline std::ostream& operator<<(std::ostream& os, const P3D::SymmetricMatrix<N, Size>& matrix) {\n\tos << \"(\";\n\n\tfor(size_t row = 0; row < Size; row++) {\n\t\tfor(size_t col = 0; col < Size - 1; col++) {\n\t\t\tos << matrix(row, col) << \", \";\n\t\t}\n\t\tos << matrix(row, Size - 1) << \"; \";\n\t}\n\tos << \")\";\n\n\treturn os;\n}\n\ntemplate<typename N, size_t Size>\ninline std::ostream& operator<<(std::ostream& os, const P3D::DiagonalMatrix<N, Size>& matrix) {\n\tos << \"Diag(\";\n\n\tfor(size_t i = 0; i < Size; i++) {\n\t\tos << matrix[i] << \"; \";\n\t}\n\tos << \")\";\n\n\treturn os;\n}\n\ntemplate<typename N, size_t Size>\ninline std::ostream& operator<<(std::ostream& os, const P3D::EigenValues<N, Size>& v) {\n\tos << \"EigenValues(\";\n\tfor(size_t i = 0; i < Size - 1; i++)\n\t\tos << v[i] << \", \";\n\n\tos << v[Size - 1] << \")\";\n\treturn os;\n}\n\ntemplate<typename T>\ninline std::ostream& operator<<(std::ostream& os, const P3D::Quaternion<T>& quat) {\n\tos << quat.w;\n\tif(quat.i >= 0) os << '+';\n\tos << quat.i << 'i';\n\tif(quat.j >= 0) os << '+';\n\tos << quat.j << 'j';\n\tif(quat.k >= 0) os << '+';\n\tos << quat.k << 'k';\n\treturn os;\n}\n\ntemplate<typename T>\ninline std::ostream& operator<<(std::ostream& os, const P3D::RotationTemplate<T>& rotation) {\n\tos << rotation.asRotationMatrix();\n\treturn os;\n}\n\ntemplate<typename T>\ninline std::ostream& operator<<(std::ostream& os, const P3D::CFrameTemplate<T>& cframe) {\n\tos << \"CFrame(\" << cframe.position << \", \" << cframe.rotation << \")\";\n\treturn os;\n}\ninline std::ostream& operator<<(std::ostream& os, const P3D::GlobalCFrame& cframe) {\n\tos << \"GlobalCFrame(\" << cframe.position << \", \" << cframe.rotation << \")\";\n\treturn os;\n}\n\ntemplate<typename T, std::size_t Size>\ninline std::ostream& operator<<(std::ostream& os, const P3D::TaylorExpansion<T, Size>& taylor) {\n\tif constexpr(Size > 0) {\n\t\tos << taylor[0] << \"x\";\n\t\tfor(std::size_t i = 1; i < Size; i++) {\n\t\t\tos << \" + \" << taylor[i] << \"x^\" << (i + 1) << '/' << (i+1) << '!';\n\t\t}\n\t}\n\treturn os;\n}\n\ntemplate<typename T, std::size_t Size>\ninline std::ostream& operator<<(std::ostream& os, const P3D::FullTaylorExpansion<T, Size>& taylor) {\n\tos << taylor.getConstantValue() << \" + \";\n\tos << taylor.getDerivatives();\n\treturn os;\n}\n\ninline std::ostream& operator<<(std::ostream& os, const P3D::TranslationalMotion& motion) {\n\tos << \"{vel: \" << motion.getVelocity();\n\tos << \", accel: \" << motion.getAcceleration() << \"}\";\n\treturn os;\n}\n\ninline std::ostream& operator<<(std::ostream& os, const P3D::RotationalMotion& motion) {\n\tos << \"{angularVel: \" << motion.getAngularVelocity();\n\tos << \", angularAccel: \" << motion.getAngularAcceleration() << \"}\";\n\treturn os;\n}\n\ninline std::ostream& operator<<(std::ostream& os, const P3D::Motion& motion) {\n\tos << \"{vel: \" << motion.getVelocity();\n\tos << \", angularVel: \" << motion.getAngularVelocity();\n\tos << \", accel: \" << motion.getAcceleration();\n\tos << \", angularAccel: \" << motion.getAngularAcceleration() << \"}\";\n\n\treturn os;\n}\n\ninline std::ostream& operator<<(std::ostream& os, const P3D::RelativeMotion& relMotion) {\n\tos << \"{motion: \" << relMotion.relativeMotion;\n\tos << \", offset: \" << relMotion.locationOfRelativeMotion << \"}\";\n\n\treturn os;\n}\n\ntemplate<typename T>\ninline std::string str(const T& obj) {\n\tstd::stringstream ss;\n\tss.precision(4);\n\tss << obj;\n\treturn ss.str();\n}\n};\n"
  },
  {
    "path": "Physics3D/misc/unreachable.h",
    "content": "#pragma once\n\nnamespace P3D {\n#ifdef NDEBUG\n#ifdef __GNUC__ // GCC 4.8+, Clang, Intel and other compilers compatible with GCC (-std=c++0x or above)\n[[noreturn]] inline __attribute__((always_inline)) void unreachable() {__builtin_unreachable();}\n#elif defined(_MSC_VER) // MSVC\n[[noreturn]] __forceinline void unreachable() {__assume(false);}\n#else // ???\ninline void unreachable() {}\n#endif\n#else\n#include <cassert>\ninline void unreachable() {assert(false);}\n#endif\n}\n"
  },
  {
    "path": "Physics3D/misc/validityHelper.cpp",
    "content": "#include \"validityHelper.h\"\n\n#include <vector>\n#include <map>\n#include <set>\n\n#include \"../geometry/polyhedron.h\"\n#include \"../geometry/indexedShape.h\"\n#include \"../misc/debug.h\"\n\n#include \"../boundstree/boundsTree.h\"\n#include \"../part.h\"\n#include \"../physical.h\"\n\nnamespace P3D {\nbool isValidTriangle(Triangle t, int vertexCount) {\n\treturn t.firstIndex != t.secondIndex && t.secondIndex != t.thirdIndex && t.thirdIndex != t.firstIndex &&\n\t\tt.firstIndex >= 0 && t.firstIndex < vertexCount &&\n\t\tt.secondIndex >= 0 && t.secondIndex < vertexCount &&\n\t\tt.thirdIndex >= 0 && t.thirdIndex < vertexCount;\n}\n\n// for every edge, of every triangle, check that it coincides with exactly one other triangle, in reverse order, revamped to be O(triangleCount) instead of O(triangleCount^2)\nstatic bool isComplete(const TriangleMesh& mesh) {\n\tstruct HitCount {\n\t\tint ascendingCount = 0;\n\t\tint descendingCount = 0;\n\t};\n\tbool verdict = true;\n\t// stores number of times two vertices appear as an edge, indexed by the lowest vertex\n\tstd::vector<std::map<int, HitCount>> hitCounts(mesh.triangleCount);\n\tfor(int i = 0; i < mesh.triangleCount; i++) {\n\t\tconst Triangle& t = mesh.getTriangle(i);\n\t\tstd::pair<int, int> indexPairs[]{{t.firstIndex, t.secondIndex}, {t.secondIndex, t.thirdIndex}, {t.thirdIndex, t.firstIndex}};\n\t\tfor(std::pair<int, int> indexes : indexPairs) {\n\t\t\tif(indexes.first == indexes.second) {\n\t\t\t\tDebug::logError(\"Invalid triangle! Triangle %d has a duplicate index! {%d, %d, %d}\", i, t.firstIndex, t.secondIndex, t.thirdIndex);\n\t\t\t\tverdict = false;\n\t\t\t}\n\t\t\tbool firstIsSmallerThanSecond = indexes.first < indexes.second;\n\t\t\tstd::pair<int, int> sortedIndexes = firstIsSmallerThanSecond ? indexes : std::pair<int, int>{indexes.second, indexes.first};\n\t\t\tstd::map<int, HitCount>& mp = hitCounts[sortedIndexes.first];\n\t\t\tauto found = mp.find(sortedIndexes.second);\n\t\t\tif(found == mp.end()) {\n\t\t\t\tif(firstIsSmallerThanSecond) {\n\t\t\t\t\tmp.emplace(sortedIndexes.second, HitCount{1,0});\n\t\t\t\t} else {\n\t\t\t\t\tmp.emplace(sortedIndexes.second, HitCount{0,1});\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif(firstIsSmallerThanSecond) {\n\t\t\t\t\t(*found).second.ascendingCount++;\n\t\t\t\t} else {\n\t\t\t\t\t(*found).second.descendingCount++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfor(int firstVertex = 0; firstVertex < hitCounts.size(); firstVertex++) {\n\t\tstd::map<int, HitCount>& everythingConnected = hitCounts[firstVertex];\n\n\t\tfor(std::pair<int, HitCount> edge : everythingConnected) {\n\t\t\tif(edge.second.ascendingCount != 1 || edge.second.descendingCount != 1) {\n\t\t\t\tDebug::logError(\"Edge {%d,%d} has bad triangles connected, ascendingCount: %d, descendingCount: %d\", firstVertex, edge.first, edge.second.ascendingCount, edge.second.descendingCount);\n\t\t\t\tverdict = false;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn verdict;\n}\n\nbool isValid(const TriangleMesh& mesh) {\n\tbool verdict = true;\n\tfor(int i = 0; i < mesh.triangleCount; i++) {\n\t\tconst Triangle& t = mesh.getTriangle(i);\n\t\tif(!isValidTriangle(t, mesh.vertexCount)) {\n\t\t\tDebug::logError(\"Invalid triangle! Triangle %d {%d, %d, %d} points to a nonexistent vertex or has a duplicate index!\", i, t.firstIndex, t.secondIndex, t.thirdIndex);\n\t\t\tverdict = false;\n\t\t}\n\t}\n\tif(verdict == false) {\n\t\treturn false;\n\t}\n\tint* usageCounts = new int[mesh.vertexCount];\n\tfor(int i = 0; i < mesh.vertexCount; i++) {\n\t\tusageCounts[i] = 0;\n\t}\n\tfor(int i = 0; i < mesh.triangleCount; i++) {\n\t\tusageCounts[mesh.getTriangle(i).firstIndex]++;\n\t\tusageCounts[mesh.getTriangle(i).secondIndex]++;\n\t\tusageCounts[mesh.getTriangle(i).thirdIndex]++;\n\t}\n\tfor(int i = 0; i < mesh.vertexCount; i++) {\n\t\tif(usageCounts[i] == 0) {\n\t\t\tDebug::logError(\"Vertex %d unused!\", i);\n\t\t\tverdict = false;\n\t\t}\n\t}\n\tdelete[] usageCounts;\n\treturn verdict;\n}\n\nbool isValid(const Polyhedron& poly) {\n\tif(!isValid(static_cast<const TriangleMesh&>(poly))) {\n\t\tDebug::logError(\"Invalid polyhedron: bad TriangleMesh\");\n\t\treturn false;\n\t}\n\tif(!isComplete(poly)) {\n\t\tDebug::logError(\"Invalid polyhedron: incomplete\");\n\t\treturn false;\n\t}\n\n\t// inverted to catch NaNs\n\tif(!(poly.getVolume() > 0)) {\n\t\tDebug::logError(\"Invalid polyhedron: inverted! Volume=%f\", poly.getVolume());\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nbool isValid(const IndexedShape& shape) {\n\tif(!isValid(static_cast<const Polyhedron&>(shape))) { return false; };\n\n\t// Assert that all neighbors are filled in\n\tfor(int i = 0; i < shape.triangleCount; i++)\n\t\tfor(int j = 0; j < 3; j++)\n\t\t\tif(shape.neighbors[i][j] < 0 || shape.neighbors[i][j] >= shape.triangleCount)\n\t\t\t\treturn false;\n\n\t// Assert that, every triangle's neighbors have it as one of their neighbors\n\tfor(int i = 0; i < shape.triangleCount; i++) {\n\t\tTriangleNeighbors thisNeighbors = shape.neighbors[i];\n\t\tfor(int j = 0; j < 3; j++) {\n\t\t\tint other = thisNeighbors[j];\n\t\t\tif(!shape.neighbors[other].hasNeighbor(i))\n\t\t\t\treturn false;\n\n\t\t\t// check that if they ARE neighbors, then they must share vertices\n\t\t\tint neighborsIndex = shape.neighbors[other].getNeighborIndex(i);\n\t\t\tTriangle t1 = shape.getTriangle(i);\n\t\t\tTriangle t2 = shape.getTriangle(other);\n\t\t\tif(!(t1[(j + 1) % 3] == t2[(neighborsIndex + 2) % 3] && t1[(j + 2) % 3] == t2[(neighborsIndex + 1) % 3]))\n\t\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n\nstatic bool isConnectedPhysicalValid(const ConnectedPhysical* phys, const MotorizedPhysical* mainPhys);\n\nstatic bool isPhysicalValid(const Physical* phys, const MotorizedPhysical* mainPhys) {\n\tif(phys->mainPhysical != mainPhys) {\n\t\tDebug::logError(\"Physical's parent is not mainPhys!\");\n\t\tDEBUGBREAK;\n\t\treturn false;\n\t}\n\tfor(const Part& part : phys->rigidBody) {\n\t\tif(part.getPhysical() != phys) {\n\t\t\tDebug::logError(\"part's parent's child is not part\");\n\t\t\tDEBUGBREAK;\n\t\t\treturn false;\n\t\t}\n\t}\n\tfor(const ConnectedPhysical& subPhys : phys->childPhysicals) {\n\t\tif(!isConnectedPhysicalValid(&subPhys, mainPhys)) return false;\n\t}\n\treturn true;\n}\n\nstatic bool isConnectedPhysicalValid(const ConnectedPhysical* phys, const MotorizedPhysical* mainPhys) {\n\treturn isPhysicalValid(phys, mainPhys);\n}\n\nbool isMotorizedPhysicalValid(const MotorizedPhysical* mainPhys) {\n\treturn isPhysicalValid(mainPhys, mainPhys);\n}\n};"
  },
  {
    "path": "Physics3D/misc/validityHelper.h",
    "content": "#pragma once\n\n#include \"../math/linalg/vec.h\"\n#include \"../math/linalg/mat.h\"\n#include \"../math/linalg/largeMatrix.h\"\n#include \"../math/cframe.h\"\n#include \"../motion.h\"\n#include \"../boundstree/boundsTree.h\"\n\n#include <cmath>\n\nnamespace P3D {\n#ifdef _MSC_VER\n#define DEBUGBREAK __debugbreak()\n#else\n#define DEBUGBREAK\n#endif\n\ninline bool isValid(double d) {\n\treturn std::isfinite(d) && std::abs(d) < 100000.0;\n}\ninline bool isValid(float f) {\n\treturn std::isfinite(f) && std::abs(f) < 100000.0; // sanity check\n}\n\ntemplate<typename T, size_t Size>\ninline bool isVecValid(const Vector<T, Size>& vec) {\n\tfor(size_t i = 0; i < Size; i++) {\n\t\tif(!isValid(vec[i])) return false;\n\t}\n\treturn true;\n}\n\ntemplate<typename T, size_t Height, size_t Width>\ninline bool isMatValid(const Matrix<T, Height, Width>& mat) {\n\tfor(size_t row = 0; row < Height; row++) {\n\t\tfor(size_t col = 0; col < Width; col++) {\n\t\t\tif(!isValid(mat(row, col))) return false;\n\t\t}\n\t}\n\treturn true;\n}\n\ntemplate<typename T, size_t Size>\ninline bool isMatValid(const SymmetricMatrix<T, Size>& mat) {\n\tfor(size_t row = 0; row < Size; row++) {\n\t\tfor(size_t col = row; col < Size; col++) {\n\t\t\tif(!isValid(mat(row, col))) return false;\n\t\t}\n\t}\n\treturn true;\n}\n\ntemplate<typename T, size_t Size>\ninline bool isMatValid(const DiagonalMatrix<T, Size>& mat) {\n\tfor(size_t i = 0; i < Size; i++) {\n\t\tif(!isValid(mat[i])) return false;\n\t}\n\treturn true;\n}\n\ntemplate<typename T>\ninline bool isVecValid(const UnmanagedLargeVector<T>& vec) {\n\tfor(size_t i = 0; i < vec.size(); i++) {\n\t\tif(!isValid(vec[i])) return false;\n\t}\n\treturn true;\n}\n\ntemplate<typename T>\ninline bool isMatValid(const UnmanagedLargeMatrix<T>& mat) {\n\tfor(size_t row = 0; row < mat.height(); row++) {\n\t\tfor(size_t col = 0; col < mat.width(); col++) {\n\t\t\tif(!isValid(mat(row, col))) return false;\n\t\t}\n\t}\n\treturn true;\n}\n\ntemplate<typename T, size_t Size>\ninline bool isMatValid(const UnmanagedHorizontalFixedMatrix<T, Size>& mat) {\n\tfor(size_t row = 0; row < mat.height(); row++) {\n\t\tfor(size_t col = 0; col < mat.width(); col++) {\n\t\t\tif(!isValid(mat(row, col))) return false;\n\t\t}\n\t}\n\treturn true;\n}\n\ntemplate<typename T, size_t Size>\ninline bool isMatValid(const UnmanagedVerticalFixedMatrix<T, Size>& mat) {\n\tfor(size_t row = 0; row < mat.height(); row++) {\n\t\tfor(size_t col = 0; col < mat.width(); col++) {\n\t\t\tif(!isValid(mat(row, col))) return false;\n\t\t}\n\t}\n\treturn true;\n}\n\ntemplate<typename T>\ninline bool isRotationValid(const MatrixRotationTemplate<T>& rotation) {\n\tSquareMatrix<T, 3> rotMat = rotation.asRotationMatrix();\n\treturn isValidRotationMatrix(rotMat);\n}\n\ntemplate<typename T>\ninline bool isRotationValid(const QuaternionRotationTemplate<T>& rotation) {\n\tQuaternion<T> rotQuat = rotation.asRotationQuaternion();\n\treturn isValidRotationQuaternion(rotQuat);\n}\n\ntemplate<typename T>\ninline bool isCFrameValid(const CFrameTemplate<T>& cframe) {\n\treturn isVecValid(cframe.getPosition()) && isRotationValid(cframe.getRotation());\n}\n\ntemplate<typename T, std::size_t DerivationCount>\ninline bool isTaylorExpansionValid(const TaylorExpansion<T, DerivationCount>& taylor) {\n\tfor(const Vec3& v : taylor) {\n\t\tif(!isVecValid(v)) return false;\n\t}\n\treturn true;\n}\n\ninline bool isTranslationalMotionValid(const TranslationalMotion& motion) {\n\treturn isTaylorExpansionValid(motion.translation);\n}\ninline bool isRotationalMotionValid(const RotationalMotion& motion) {\n\treturn isTaylorExpansionValid(motion.rotation);\n}\ninline bool isMotionValid(const Motion& motion) {\n\treturn isTranslationalMotionValid(motion.translation) && isRotationalMotionValid(motion.rotation);\n}\n\nstruct Triangle;\nclass TriangleMesh;\nclass Polyhedron;\nstruct IndexedShape;\n\nbool isValid(const TriangleMesh& mesh);\nbool isValid(const Polyhedron& poly);\nbool isValid(const IndexedShape& shape);\n\nbool isValidTriangle(Triangle t, int vertexCount);\n\nclass Part;\n\nclass MotorizedPhysical;\n\nbool isMotorizedPhysicalValid(const MotorizedPhysical* mainPhys);\n\ntemplate<typename Boundable>\ninline bool isBoundsTreeValidRecursive(const TreeTrunk& curNode, int curNodeSize, int depth = 0) {\n\tfor(int i = 0; i < curNodeSize; i++) {\n\t\tconst TreeNodeRef& subNode = curNode.subNodes[i];\n\n\t\tBoundsTemplate<float> foundBounds = curNode.getBoundsOfSubNode(i);\n\n\t\tif(subNode.isTrunkNode()) {\n\t\t\tconst TreeTrunk& subTrunk = subNode.asTrunk();\n\t\t\tint subTrunkSize = subNode.getTrunkSize();\n\n\t\t\tBoundsTemplate<float> realBounds = TrunkSIMDHelperFallback::getTotalBounds(subTrunk, subTrunkSize);\n\n\t\t\tif(realBounds != foundBounds) {\n\t\t\t\tstd::cout << \"(\" << i << \"/\" << curNodeSize << \") Trunk bounds not up to date\\n\";\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif(!isBoundsTreeValidRecursive<Boundable>(subTrunk, subTrunkSize, depth + 1)) {\n\t\t\t\tstd::cout << \"(\" << i << \"/\" << curNodeSize << \")\\n\";\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} else {\n\t\t\tconst Boundable* itemB = static_cast<const Boundable*>(subNode.asObject());\n\t\t\tif(foundBounds != itemB->getBounds()) {\n\t\t\t\tstd::cout << \"(\" << i << \"/\" << curNodeSize << \") Leaf not up to date\\n\";\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n\treturn true;\n}\n\ntemplate<typename Boundable>\nbool isBoundsTreeValid(const BoundsTreePrototype& tree) {\n\tstd::pair<const TreeTrunk&, int> baseTrunk = tree.getBaseTrunk();\n\treturn isBoundsTreeValidRecursive<Boundable>(baseTrunk.first, baseTrunk.second);\n}\n\ntemplate<typename Boundable>\nbool isBoundsTreeValid(const BoundsTree<Boundable>& tree) {\n\treturn isBoundsTreeValid<Boundable>(tree.getPrototype());\n}\n\ntemplate<typename Boundable>\ninline void treeValidCheck(const BoundsTree<Boundable>& tree) {\n\tif(!isBoundsTreeValid(tree)) throw \"tree invalid!\";\n}\n\n};\n"
  },
  {
    "path": "Physics3D/motion.h",
    "content": "#pragma once\n\n#include \"math/linalg/vec.h\"\n#include \"math/rotation.h\"\n\n#include \"math/taylorExpansion.h\"\n\nnamespace P3D {\nstruct TranslationalMotion {\n\tTaylor<Vec3> translation;\n\n\tinline TranslationalMotion() : translation{Vec3(0.0, 0.0, 0.0), Vec3(0.0, 0.0, 0.0)} {}\n\tinline TranslationalMotion(Vec3 velocity) : translation{velocity, Vec3(0.0, 0.0, 0.0)} {}\n\tinline TranslationalMotion(Vec3 velocity, Vec3 acceleration) : translation{velocity, acceleration} {}\n\tinline TranslationalMotion(const Taylor<Vec3>& translation) : translation(translation) {}\n\n\tinline Vec3 getVelocity() const { return translation[0]; }\n\tinline Vec3 getAcceleration() const { return translation[1]; }\n\n\tinline Vec3 getOffsetAfterDeltaT(double deltaT) const {\n\t\treturn translation(deltaT);\n\t}\n\n\tinline TranslationalMotion operator-() const {\n\t\treturn TranslationalMotion{-translation};\n\t}\n\n};\n\ninline TranslationalMotion operator+(const TranslationalMotion& first, const TranslationalMotion& second) {\n\treturn TranslationalMotion(first.translation + second.translation);\n}\ninline TranslationalMotion& operator+=(TranslationalMotion& first, const TranslationalMotion& second) {\n\tfirst.translation += second.translation;\n\treturn first;\n}\n\ninline TranslationalMotion operator-(const TranslationalMotion& first, const TranslationalMotion& second) {\n\treturn TranslationalMotion(first.translation - second.translation);\n}\ninline TranslationalMotion& operator-=(TranslationalMotion& first, const TranslationalMotion& second) {\n\tfirst.translation -= second.translation;\n\treturn first;\n}\n\ninline TranslationalMotion operator*(const TranslationalMotion& motion, double factor) {\n\treturn TranslationalMotion(motion.translation * factor);\n}\ninline TranslationalMotion operator*(double factor, const TranslationalMotion& motion) {\n\treturn motion * factor;\n}\n\ninline TranslationalMotion& operator*=(TranslationalMotion& motion, double factor) {\n\tmotion.translation *= factor;\n\treturn motion;\n}\n\n\nstruct RotationalMotion {\n\tTaylor<Vec3> rotation;\n\n\tinline RotationalMotion() : rotation{Vec3(0.0, 0.0, 0.0), Vec3(0.0, 0.0, 0.0)} {}\n\tinline RotationalMotion(Vec3 angularVelocity) : rotation{angularVelocity, Vec3(0.0, 0.0, 0.0)} {}\n\tinline RotationalMotion(Vec3 angularVelocity, Vec3 angularAcceleration) : rotation{angularVelocity, angularAcceleration} {}\n\tinline RotationalMotion(const Taylor<Vec3>& rotation) : rotation(rotation) {}\n\n\tinline Vec3 getAngularVelocity() const { return rotation[0]; }\n\tinline Vec3 getAngularAcceleration() const { return rotation[1]; }\n\n\tinline Vec3 getVelocityOfPoint(Vec3 relativePoint) const {\n\t\treturn getAngularVelocity() % relativePoint;\n\t}\n\tinline Vec3 getAccelerationOfPoint(Vec3 relativePoint) const {\n\t\treturn getAngularAcceleration() % relativePoint + getAngularVelocity() % (getAngularVelocity() % relativePoint);\n\t}\n\n\tinline TranslationalMotion getTranslationalMotionOfPoint(Vec3 relativePoint) const {\n\t\treturn TranslationalMotion(getVelocityOfPoint(relativePoint), getAccelerationOfPoint(relativePoint));\n\t}\n\n\tinline Vec3 getRotationAfterDeltaT(double deltaT) const {\n\t\treturn rotation(deltaT);\n\t}\n};\n\ninline RotationalMotion operator*(const RotationalMotion& motion, double factor) {\n\treturn RotationalMotion(motion.getAngularVelocity() * factor, motion.getAngularAcceleration() * factor);\n}\ninline RotationalMotion operator*(double factor, const RotationalMotion& motion) {\n\treturn motion * factor;\n}\n\nstruct Movement {\n\tVec3 translation;\n\tVec3 rotation;\n};\nstruct Motion {\n\tTranslationalMotion translation;\n\tRotationalMotion rotation;\n\n\tinline Motion() = default;\n\n\tinline Motion(Vec3 velocity, Vec3 angularVelocity) :\n\t\ttranslation(velocity),\n\t\trotation(angularVelocity) {}\n\tinline Motion(Vec3 velocity, Vec3 angularVelocity, Vec3 acceleration, Vec3 angularAcceleration) :\n\t\ttranslation(velocity, acceleration),\n\t\trotation(angularVelocity, angularAcceleration) {}\n\n\tinline Motion(TranslationalMotion translationMotion) :\n\t\ttranslation(translationMotion),\n\t\trotation() {}\n\n\tinline Motion(RotationalMotion rotationMotion) :\n\t\ttranslation(),\n\t\trotation(rotationMotion) {}\n\n\tinline Motion(TranslationalMotion translationMotion, RotationalMotion rotationMotion) :\n\t\ttranslation(translationMotion),\n\t\trotation(rotationMotion) {}\n\n\tinline Vec3 getVelocityOfPoint(Vec3 relativePoint) const {\n\t\treturn translation.getVelocity() + rotation.getVelocityOfPoint(relativePoint);\n\t}\n\tinline Vec3 getAccelerationOfPoint(Vec3 relativePoint) const {\n\t\treturn translation.getAcceleration() + rotation.getAccelerationOfPoint(relativePoint);\n\t}\n\tinline TranslationalMotion getTranslationalMotionOfPoint(Vec3 relativePoint) const {\n\t\treturn translation + rotation.getTranslationalMotionOfPoint(relativePoint);\n\t}\n\n\tinline Motion getMotionOfPoint(Vec3 relativePoint) const {\n\t\treturn Motion(\n\t\t\tgetTranslationalMotionOfPoint(relativePoint),\n\t\t\trotation\n\t\t);\n\t}\n\n\tinline Motion addRelativeMotion(const Motion& relativeMotion) const {\n\t\treturn Motion(\n\t\t\ttranslation.getVelocity() + relativeMotion.translation.getVelocity(),\n\t\t\trotation.getAngularVelocity() + relativeMotion.rotation.getAngularVelocity(),\n\t\t\ttranslation.getAcceleration() + relativeMotion.translation.getAcceleration() + rotation.getAngularVelocity() % relativeMotion.translation.getVelocity() * 2.0,\n\t\t\trotation.getAngularAcceleration() + relativeMotion.rotation.getAngularAcceleration() + rotation.getAngularVelocity() % relativeMotion.rotation.getAngularVelocity()\n\t\t);\n\t}\n\n\tinline Motion addOffsetRelativeMotion(Vec3 offset, const Motion& relativeMotion) const {\n\t\treturn this->getMotionOfPoint(offset).addRelativeMotion(relativeMotion);\n\t}\n\n\tinline Movement getMovementAfterDeltaT(double deltaT) const {\n\t\treturn Movement{translation.getOffsetAfterDeltaT(deltaT), rotation.getRotationAfterDeltaT(deltaT)};\n\t}\n\n\tinline Vec3 getVelocity() const { return translation.getVelocity(); }\n\tinline Vec3 getAcceleration() const { return translation.getAcceleration(); }\n\tinline Vec3 getAngularVelocity() const { return rotation.getAngularVelocity(); }\n\tinline Vec3 getAngularAcceleration() const { return rotation.getAngularAcceleration(); }\n\n\tinline Vec6 getDerivAsVec6(int deriv) const {\n\t\treturn join(translation.translation[deriv], rotation.rotation[deriv]);\n\t}\n};\n\ninline Motion operator+(const TranslationalMotion& motionOfStart, const Motion& motionToTranslate) {\n\treturn Motion(motionOfStart + motionToTranslate.translation, motionToTranslate.rotation);\n}\n\ninline TranslationalMotion localToGlobal(const Rotation& rot, const TranslationalMotion& motion) {\n\treturn TranslationalMotion(motion.translation.transform([&rot](const Vec3& v) {return rot.localToGlobal(v); }));\n}\ninline TranslationalMotion globalToLocal(const Rotation& rot, const TranslationalMotion& motion) {\n\treturn TranslationalMotion(motion.translation.transform([&rot](const Vec3& v) {return rot.globalToLocal(v); }));\n}\ninline RotationalMotion localToGlobal(const Rotation& rot, const RotationalMotion& motion) {\n\treturn RotationalMotion(motion.rotation.transform([&rot](const Vec3& v) {return rot.localToGlobal(v); }));\n}\ninline RotationalMotion globalToLocal(const Rotation& rot, const RotationalMotion& motion) {\n\treturn RotationalMotion(motion.rotation.transform([&rot](const Vec3& v) {return rot.globalToLocal(v); }));\n}\n\ninline Motion localToGlobal(const Rotation& rot, const Motion& motion) {\n\treturn Motion(localToGlobal(rot, motion.translation),\n\t\t\t\t  localToGlobal(rot, motion.rotation));\n}\n\ninline Motion globalToLocal(const Rotation& rot, const Motion& motion) {\n\treturn Motion(globalToLocal(rot, motion.translation),\n\t\t\t\t  globalToLocal(rot, motion.rotation));\n}\n};"
  },
  {
    "path": "Physics3D/part.cpp",
    "content": "#include \"part.h\"\n\n#include \"physical.h\"\n\n#include \"geometry/intersection.h\"\n\n#include \"misc/validityHelper.h\"\n#include \"misc/catchable_assert.h\"\n#include <stdexcept>\n#include <set>\n#include <utility>\n\n\n#include \"layer.h\"\n\nnamespace P3D {\nnamespace {\nvoid recalculate(Part* part) {\n\tpart->maxRadius = part->hitbox.getMaxRadius();\n}\n\nvoid recalculateAndUpdateParent(Part* part, const Bounds& oldBounds) {\n\trecalculate(part);\n\tPhysical* phys = part->getPhysical();\n\tif(phys != nullptr) {\n\t\tphys->notifyPartPropertiesChanged(part);\n\t}\n\tif(part->layer != nullptr) part->layer->notifyPartBoundsUpdated(part, oldBounds);\n}\n};\n\nPart::Part(const Shape& shape, const GlobalCFrame& position, const PartProperties& properties) : \n\thitbox(shape), properties(properties), maxRadius(shape.getMaxRadius()), cframe(position) {\n}\n\nPart::Part(const Shape& shape, Part& attachTo, const CFrame& attach, const PartProperties& properties) : \n\thitbox(shape), properties(properties), maxRadius(shape.getMaxRadius()), cframe(attachTo.cframe.localToGlobal(attach)) {\n\tattachTo.attach(this, attach);\n}\n\nPart::Part(const Shape& shape, Part& attachTo, HardConstraint* constraint, const CFrame& attachToParent, const CFrame& attachToThis, const PartProperties& properties) : \n\thitbox(shape), properties(properties), maxRadius(shape.getMaxRadius()), cframe(attachTo.getCFrame().localToGlobal(attachToParent.localToGlobal(constraint->getRelativeCFrame()).localToGlobal(attachToThis))) {\n\tattachTo.attach(this, constraint, attachToParent, attachToThis);\n}\n\nPart::Part(Part&& other) noexcept :\n\tcframe(other.cframe),\n\tlayer(other.layer),\n\tparent(other.parent), \n\thitbox(std::move(other.hitbox)), \n\tmaxRadius(other.maxRadius), \n\tproperties(std::move(other.properties)) {\n\n\tif (parent != nullptr) parent->notifyPartStdMoved(&other, this);\n\tif (layer != nullptr) layer->notifyPartStdMoved(&other, this);\n\n\tother.parent = nullptr;\n\tother.layer = nullptr;\n}\nPart& Part::operator=(Part&& other) noexcept {\n\tthis->cframe = other.cframe;\n\tthis->layer = other.layer;\n\tthis->parent = other.parent;\n\tthis->hitbox = std::move(other.hitbox);\n\tthis->maxRadius = other.maxRadius;\n\tthis->properties = std::move(other.properties);\n\n\tif (parent != nullptr) parent->notifyPartStdMoved(&other, this);\n\tif (layer != nullptr) layer->notifyPartStdMoved(&other, this);\n\n\tother.parent = nullptr;\n\tother.layer = nullptr;\n\n\treturn *this;\n}\n\nWorldPrototype* Part::getWorld() {\n\tif (layer == nullptr)\n\t\treturn nullptr;\n\t\n\treturn layer->parent->world;\n}\n\nPart::~Part() {\n\tthis->removeFromWorld();\n}\n\nint Part::getLayerID() const {\n\treturn layer->getID();\n}\n\nvoid Part::removeFromWorld() {\n\tPhysical* partPhys = this->getPhysical();\n\tif(partPhys) partPhys->removePart(this);\n\tif(this->layer) this->layer->removePart(this);\n}\n\nPartIntersection Part::intersects(const Part& other) const {\n\tCFrame relativeTransform = this->cframe.globalToLocal(other.cframe);\n\tstd::optional<Intersection> result = intersectsTransformed(this->hitbox, other.hitbox, relativeTransform);\n\tif(result) {\n\t\tPosition intersection = this->cframe.localToGlobal(result.value().intersection);\n\t\tVec3 exitVector = this->cframe.localToRelative(result.value().exitVector);\n\n\n\t\tcatchable_assert(isVecValid(exitVector));\n\n\n\t\treturn PartIntersection(intersection, exitVector);\n\t}\n\treturn PartIntersection();\n}\n\nBoundingBox Part::getLocalBounds() const {\n\tVec3 v = Vec3(this->hitbox.scale[0], this->hitbox.scale[1], this->hitbox.scale[2]);\n\treturn BoundingBox(-v, v);\n}\n\nBoundsTemplate<float> Part::getBounds() const {\n\tBoundingBox boundsOfHitbox = this->hitbox.getBounds(this->cframe.getRotation());\n\n\tassert(isVecValid(boundsOfHitbox.min));\n\tassert(isVecValid(boundsOfHitbox.max));\n\n\treturn BoundsTemplate<float>(boundsOfHitbox + getPosition());\n}\n\nvoid Part::scale(double scaleX, double scaleY, double scaleZ) {\n\tBounds oldBounds = this->getBounds();\n\tthis->hitbox = this->hitbox.scaled(scaleX, scaleY, scaleZ);\n\trecalculateAndUpdateParent(this, oldBounds);\n}\n\nvoid Part::setScale(const DiagonalMat3& scale) {\n\tBounds oldBounds = this->getBounds();\n\tthis->hitbox.scale = scale;\n\trecalculateAndUpdateParent(this, oldBounds);\n}\n\nvoid Part::setCFrame(const GlobalCFrame& newCFrame) {\n\tBounds oldBounds = this->getBounds();\n\tPhysical* partPhys = this->getPhysical();\n\tif(partPhys) {\n\t\tpartPhys->setPartCFrame(this, newCFrame);\n\t} else {\n\t\tthis->cframe = newCFrame;\n\t}\n\tif(this->layer != nullptr) this->layer->notifyPartGroupBoundsUpdated(this, oldBounds);\n}\n\nVec3 Part::getVelocity() const {\n\treturn this->getMotion().getVelocity();\n}\nVec3 Part::getAngularVelocity() const {\n\treturn this->getMotion().getAngularVelocity();\n}\nMotion Part::getMotion() const {\n\tif(this->getPhysical() == nullptr) return Motion();\n\tMotion parentsMotion = this->getPhysical()->getMotion();\n\tif(this->isMainPart()) {\n\t\treturn parentsMotion;\n\t} else {\n\t\tVec3 offset = this->getAttachToMainPart().getPosition();\n\t\treturn parentsMotion.getMotionOfPoint(offset);\n\t}\n}\n\nvoid Part::setVelocity(Vec3 velocity) {\n\tVec3 oldVel = this->getVelocity();\n\tthis->getMainPhysical()->motionOfCenterOfMass.translation.translation[0] += (velocity - oldVel);\n}\nvoid Part::setAngularVelocity(Vec3 angularVelocity) {\n\tVec3 oldAngularVel = this->getAngularVelocity();\n\tthis->getMainPhysical()->motionOfCenterOfMass.rotation.rotation[0] += (angularVelocity - oldAngularVel);\n}\nvoid Part::setMotion(Vec3 velocity, Vec3 angularVelocity) {\n\tsetAngularVelocity(angularVelocity); // angular velocity must come first, as it affects the velocity that setVelocity() uses\n\tsetVelocity(velocity);\n}\n\nbool Part::isTerrainPart() const {\n\treturn this->getPhysical() == nullptr;\n}\n\nconst Shape& Part::getShape() const {\n\treturn this->hitbox;\n}\nvoid Part::setShape(Shape newShape) {\n\tBounds oldBounds = this->getBounds();\n\tthis->hitbox = std::move(newShape);\n\trecalculateAndUpdateParent(this, oldBounds);\n}\n\nvoid Part::translate(Vec3 translation) {\n\tBounds oldBounds = this->getBounds();\n\tPhysical* phys = this->getPhysical();\n\tif(phys) {\n\t\tphys->mainPhysical->translate(translation);\n\t} else {\n\t\tthis->cframe += translation;\n\t}\n\tif(this->layer != nullptr) this->layer->notifyPartGroupBoundsUpdated(this, oldBounds);\n}\n\ndouble Part::getWidth() const {\n\treturn this->hitbox.getWidth();\n}\ndouble Part::getHeight() const {\n\treturn this->hitbox.getHeight();\n}\ndouble Part::getDepth() const {\n\treturn this->hitbox.getDepth();\n}\n\nvoid Part::setWidth(double newWidth) {\n\tBounds oldBounds = this->getBounds();\n\tthis->hitbox.setWidth(newWidth);\n\trecalculateAndUpdateParent(this, oldBounds);\n}\nvoid Part::setHeight(double newHeight) {\n\tBounds oldBounds = this->getBounds();\n\tthis->hitbox.setHeight(newHeight);\n\trecalculateAndUpdateParent(this, oldBounds);\n}\nvoid Part::setDepth(double newDepth) {\n\tBounds oldBounds = this->getBounds();\n\tthis->hitbox.setDepth(newDepth);\n\trecalculateAndUpdateParent(this, oldBounds);\n}\n\ndouble Part::getFriction() {\n\treturn this->properties.friction;\n}\n\ndouble Part::getDensity() {\n\treturn this->properties.density;\n}\n\ndouble Part::getBouncyness() {\n\treturn this->properties.bouncyness;\n}\n\nVec3 Part::getConveyorEffect() {\n\treturn this->properties.conveyorEffect;\n}\n\nvoid Part::setMass(double mass) {\n\tsetDensity(mass / hitbox.getVolume());\n\t// TODO update necessary?\n}\n\nvoid Part::setFriction(double friction) {\n\tthis->properties.friction = friction;\n\t// TODO update necessary?\n}\n\nvoid Part::setDensity(double density) {\n\tthis->properties.density = density;\n\t// TODO update necessary?\n}\n\nvoid Part::setBouncyness(double bouncyness) {\n\tthis->properties.bouncyness = bouncyness;\n\t// TODO update necessary?\n}\n\nvoid Part::setConveyorEffect(const Vec3& conveyorEffect) {\n\tthis->properties.conveyorEffect = conveyorEffect;\n\t// TODO update necessary?\n}\n\nvoid Part::applyForce(Vec3 relativeOrigin, Vec3 force) {\n\tPhysical* phys = this->getPhysical();\n\tassert(phys != nullptr);\n\tVec3 originOffset = this->getPosition() - phys->mainPhysical->getPosition();\n\tphys->mainPhysical->applyForce(originOffset + relativeOrigin, force);\n}\nvoid Part::applyForceAtCenterOfMass(Vec3 force) {\n\tPhysical* phys = this->getPhysical();\n\tassert(phys != nullptr);\n\tVec3 originOffset = this->getCenterOfMass() - phys->mainPhysical->getPosition();\n\tphys->mainPhysical->applyForce(originOffset, force);\n}\nvoid Part::applyMoment(Vec3 moment) {\n\tPhysical* phys = this->getPhysical();\n\tassert(phys != nullptr);\n\tphys->mainPhysical->applyMoment(moment);\n}\n\nstatic void mergePartLayers(Part* first, Part* second, const std::vector<FoundLayerRepresentative>& layersOfFirst, const std::vector<FoundLayerRepresentative>& layersOfSecond) {\n\tfor(const FoundLayerRepresentative& l1 : layersOfFirst) {\n\t\tfor(const FoundLayerRepresentative& l2 : layersOfSecond) {\n\t\t\tif(l1.layer == l2.layer) {\n\t\t\t\tl1.layer->mergeGroups(l1.part, l2.part);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n\nstatic void updateGroupBounds(std::vector<FoundLayerRepresentative>& layers, std::vector<Bounds>& bounds) {\n\tfor(size_t i = 0; i < layers.size(); i++) {\n\t\tlayers[i].layer->notifyPartGroupBoundsUpdated(layers[i].part, bounds[i]);\n\t}\n}\n\nstatic std::vector<Part*> getAllPartsInPhysical(Part* rep) {\n\tstd::vector<Part*> result;\n\tPhysical* repPhys = rep->getPhysical();\n\tif(repPhys != nullptr) {\n\t\trepPhys->mainPhysical->forEachPart([&result](Part& part) {\n\t\t\tresult.push_back(&part);\n\t\t});\n\t} else {\n\t\tresult.push_back(rep);\n\t}\n\treturn result;\n}\n\nstatic void addAllToGroupLayer(Part* layerOwner, const std::vector<Part*>& partsToAdd) {\n\tlayerOwner->layer->addAllToGroup(partsToAdd.begin(), partsToAdd.end(), layerOwner);\n\tfor(Part* p : partsToAdd) {\n\t\tp->layer = layerOwner->layer;\n\t}\n}\n\ntemplate<typename PhysicalMergeFunc>\nstatic void mergeLayersAround(Part* first, Part* second, PhysicalMergeFunc mergeFunc) {\n\tif(second->layer != nullptr) {\n\t\tstd::vector<FoundLayerRepresentative> layersOfSecond = findAllLayersIn(second);\n\t\tstd::vector<Bounds> boundsOfSecondParts(layersOfSecond.size());\n\t\tfor(size_t i = 0; i < layersOfSecond.size(); i++) {\n\t\t\tboundsOfSecondParts[i] = layersOfSecond[i].part->getBounds();\n\t\t}\n\n\t\tif(first->layer != nullptr) {\n\t\t\tstd::vector<FoundLayerRepresentative> layersOfFirst = findAllLayersIn(first);\n\t\t\n\t\t\tmergeFunc();\n\t\t\tupdateGroupBounds(layersOfSecond, boundsOfSecondParts);\n\n\t\t\tmergePartLayers(first, second, layersOfFirst, layersOfSecond);\n\t\t} else {\n\t\t\tstd::vector<Part*> partsInFirst = getAllPartsInPhysical(first);\n\t\t\t\n\t\t\tmergeFunc();\n\t\t\tupdateGroupBounds(layersOfSecond, boundsOfSecondParts);\n\t\t\t\n\t\t\taddAllToGroupLayer(second, partsInFirst);\n\t\t}\n\t} else {\n\t\tif(first->layer != nullptr) {\n\t\t\tstd::vector<Part*> partsInSecond = getAllPartsInPhysical(second);\n\n\t\t\tmergeFunc();\n\n\t\t\taddAllToGroupLayer(first, partsInSecond);\n\t\t} else {\n\t\t\tmergeFunc();\n\t\t}\n\t}\n}\n\nvoid Part::attach(Part* other, const CFrame& relativeCFrame) {\n\tmergeLayersAround(this, other, [&]() {\n\t\tPhysical* partPhys = this->ensureHasPhysical();\n\t\tpartPhys->attachPart(other, this->transformCFrameToParent(relativeCFrame));\n\t});\n}\n\nvoid Part::attach(Part* other, HardConstraint* constraint, const CFrame& attachToThis, const CFrame& attachToThat) {\n\tmergeLayersAround(this, other, [&]() {\n\t\tPhysical* partPhys = this->ensureHasPhysical();\n\t\tpartPhys->attachPart(other, constraint, attachToThis, attachToThat);\n\t});\n}\n\nvoid Part::detach() {\n\tif(this->parent == nullptr) throw std::logic_error(\"No physical to detach from!\");\n\tthis->parent->detachPart(this);\n\tif(this->layer != nullptr) {\n\t\tthis->layer->moveOutOfGroup(this);\n\t}\n}\n\nPhysical* Part::getPhysical() const {\n\treturn this->parent;\n}\nvoid Part::setRigidBodyPhysical(Physical* phys) {\n\tthis->parent = phys;\n\tthis->parent->rigidBody.mainPart->parent = phys;\n\tfor(AttachedPart& p : this->parent->rigidBody.parts) {\n\t\tp.part->parent = phys;\n\t}\n}\nMotorizedPhysical* Part::getMainPhysical() const {\n\tPhysical* phys = this->getPhysical();\n\treturn phys->mainPhysical;\n}\nPhysical* Part::ensureHasPhysical() {\n\tif(this->parent == nullptr) {\n\t\tthis->parent = new MotorizedPhysical(this);\n\t}\n\treturn this->parent;\n}\nbool Part::hasAttachedParts() const {\n\tPhysical* thisPhys = this->getPhysical();\n\treturn thisPhys != nullptr && !thisPhys->rigidBody.parts.empty();\n}\nCFrame& Part::getAttachToMainPart() const {\n\tassert(!this->isMainPart());\n\treturn this->parent->rigidBody.getAttachFor(this).attachment;\n}\n\nCFrame Part::transformCFrameToParent(const CFrame& cframeRelativeToPart) const {\n\tif(this->isMainPart()) {\n\t\treturn cframeRelativeToPart;\n\t} else {\n\t\treturn this->getAttachToMainPart().localToGlobal(cframeRelativeToPart);\n\t}\n}\n\nbool Part::isMainPart() const {\n\treturn this->parent == nullptr || this->parent->rigidBody.mainPart == this;\n}\n\nvoid Part::makeMainPart() {\n\tif(!this->isMainPart()) {\n\t\tthis->parent->makeMainPart(this);\n\t}\n}\n\nbool Part::isValid() const {\n\tassert(std::isfinite(hitbox.getVolume()));\n\tassert(std::isfinite(maxRadius));\n\tassert(std::isfinite(properties.density));\n\tassert(std::isfinite(properties.friction));\n\tassert(std::isfinite(properties.bouncyness));\n\tassert(isVecValid(properties.conveyorEffect));\n\n\treturn true;\n}\n};"
  },
  {
    "path": "Physics3D/part.h",
    "content": "#pragma once\n\n\n// this is a central class to everything else, but applications using the library don't need to include all these, as they are implementation details. \nnamespace P3D {\nclass Part;\nclass HardConstraint;\nclass RigidBody;\nclass Physical;\nclass ConnectedPhysical;\nclass MotorizedPhysical;\nclass WorldLayer;\nclass WorldPrototype;\n};\n\n#include \"geometry/shape.h\"\n#include \"math/linalg/mat.h\"\n#include \"math/position.h\"\n#include \"math/globalCFrame.h\"\n#include \"math/bounds.h\"\n#include \"motion.h\"\n\nnamespace P3D {\nstruct PartProperties {\n\tdouble density;\n\tdouble friction;\n\tdouble bouncyness;\n\n\t/*\n\t\tThis is extra velocity that should be added to any colission\n\t\tif this part is anchored, this gives the velocity of another part sliding on top of it, with perfect friction\n\n\t\tIn other words, this is the desired relative velocity for there to be no friction\n\t*/\n\tVec3 conveyorEffect{0, 0, 0};\n};\n\nstruct PartIntersection {\n\tbool intersects;\n\tPosition intersection;\n\tVec3 exitVector;\n\n\tPartIntersection() : intersects(false) {}\n\tPartIntersection(const Position& intersection, const Vec3& exitVector) :\n\t\tintersects(true),\n\t\tintersection(intersection),\n\t\texitVector(exitVector) {}\n};\n\nclass Part {\n\tfriend class RigidBody;\n\tfriend class Physical;\n\tfriend class ConnectedPhysical;\n\tfriend class MotorizedPhysical;\n\tfriend class WorldPrototype;\n\tfriend class ConstraintGroup;\n\n\tGlobalCFrame cframe;\n\tPhysical* parent = nullptr;\n\npublic:\n\tWorldLayer* layer = nullptr;\n\tShape hitbox;\n\tdouble maxRadius;\n\tPartProperties properties;\n\n\tPart() = default;\n\tPart(const Shape& shape, const GlobalCFrame& position, const PartProperties& properties);\n\tPart(const Shape& shape, Part& attachTo, const CFrame& attach, const PartProperties& properties);\n\tPart(const Shape& shape, Part& attachTo, HardConstraint* constraint, const CFrame& attachToParent, const CFrame& attachToThis, const PartProperties& properties);\n\t~Part();\n\n\tPart(const Part& other) = delete;\n\tPart& operator=(const Part& other) = delete;\n\tPart(Part&& other) noexcept;\n\tPart& operator=(Part&& other) noexcept;\n\n\tWorldPrototype* getWorld();\n\n\tPartIntersection intersects(const Part& other) const;\n\tvoid scale(double scaleX, double scaleY, double scaleZ);\n\tvoid setScale(const DiagonalMat3& scale);\n\t\n\tBoundsTemplate<float> getBounds() const;\n\tBoundingBox getLocalBounds() const;\n\n\tPosition getPosition() const { return cframe.getPosition(); }\n\tdouble getMass() const { return hitbox.getVolume() * properties.density; }\n\tvoid setMass(double mass);\n\tVec3 getLocalCenterOfMass() const { return hitbox.getCenterOfMass(); }\n\tPosition getCenterOfMass() const { return cframe.localToGlobal(this->getLocalCenterOfMass()); }\n\tSymmetricMat3 getInertia() const { return hitbox.getInertia() * properties.density; }\n\tconst GlobalCFrame& getCFrame() const { return cframe; }\n\tvoid setCFrame(const GlobalCFrame& newCFrame);\n\n\tVec3 getVelocity() const;\n\tVec3 getAngularVelocity() const;\n\tMotion getMotion() const;\n\n\t// does not modify angular velocity\n\tvoid setVelocity(Vec3 velocity);\n\t// modifies velocity\n\tvoid setAngularVelocity(Vec3 angularVelocity);\n\tvoid setMotion(Vec3 velocity, Vec3 angularVelocity);\n\n\tbool isTerrainPart() const;\n\tbool isMainPart() const;\n\tvoid makeMainPart();\n\n\tconst Shape& getShape() const;\n\tvoid setShape(Shape newShape);\n\n\tvoid translate(Vec3 translation);\n\n\tdouble getWidth() const;\n\tdouble getHeight() const;\n\tdouble getDepth() const;\n\n\tvoid setWidth(double newWidth);\n\tvoid setHeight(double newHeight);\n\tvoid setDepth(double newDepth);\n\n\tdouble getFriction();\n\tdouble getDensity();\n\tdouble getBouncyness();\n\tVec3 getConveyorEffect();\n\t\n\tvoid setFriction(double friction);\n\tvoid setDensity(double density);\n\tvoid setBouncyness(double bouncyness);\n\tvoid setConveyorEffect(const Vec3& conveyorEffect);\n\t\n\tvoid applyForce(Vec3 relativeOrigin, Vec3 force);\n\tvoid applyForceAtCenterOfMass(Vec3 force);\n\tvoid applyMoment(Vec3 moment);\n\n\tint getLayerID() const;\n\n\tCFrame& getAttachToMainPart() const;\n\tCFrame transformCFrameToParent(const CFrame& cframeRelativeToPart) const;\n\tPhysical* getPhysical() const;\n\tvoid setRigidBodyPhysical(Physical* phys);\n\tMotorizedPhysical* getMainPhysical() const;\n\tPhysical* ensureHasPhysical();\n\n\tbool hasAttachedParts() const;\n\tvoid attach(Part* other, const CFrame& relativeCFrame);\n\tvoid attach(Part* other, HardConstraint* constraint, const CFrame& attachToThis, const CFrame& attachToThat);\n\tvoid detach();\n\tvoid removeFromWorld();\n\n\tbool isValid() const;\n};\n};\n"
  },
  {
    "path": "Physics3D/physical.cpp",
    "content": "#include \"physical.h\"\n\n#include \"inertia.h\"\n#include \"world.h\"\n#include \"math/linalg/mat.h\"\n#include \"math/linalg/trigonometry.h\"\n\n#include \"misc/debug.h\"\n#include \"misc/validityHelper.h\"\n#include \"misc/unreachable.h\"\n\n#include \"layer.h\"\n\n#include <algorithm>\n#include <cassert>\n#include <stdexcept>\n\n/*\n\t===== Physical Structure =====\n*/\n\nnamespace P3D {\n#pragma region structure\n\nPhysical::Physical(Part* part, MotorizedPhysical* mainPhysical) : rigidBody(part), mainPhysical(mainPhysical) {\n\tassert(part->parent == nullptr);\n\tpart->parent = this;\n}\n\nPhysical::Physical(RigidBody&& rigidBody, MotorizedPhysical* mainPhysical) : rigidBody(std::move(rigidBody)), mainPhysical(mainPhysical) {\n\tfor(Part& p : this->rigidBody) {\n\t\tassert(p.parent == nullptr);\n\t\tp.parent = this;\n\t}\n}\n\nPhysical::Physical(Physical&& other) noexcept :\n\trigidBody(std::move(other.rigidBody)), \n\tmainPhysical(other.mainPhysical),\n\tchildPhysicals(std::move(other.childPhysicals)) {\n\tthis->rigidBody.mainPart->setRigidBodyPhysical(this);\n\tfor(ConnectedPhysical& p : this->childPhysicals) {\n\t\tp.parent = this;\n\t}\n}\n\nPhysical& Physical::operator=(Physical&& other) noexcept {\n\tthis->rigidBody = std::move(other.rigidBody);\n\tthis->mainPhysical = other.mainPhysical;\n\tthis->childPhysicals = std::move(other.childPhysicals);\n\tthis->rigidBody.mainPart->setRigidBodyPhysical(this);\n\tfor(ConnectedPhysical& p : this->childPhysicals) {\n\t\tp.parent = this;\n\t}\n\t\n\treturn *this;\n}\n\nConnectedPhysical::ConnectedPhysical(RigidBody&& rigidBody, Physical* parent, HardPhysicalConnection&& connectionToParent) :\n\tPhysical(std::move(rigidBody), parent->mainPhysical), parent(parent), connectionToParent(std::move(connectionToParent)) {}\n\nConnectedPhysical::ConnectedPhysical(Physical&& phys, Physical* parent, HardPhysicalConnection&& connectionToParent) :\n\tPhysical(std::move(phys)), parent(parent), connectionToParent(std::move(connectionToParent)) {}\n\nConnectedPhysical::ConnectedPhysical(Physical&& phys, Physical* parent, HardConstraint* constraintWithParent, const CFrame& attachOnThis, const CFrame& attachOnParent) :\n\tPhysical(std::move(phys)), parent(parent), connectionToParent(std::unique_ptr<HardConstraint>(constraintWithParent), attachOnThis, attachOnParent) {}\n\nMotorizedPhysical::MotorizedPhysical(Part* mainPart) : Physical(mainPart, this) {\n\trefreshPhysicalProperties();\n}\n\nMotorizedPhysical::MotorizedPhysical(RigidBody&& rigidBody) : Physical(std::move(rigidBody), this) {\n\trefreshPhysicalProperties();\n}\n\nMotorizedPhysical::MotorizedPhysical(Physical&& movedPhys) : Physical(std::move(movedPhys)) {\n\tthis->setMainPhysicalRecursive(this);\n\trefreshPhysicalProperties();\n}\n\nvoid Physical::makeMainPart(Part* newMainPart) {\n\tif (rigidBody.getMainPart() == newMainPart) {\n\t\tDebug::logWarn(\"Attempted to replace mainPart with mainPart\");\n\t\treturn;\n\t}\n\tAttachedPart& atPart = rigidBody.getAttachFor(newMainPart);\n\t\n\tmakeMainPart(atPart);\n}\n\nvoid Physical::makeMainPart(AttachedPart& newMainPart) {\n\tCFrame newCenterCFrame = rigidBody.makeMainPart(newMainPart);\n\n\t// Update attached physicals\n\tfor(ConnectedPhysical& connectedPhys : childPhysicals) {\n\t\tconnectedPhys.connectionToParent.attachOnParent = newCenterCFrame.globalToLocal(connectedPhys.connectionToParent.attachOnParent);\n\t}\n\tif(!isMainPhysical()) {\n\t\tConnectedPhysical* self = (ConnectedPhysical*) this;\n\t\tself->connectionToParent.attachOnChild = newCenterCFrame.globalToLocal(self->connectionToParent.attachOnChild);\n\t}\n}\n\ntemplate<typename T>\nstatic inline bool liesInVector(const std::vector<T>& vec, const T* ptr) {\n\treturn &vec[0] <= ptr && &vec[0]+vec.size() > ptr;\n}\n\n/*\n\tWe will build a new tree, starting from a copy of the current physical\n\n\tS is the physical we are currently adding a child to\n\tOS is old location of S, which is now invalid and which will be replaced in the next iteration\n\tP (for parent) is the old parent of S, to be moved to be a child of S\n\tT (for trash) is the physical currently being replaced by P\n\t\n\tWe wish to make S the new Main Physical\n\n\t      M\n\t     / \\\n\t    /\\\n\t   P\n\t  / \\\n\t S\n\t/ \\\n\n\tSplit S off from the tree\n\tAdd a new empty node to S, call it T\n\n\t            .\n\t           / \\\n\t S        P\n\t/|\\      / \\\n\t   T   OS\n\t\n\tCopy P to T, reversing OS's attachment\n\n\t S\n\t/|\\        .\n\t   T      / \\\n\t  / \\    P\n\tOS\n\n\tT is the new S\n\tOS is the new T\n\tP is the new OS\n\tP's parent is the new P\n\n\tif P has no parent, then the separate tree of S is copied into it and is the new mainPhysical\n*/\nvoid ConnectedPhysical::makeMainPhysical() {\n\tPhysical* P = this->parent;\n\tPhysical newTop = std::move(*this);\n\tConnectedPhysical* T = nullptr;\n\tConnectedPhysical* OS = this;\n\tPhysical* S = &newTop;\n\n\t// OS's Physical fields are invalid, but it's ConnectedPhysical fields are still valid\n\n\tbool firstRun = true;\n\twhile(true) {\n\t\tbool PIsMain = P->isMainPhysical();\n\t\t// this part moves P down to be the child of S\n\t\t// swap attachOnParent and attachOnThis and use inverted constraint\n\t\tif(firstRun) {\n\t\t\tS->childPhysicals.push_back(ConnectedPhysical(std::move(*P),\n\t\t\t\t\t\t\t\t\t    S,\n\t\t\t\t\t\t\t\t\t    std::move(*OS).connectionToParent.inverted()));\n\t\t\tT = &S->childPhysicals.back();\n\t\t\tfirstRun = false;\n\t\t} else {\n\t\t\t*T = ConnectedPhysical(std::move(*P),\n\t\t\t\t\t\t\t\t   S,\n\t\t\t\t\t\t\t\t   std::move(*OS).connectionToParent.inverted());\n\t\t}\n\n\t\t// at this point, P::Physical is no longer valid, but the ConnectedPhysical's fields can still be used\n\n\t\tS = T;\n\t\tT = OS;\n\n\t\tif(!PIsMain) {\n\t\t\tConnectedPhysical* OP = static_cast<ConnectedPhysical*>(P);\n\t\t\tOS = OP;\n\t\t\tP = OP->parent;\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t}\n\tS->childPhysicals.remove(std::move(*T)); // remove the last trash Physical\n\n\t*P = std::move(newTop);\n\n\tMotorizedPhysical* OP = static_cast<MotorizedPhysical*>(P);\n\tOP->refreshPhysicalProperties();\n}\n\nstd::size_t ConnectedPhysical::getIndexInParent() const {\n\treturn &this->parent->childPhysicals[0] - this;\n}\n\nRelativeMotion ConnectedPhysical::getRelativeMotionBetweenParentAndSelf() const {\n\treturn connectionToParent.getRelativeMotion();\n}\n\nbool Physical::isMainPhysical() const {\n\tPhysical* ptr = mainPhysical;\n\treturn ptr == this;\n}\n\nMotorizedPhysical* Physical::makeMainPhysical() {\n\tif(this->isMainPhysical()) {\n\t\treturn static_cast<MotorizedPhysical*>(this);\n\t} else {\n\t\tMotorizedPhysical* main = this->mainPhysical;\n\t\tstatic_cast<ConnectedPhysical*>(this)->makeMainPhysical();\n\t\treturn main;\n\t}\n}\n\nvoid Physical::removeChild(ConnectedPhysical* child) {\n\tassert(liesInVector(this->childPhysicals, child));\n\n\t*child = std::move(childPhysicals.back());\n\tchildPhysicals.pop_back();\n}\n\nvoid Physical::attachPhysical(Physical* phys, HardConstraint* constraint, const CFrame& attachToThis, const CFrame& attachToThat) {\n\tif(this->mainPhysical == phys->mainPhysical) {\n\t\tthrow std::invalid_argument(\"Attempting to create HardConstraint loop\");\n\t}\n\tthis->attachPhysical(phys->makeMainPhysical(), constraint, attachToThis, attachToThat);\n}\n\nstatic void removePhysicalFromList(std::vector<MotorizedPhysical*>& physicals, MotorizedPhysical* physToRemove) {\n\tfor(MotorizedPhysical*& item : physicals) {\n\t\tif(item == physToRemove) {\n\t\t\titem = std::move(physicals.back());\n\t\t\tphysicals.pop_back();\n\t\t\treturn;\n\t\t}\n\t}\n\tunreachable(); // No physical found to remove!\n}\n\nvoid Physical::attachPhysical(MotorizedPhysical* phys, HardConstraint* constraint, const CFrame& attachToThis, const CFrame& attachToThat) {\n\tWorldPrototype* world = this->getWorld();\n\tif(world != nullptr) {\n\t\tif(mainPhysical->getWorld() != nullptr) {\n\t\t\tassert(mainPhysical->getWorld() == world);\n\t\t\tremovePhysicalFromList(world->physicals, mainPhysical);\n\t\t}\n\t}\n\n\tConnectedPhysical childToAdd(std::move(*phys), this, constraint, attachToThat, attachToThis);\n\tchildPhysicals.push_back(std::move(childToAdd));\n\tConnectedPhysical& p = childPhysicals.back();\n\n\tp.parent = this;\n\tp.setMainPhysicalRecursive(this->mainPhysical);\n\n\tdelete phys;\n\n\tchildPhysicals.back().refreshCFrameRecursive();\n\n\tmainPhysical->refreshPhysicalProperties();\n}\n\nvoid Physical::attachPart(Part* part, HardConstraint* constraint, const CFrame& attachToThis, const CFrame& attachToThat) {\n\tPhysical* partPhys = part->getPhysical();\n\tif(partPhys) {\n\t\tattachPhysical(partPhys, constraint, attachToThis, part->transformCFrameToParent(attachToThat));\n\t} else {\n\t\tWorldPrototype* world = this->getWorld();\n\t\tif(world != nullptr) {\n\t\t\tworld->onPartAdded(part);\n\t\t}\n\t\tchildPhysicals.push_back(ConnectedPhysical(Physical(part, this->mainPhysical), this, constraint, attachToThat, attachToThis));\n\t\tchildPhysicals.back().refreshCFrame();\n\t}\n\n\tmainPhysical->refreshPhysicalProperties();\n}\n\n\nstatic Physical* findPhysicalParent(Physical* findIn, const ConnectedPhysical* toBeFound) {\n\tif(liesInVector(findIn->childPhysicals, toBeFound)) {\n\t\treturn findIn;\n\t}\n\tfor(ConnectedPhysical& p : findIn->childPhysicals) {\n\t\tPhysical* result = findPhysicalParent(&p, toBeFound);\n\t\tif(result != nullptr) {\n\t\t\treturn result;\n\t\t}\n\t}\n\treturn nullptr;\n}\n\nvoid Physical::attachPhysical(Physical* phys, const CFrame& attachment) {\n\tattachPhysical(phys->makeMainPhysical(), attachment);\n}\n\nvoid Physical::attachPhysical(MotorizedPhysical* phys, const CFrame& attachment) {\n\tthis->childPhysicals.reserve(this->childPhysicals.size() + phys->childPhysicals.size());\n\n\tphys->rigidBody.mainPart->setRigidBodyPhysical(this);\n\tthis->rigidBody.attach(std::move(phys->rigidBody), attachment);\n\t\n\n\tfor(ConnectedPhysical& conPhys : phys->childPhysicals) {\n\t\tthis->childPhysicals.push_back(std::move(conPhys));\n\t\tConnectedPhysical& conPhysOnThis = this->childPhysicals.back();\n\t\tconPhysOnThis.connectionToParent.attachOnParent = attachment.localToGlobal(conPhysOnThis.connectionToParent.attachOnParent);\n\t\tconPhysOnThis.parent = this;\n\t\tconPhysOnThis.setMainPhysicalRecursive(this->mainPhysical);\n\t\tconPhysOnThis.refreshCFrameRecursive();\n\t}\n\n\tWorldPrototype* world = this->getWorld();\n\tif(world != nullptr) {\n\t\tif(phys->getWorld() != nullptr) {\n\t\t\tassert(phys->getWorld() == world);\n\t\t\tremovePhysicalFromList(world->physicals, phys->mainPhysical);\n\t\t}\n\t}\n\n\tdelete phys;\n\n\tmainPhysical->refreshPhysicalProperties();\n}\n\nvoid Physical::attachPart(Part* part, const CFrame& attachment) {\n\tPhysical* partPhys = part->getPhysical();\n\tif(partPhys != nullptr) { // part is already in a physical\n\t\tif(partPhys->mainPhysical == this->mainPhysical) {\n\t\t\tthrow std::invalid_argument(\"Part already attached to this physical!\");\n\t\t}\n\n\t\t// attach other part's entire physical\n\t\tif(part->isMainPart()) {\n\t\t\tattachPhysical(partPhys, attachment);\n\t\t} else {\n\t\t\tCFrame newAttach = attachment.localToGlobal(~part->getAttachToMainPart());\n\t\t\tattachPhysical(partPhys, newAttach);\n\t\t}\n\t} else {\n\t\tWorldPrototype* world = this->getWorld();\n\t\tif(world != nullptr) {\n\t\t\tworld->onPartAdded(part);\n\t\t}\n\t\tpart->parent = this;\n\t\trigidBody.attach(part, attachment);\n\t}\n\tthis->mainPhysical->refreshPhysicalProperties();\n}\n\nvoid Physical::detachAllChildPhysicals() {\n\tWorldPrototype* world = this->getWorld();\n\tfor(ConnectedPhysical& child : childPhysicals) {\n\t\tMotorizedPhysical* newPhys = new MotorizedPhysical(std::move(static_cast<Physical&>(child)));\n\t\t\n\t\tif(world != nullptr) {\n\t\t\tworld->notifyPhysicalHasBeenSplit(this->mainPhysical, newPhys);\n\t\t}\n\t}\n\n\tchildPhysicals.clear(); // calls the destructors on all (now invalid) children, deleting the constraints in the process\n}\n\nvoid Physical::detachFromRigidBody(Part* part) {\n\tpart->parent = nullptr;\n\trigidBody.detach(part);\n\tWorldPrototype* world = this->getWorld();\n\t// TODO?\n}\n\nvoid Physical::detachFromRigidBody(AttachedPart&& part) {\n\tpart.part->parent = nullptr;\n\trigidBody.detach(std::move(part));\n}\n\nstatic void computeInternalRelativeMotionTree(MonotonicTreeBuilder<RelativeMotion>& builder, MonotonicTreeNode<RelativeMotion>& curNode, const ConnectedPhysical& conPhys, const RelativeMotion& motionOfParent) {\n\tRelativeMotion motionOfSelf = motionOfParent + conPhys.getRelativeMotionBetweenParentAndSelf();\n\n\tcurNode.value = motionOfSelf.extendEnd(conPhys.rigidBody.localCenterOfMass);\n\n\tstd::size_t size = conPhys.childPhysicals.size();\n\t\n\tif(size == 0) {\n\t\tcurNode.children = nullptr;\n\t} else { \n\t\tcurNode.children = builder.alloc(size);\n\t\tfor(std::size_t i = 0; i < size; i++) {\n\t\t\tcomputeInternalRelativeMotionTree(builder, curNode.children[i], conPhys.childPhysicals[i], motionOfSelf);\n\t\t}\n\t}\n}\n\nInternalMotionTree MotorizedPhysical::getInternalRelativeMotionTree(UnmanagedArray<MonotonicTreeNode<RelativeMotion>>&& mem) const noexcept {\n\tMonotonicTreeBuilder<RelativeMotion> builder(std::move(mem));\n\n\tstd::size_t mainSize = this->childPhysicals.size();\n\n\tMonotonicTreeNode<RelativeMotion>* childNodes = builder.alloc(mainSize);\n\tfor(std::size_t i = 0; i < mainSize; i++) {\n\t\tMonotonicTreeNode<RelativeMotion>& curNode = childNodes[i];\n\t\tconst ConnectedPhysical& conPhys = this->childPhysicals[i];\n\t\tRelativeMotion motionOfPrimallyAttached = conPhys.getRelativeMotionBetweenParentAndSelf();\n\n\t\tcurNode.value = motionOfPrimallyAttached.extendEnd(conPhys.rigidBody.localCenterOfMass);\n\n\t\tstd::size_t size = conPhys.childPhysicals.size();\n\n\t\tif(size == 0) {\n\t\t\tcurNode.children = nullptr;\n\t\t} else {\n\t\t\tcurNode.children = builder.alloc(size);\n\t\t\tfor(std::size_t j = 0; j < size; j++) {\n\t\t\t\tcomputeInternalRelativeMotionTree(builder, curNode.children[j], conPhys.childPhysicals[j], motionOfPrimallyAttached);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn InternalMotionTree(this, MonotonicTree<RelativeMotion>(std::move(builder)));\n}\n\nCOMMotionTree MotorizedPhysical::getCOMMotionTree(UnmanagedArray<MonotonicTreeNode<RelativeMotion>>&& mem) const noexcept {\n\treturn this->getInternalRelativeMotionTree(std::move(mem)).normalizeCenterOfMass();\n}\n\nvoid Physical::detachPartAssumingMultipleParts(Part* part) {\n\tassert(part->getPhysical() == this);\n\tassert(rigidBody.getPartCount() > 1);\n\n\tif(part == rigidBody.getMainPart()) {\n\t\tAttachedPart& newMainPartAndLaterOldPart = rigidBody.parts.back();\n\t\tmakeMainPart(newMainPartAndLaterOldPart); // now points to old part\n\t\tdetachFromRigidBody(std::move(newMainPartAndLaterOldPart));\n\t} else {\n\t\tdetachFromRigidBody(part);\n\t}\n\n\tthis->mainPhysical->refreshPhysicalProperties();\n}\n\nvoid Physical::detachPart(Part* part) {\n\tassert(part->getPhysical() == this);\n\n\tWorldPrototype* world = this->getWorld();\n\n\tif(rigidBody.getPartCount() == 1) {\n\t\tassert(part == rigidBody.getMainPart());\n\n\t\t// we have to disconnect this from other physicals as we're detaching the last part in the physical\n\n\t\tthis->detachAllChildPhysicals();\n\t\tMotorizedPhysical* mainPhys = this->mainPhysical; // save main physical because it'll get deleted by parent->detachChild()\n\t\tif(this != mainPhys) {\n\t\t\tConnectedPhysical& self = static_cast<ConnectedPhysical&>(*this);\n\t\t\tMotorizedPhysical* newPhys = new MotorizedPhysical(std::move(static_cast<Physical&>(self)));\n\t\t\tif(world != nullptr) {\n\t\t\t\tworld->notifyPhysicalHasBeenSplit(mainPhys, newPhys);\n\t\t\t}\n\t\t\tself.parent->childPhysicals.remove(std::move(self)); // double move, but okay, since remove really only needs the address of self\n\t\t\tmainPhys->refreshPhysicalProperties();\n\t\t}\n\n\t\t// After this, self, and hence also *this* is no longer valid!\n\t\t// It has been removed\n\t} else {\n\t\tdetachPartAssumingMultipleParts(part);\n\t\tMotorizedPhysical* newPhys = new MotorizedPhysical(part);\n\t\tpart->parent = newPhys;\n\t\tif(world != nullptr) {\n\t\t\tworld->physicals.push_back(newPhys);\n\t\t}\n\t}\n}\n\nvoid Physical::removePart(Part* part) {\n\tassert(part->getPhysical() == this);\n\n\tif(rigidBody.getPartCount() == 1) {\n\t\tassert(part == rigidBody.getMainPart());\n\n\t\t// we have to disconnect this from other physicals as we're removing the last part in the physical\n\n\t\tthis->detachAllChildPhysicals();\n\t\tMotorizedPhysical* mainPhys = this->mainPhysical; // save main physical because it'll get deleted by parent->detachChild()\n\t\tif(this != mainPhys) {\n\t\t\tConnectedPhysical& self = static_cast<ConnectedPhysical&>(*this);\n\t\t\tself.parent->childPhysicals.remove(std::move(self));\n\t\t\tmainPhys->refreshPhysicalProperties();\n\t\t} else {\n\t\t\tWorldPrototype* mainPhysWorld = this->getWorld();\n\t\t\tif(mainPhysWorld != nullptr) {\n\t\t\t\tremovePhysicalFromList(mainPhysWorld->physicals, mainPhys);\n\t\t\t}\n\t\t\tdelete mainPhys;\n\t\t}\n\n\t\t// After this, self, and hence also *this* is no longer valid!\n\t\t// It has been removed\n\t} else {\n\t\tdetachPartAssumingMultipleParts(part);\n\t}\n\tpart->parent = nullptr;\n}\n\n// TODO: this seems to need to update the encompassing MotorizedPhysical as well\nvoid Physical::notifyPartPropertiesChanged(Part* part) {\n\trigidBody.refreshWithNewParts();\n}\nvoid Physical::notifyPartStdMoved(Part* oldPartPtr, Part* newPartPtr) noexcept {\n\trigidBody.notifyPartStdMoved(oldPartPtr, newPartPtr);\n}\n\nvoid Physical::updateConstraints(double deltaT) {\n\tfor(ConnectedPhysical& p : childPhysicals) {\n\t\tp.connectionToParent.update(deltaT);\n\t\tp.updateConstraints(deltaT);\n\t}\n}\n\nvoid Physical::updateAttachedPhysicals() {\n\tfor(ConnectedPhysical& p : childPhysicals) {\n\t\tp.refreshCFrame();\n\t\tp.updateAttachedPhysicals();\n\t}\n}\n\nvoid Physical::setCFrame(const GlobalCFrame& newCFrame) {\n\tif(this->isMainPhysical()) {\n\t\tMotorizedPhysical* motorThis = static_cast<MotorizedPhysical*>(this);\n\t\tmotorThis->setCFrame(newCFrame);\n\t} else {\n\t\tConnectedPhysical* connectedThis = static_cast<ConnectedPhysical*>(this);\n\t\tconnectedThis->setCFrame(newCFrame);\n\t}\n}\n\nvoid ConnectedPhysical::setCFrame(const GlobalCFrame& newCFrame) {\n\tCFrame relativeCFrameToParent = this->getRelativeCFrameToParent();\n\n\tGlobalCFrame resultingCFrame = newCFrame.localToGlobal(~relativeCFrameToParent);\n\n\tthis->parent->setCFrame(resultingCFrame);\n}\n\nvoid MotorizedPhysical::setCFrame(const GlobalCFrame& newCFrame) {\n\trigidBody.setCFrame(newCFrame);\n\tfor(ConnectedPhysical& conPhys : childPhysicals) {\n\t\tconPhys.refreshCFrameRecursive();\n\t}\n}\n\nvoid Physical::setPartCFrame(Part* part, const GlobalCFrame& newCFrame) {\n\tif(part == rigidBody.mainPart) {\n\t\tsetCFrame(newCFrame);\n\t} else {\n\t\tCFrame attach = rigidBody.getAttachFor(part).attachment;\n\t\tGlobalCFrame newMainCFrame = newCFrame.localToGlobal(~attach);\n\n\t\tsetCFrame(newMainCFrame);\n\t}\n}\n\n#pragma endregion\n\n/*\n\t===== Refresh functions =====\n*/\n\n#pragma region refresh\n\nvoid MotorizedPhysical::rotateAroundCenterOfMass(const Rotation& rotation) {\n\trigidBody.rotateAroundLocalPoint(totalCenterOfMass, rotation);\n}\nvoid Physical::translateUnsafeRecursive(const Vec3Fix& translation) {\n\trigidBody.translate(translation);\n\tfor(ConnectedPhysical& conPhys : childPhysicals) {\n\t\tconPhys.translateUnsafeRecursive(translation);\n\t}\n}\nvoid MotorizedPhysical::translate(const Vec3& translation) {\n\ttranslateUnsafeRecursive(translation);\n}\n\nvoid MotorizedPhysical::refreshPhysicalProperties() {\n\tALLOCA_COMMotionTree(cache, this, size);\n\n\tthis->totalCenterOfMass = cache.centerOfMass;\n\tthis->totalMass = cache.totalMass;\n\n\tSymmetricMat3 totalInertia = cache.getInertia();\n\n\tthis->forceResponse = SymmetricMat3::IDENTITY() * (1 / cache.totalMass);\n\tthis->momentResponse = ~totalInertia;\n}\n\nvoid ConnectedPhysical::refreshCFrame() {\n\tGlobalCFrame newPosition = parent->getCFrame().localToGlobal(getRelativeCFrameToParent());\n\trigidBody.setCFrame(newPosition);\n}\n\nvoid ConnectedPhysical::refreshCFrameRecursive() {\n\tthis->refreshCFrame();\n\tfor(ConnectedPhysical& childPhys : childPhysicals) {\n\t\tchildPhys.refreshCFrameRecursive();\n\t}\n}\n\nvoid MotorizedPhysical::fullRefreshOfConnectedPhysicals() {\n\tfor(ConnectedPhysical& conPhys : childPhysicals) {\n\t\tconPhys.refreshCFrameRecursive();\n\t}\n}\n\n#pragma endregion\n\n/*\n\t===== Update =====\n*/\n\n#pragma region update\n\nvoid MotorizedPhysical::update(double deltaT) {\n\n\tVec3 accel = forceResponse * totalForce * deltaT;\n\t\n\tVec3 localMoment = getCFrame().relativeToLocal(totalMoment);\n\tVec3 localRotAcc = momentResponse * localMoment * deltaT;\n\tVec3 rotAcc = getCFrame().localToRelative(localRotAcc);\n\n\ttotalForce = Vec3();\n\ttotalMoment = Vec3();\n\n\tmotionOfCenterOfMass.translation.translation[0] += accel;\n\tmotionOfCenterOfMass.rotation.rotation[0] += rotAcc;\n\n\tVec3 oldCenterOfMass = this->totalCenterOfMass;\n\tVec3 angularMomentumBefore = getTotalAngularMomentum();\n\n\tupdateConstraints(deltaT);\n\trefreshPhysicalProperties();\n\n\tVec3 deltaCOM = this->totalCenterOfMass - oldCenterOfMass;\n\tVec3 movementOfCenterOfMass = motionOfCenterOfMass.getVelocity() * deltaT + accel * deltaT * deltaT * 0.5 - getCFrame().localToRelative(deltaCOM);\n\n\trotateAroundCenterOfMass(Rotation::fromRotationVector(motionOfCenterOfMass.getAngularVelocity() * deltaT));\n\ttranslateUnsafeRecursive(movementOfCenterOfMass);\n\n\tVec3 angularMomentumAfter = getTotalAngularMomentum();\n\n\tSymmetricMat3 globalMomentResponse = getCFrame().getRotation().localToGlobal(momentResponse);\n\n\tVec3 deltaAngularVelocity = globalMomentResponse * (angularMomentumAfter - angularMomentumBefore);\n\tthis->motionOfCenterOfMass.rotation.rotation[0] -= deltaAngularVelocity;\n\n\tupdateAttachedPhysicals();\n}\n\n#pragma endregion\n\n/*\n\t===== application of forces and the like\n*/\n\n#pragma region apply\n\nvoid MotorizedPhysical::applyForceAtCenterOfMass(Vec3 force) {\n\tassert(isVecValid(force));\n\ttotalForce += force;\n\n\tDebug::logVector(getCenterOfMass(), force, Debug::FORCE);\n}\n\nvoid MotorizedPhysical::applyForce(Vec3Relative origin, Vec3 force) {\n\tassert(isVecValid(origin));\n\tassert(isVecValid(force));\n\ttotalForce += force;\n\n\tDebug::logVector(getCenterOfMass() + origin, force, Debug::FORCE);\n\n\tapplyMoment(origin % force);\n}\n\nvoid MotorizedPhysical::applyMoment(Vec3 moment) {\n\tassert(isVecValid(moment));\n\ttotalMoment += moment;\n\tDebug::logVector(getCenterOfMass(), moment, Debug::MOMENT);\n}\n\nvoid MotorizedPhysical::applyImpulseAtCenterOfMass(Vec3 impulse) {\n\tassert(isVecValid(impulse));\n\tDebug::logVector(getCenterOfMass(), impulse, Debug::IMPULSE);\n\tmotionOfCenterOfMass.translation.translation[0] += forceResponse * impulse;\n}\nvoid MotorizedPhysical::applyImpulse(Vec3Relative origin, Vec3Relative impulse) {\n\tassert(isVecValid(origin));\n\tassert(isVecValid(impulse));\n\tDebug::logVector(getCenterOfMass() + origin, impulse, Debug::IMPULSE);\n\tmotionOfCenterOfMass.translation.translation[0] += forceResponse * impulse;\n\tVec3 angularImpulse = origin % impulse;\n\tapplyAngularImpulse(angularImpulse);\n}\nvoid MotorizedPhysical::applyAngularImpulse(Vec3 angularImpulse) {\n\tassert(isVecValid(angularImpulse));\n\tDebug::logVector(getCenterOfMass(), angularImpulse, Debug::ANGULAR_IMPULSE);\n\tVec3 localAngularImpulse = getCFrame().relativeToLocal(angularImpulse);\n\tVec3 localRotAcc = momentResponse * localAngularImpulse;\n\tVec3 rotAcc = getCFrame().localToRelative(localRotAcc);\n\tmotionOfCenterOfMass.rotation.rotation[0] += rotAcc;\n}\n\nvoid MotorizedPhysical::applyDragAtCenterOfMass(Vec3 drag) {\n\tassert(isVecValid(drag));\n\tDebug::logVector(getCenterOfMass(), drag, Debug::POSITION);\n\ttranslate(forceResponse * drag);\n}\nvoid MotorizedPhysical::applyDrag(Vec3Relative origin, Vec3Relative drag) {\n\tassert(isVecValid(origin));\n\tassert(isVecValid(drag));\n\tDebug::logVector(getCenterOfMass() + origin, drag, Debug::POSITION);\n\ttranslateUnsafeRecursive(forceResponse * drag);\n\tVec3 angularDrag = origin % drag;\n\tapplyAngularDrag(angularDrag);\n}\nvoid MotorizedPhysical::applyAngularDrag(Vec3 angularDrag) {\n\tassert(isVecValid(angularDrag));\n\tDebug::logVector(getCenterOfMass(), angularDrag, Debug::INFO_VEC);\n\tVec3 localAngularDrag = getCFrame().relativeToLocal(angularDrag);\n\tVec3 localRotAcc = momentResponse * localAngularDrag;\n\tVec3 rotAcc = getCFrame().localToRelative(localRotAcc);\n\trotateAroundCenterOfMass(Rotation::fromRotationVector(rotAcc));\n}\n\n\nvoid Physical::applyDragToPhysical(Vec3 origin, Vec3 drag) {\n\tVec3 COMOffset = mainPhysical->getCenterOfMass() - getCFrame().getPosition();\n\tmainPhysical->applyDrag(origin + COMOffset, drag);\n}\nvoid Physical::applyImpulseToPhysical(Vec3 origin, Vec3 impulse) {\n\tVec3 COMOffset = mainPhysical->getCenterOfMass() - getCFrame().getPosition();\n\tmainPhysical->applyImpulse(origin + COMOffset, impulse);\n}\nvoid Physical::applyForceToPhysical(Vec3 origin, Vec3 force) {\n\tVec3 COMOffset = mainPhysical->getCenterOfMass() - getCFrame().getPosition();\n\tmainPhysical->applyForce(origin + COMOffset, force);\n}\n\n#pragma endregion\n\n#pragma region getters\n\nWorldPrototype* Physical::getWorld() const {\n\treturn this->rigidBody.mainPart->getWorld();\n}\n\ndouble Physical::getVelocityKineticEnergy() const {\n\treturn rigidBody.mass * lengthSquared(getMotionOfCenterOfMass().getVelocity()) / 2;\n}\ndouble Physical::getAngularKineticEnergy() const {\n\tVec3 localAngularVel = getCFrame().relativeToLocal(getMotionOfCenterOfMass().getAngularVelocity());\n\treturn (rigidBody.inertia * localAngularVel) * localAngularVel / 2;\n}\ndouble Physical::getKineticEnergy() const {\n\treturn getVelocityKineticEnergy() + getAngularKineticEnergy();\n}\nCFrame Physical::getRelativeCFrameToMain() const {\n\treturn mainPhysical->getCFrame().globalToLocal(this->getCFrame());\n}\nVec3 Physical::localToMain(const Vec3Local& vec) const {\n\tPosition globalPos = this->getCFrame().localToGlobal(vec);\n\treturn mainPhysical->getCFrame().globalToLocal(globalPos);\n}\nVec3 Physical::localToMainCOMRelative(const Vec3Local& vec) const {\n\tPosition globalPos = this->getCFrame().localToGlobal(vec);\n\treturn mainPhysical->getCFrame().globalToRelative(globalPos) - mainPhysical->totalCenterOfMass;\n}\n\n/*Motion MotorizedPhysical::getMotionOfCenterOfMass() const {\n\treturn this->motionOfCenterOfMass;\n}*/\n\nVec3 MotorizedPhysical::getVelocityOfCenterOfMass() const {\n\treturn this->motionOfCenterOfMass.getVelocity();\n}\n\n/*\n\tComputes the force->acceleration transformation matrix\n\tSuch that:\n\ta = M*F\n*/\nSymmetricMat3 MotorizedPhysical::getResponseMatrix(const Vec3Local& r) const {\n\tMat3 crossMat = createCrossProductEquivalent(r);\n\n\tSymmetricMat3 rotationFactor = multiplyLeftRight(momentResponse , crossMat);\n\n\treturn forceResponse + rotationFactor;\n}\n\nMat3 MotorizedPhysical::getResponseMatrix(const Vec3Local& actionPoint, const Vec3Local& responsePoint) const {\n\tMat3 actionCross = createCrossProductEquivalent(actionPoint);\n\tMat3 responseCross = createCrossProductEquivalent(responsePoint);\n\n\tMat3 rotationFactor = responseCross * momentResponse * actionCross;\n\n\treturn Mat3(forceResponse) - rotationFactor;\n}\ndouble MotorizedPhysical::getInertiaOfPointInDirectionLocal(const Vec3Local& localPoint, const Vec3Local& localDirection) const {\n\tSymmetricMat3 accMat = getResponseMatrix(localPoint);\n\n\tVec3 force = localDirection;\n\tVec3 accel = accMat * force;\n\tdouble accelInForceDir = accel * localDirection / lengthSquared(localDirection);\n\n\treturn 1 / accelInForceDir;\n\n\t/*SymmetricMat3 accelToForceMat = ~accMat;\n\tVec3 imaginaryForceForAcceleration = accelToForceMat * direction;\n\tdouble forcePerAccelRatio = imaginaryForceForAcceleration * direction / direction.lengthSquared();\n\treturn forcePerAccelRatio;*/\n}\n\ndouble MotorizedPhysical::getInertiaOfPointInDirectionRelative(const Vec3Relative& relPoint, const Vec3Relative& relDirection) const {\n\treturn getInertiaOfPointInDirectionLocal(getCFrame().relativeToLocal(relPoint), getCFrame().relativeToLocal(relDirection));\n}\n\nCFrame ConnectedPhysical::getRelativeCFrameToParent() const {\n\treturn connectionToParent.getRelativeCFrameToParent();\n}\n\nPosition MotorizedPhysical::getCenterOfMass() const {\n\treturn getCFrame().localToGlobal(totalCenterOfMass);\n}\n\nGlobalCFrame MotorizedPhysical::getCenterOfMassCFrame() const {\n\treturn GlobalCFrame(getCFrame().localToGlobal(totalCenterOfMass), getCFrame().getRotation());\n}\n\nVec3 MotorizedPhysical::getTotalImpulse() const {\n\treturn this->motionOfCenterOfMass.getVelocity() * this->totalMass;\n}\n\nVec3 MotorizedPhysical::getTotalAngularMomentum() const {\n\tRotation selfRot = this->getCFrame().getRotation();\n\n\tALLOCA_COMMotionTree(cache, this, size);\n\n\tSymmetricMat3 totalInertia = selfRot.localToGlobal(cache.getInertia());\n\tVec3 localInternalAngularMomentum = cache.getInternalAngularMomentum();\n\tVec3 globalInternalAngularMomentum = selfRot.localToGlobal(localInternalAngularMomentum);\n\t\n\tVec3 externalAngularMomentum = totalInertia * this->motionOfCenterOfMass.getAngularVelocity();\n\n\treturn externalAngularMomentum + globalInternalAngularMomentum;\n}\n\nMotion Physical::getMotion() const {\n\tif(this->isMainPhysical()) {\n\t\treturn ((MotorizedPhysical*) this)->getMotion();\n\t} else {\n\t\treturn ((ConnectedPhysical*) this)->getMotion();\n\t}\n}\n\nMotion MotorizedPhysical::getMotion() const {\n\tALLOCA_COMMotionTree(cache, this, size);\n\n\tGlobalCFrame cf = this->getCFrame();\n\tTranslationalMotion motionOfCom = localToGlobal(cf.getRotation(), cache.motionOfCenterOfMass);\n\n\treturn -motionOfCom + motionOfCenterOfMass.getMotionOfPoint(cf.localToRelative(-cache.centerOfMass));\n}\nMotion ConnectedPhysical::getMotion() const {\n\t// All motion and offset variables here are expressed in the global frame\n\n\tMotion parentMotion = parent->getMotion();\n\n\tRelativeMotion motionBetweenParentAndChild = connectionToParent.getRelativeMotion();\n\n\tRelativeMotion inGlobalFrame = motionBetweenParentAndChild.extendBegin(CFrame(parent->getCFrame().getRotation()));\n\n\tMotion result = inGlobalFrame.applyTo(parentMotion);\n\n\treturn result;\n}\n\nMotion Physical::getMotionOfCenterOfMass() const {\n\treturn this->getMotion().getMotionOfPoint(this->getCFrame().localToRelative(this->rigidBody.localCenterOfMass));\n}\nMotion MotorizedPhysical::getMotionOfCenterOfMass() const {\n\treturn this->motionOfCenterOfMass;\n}\nMotion ConnectedPhysical::getMotionOfCenterOfMass() const {\n\treturn this->getMotion().getMotionOfPoint(this->getCFrame().localToRelative(this->rigidBody.localCenterOfMass));\n}\n\nsize_t Physical::getNumberOfPhysicalsInThisAndChildren() const {\n\tsize_t totalPhysicals = 1;\n\tfor(const ConnectedPhysical& child : childPhysicals) {\n\t\ttotalPhysicals += child.getNumberOfPhysicalsInThisAndChildren();\n\t}\n\treturn totalPhysicals;\n}\n\nsize_t Physical::getNumberOfPartsInThisAndChildren() const {\n\tsize_t totalParts = rigidBody.getPartCount();\n\tfor(const ConnectedPhysical& child : childPhysicals) {\n\t\ttotalParts += child.getNumberOfPartsInThisAndChildren();\n\t}\n\treturn totalParts;\n}\n\nvoid Physical::setMainPhysicalRecursive(MotorizedPhysical* newMainPhysical) {\n\tthis->mainPhysical = newMainPhysical;\n\tfor(ConnectedPhysical& child : childPhysicals) {\n\t\tchild.setMainPhysicalRecursive(newMainPhysical);\n\t}\n}\n\nstd::tuple<double, Vec3, TranslationalMotion> InternalMotionTree::getInternalMotionOfCenterOfMass() const {\n\tTranslationalMotion totalMotion(Vec3(0.0, 0.0, 0.0), Vec3(0.0, 0.0, 0.0));\n\tVec3 totalCenterOfMass = this->motorPhys->rigidBody.localCenterOfMass * motorPhys->rigidBody.mass;\n\tdouble totalMass = motorPhys->rigidBody.mass;\n\tmotorPhys->mutuallyRecurse(relativeMotionTree, [&totalMass, &totalCenterOfMass, &totalMotion](const MonotonicTreeNode<RelativeMotion>& node, const ConnectedPhysical& conPhys) {\n\t\tdouble mass = conPhys.rigidBody.mass;\n\t\ttotalMotion += node.value.relativeMotion.translation * mass;\n\t\ttotalCenterOfMass += node.value.locationOfRelativeMotion.getPosition() * mass;\n\t\ttotalMass += mass;\n\t});\n\n\ttotalCenterOfMass *= (1 / totalMass);\n\ttotalMotion *= (1 / totalMass);\n\n\treturn std::make_tuple(totalMass, totalCenterOfMass, totalMotion);\n}\n\nCOMMotionTree InternalMotionTree::normalizeCenterOfMass() && {\n\tstd::tuple<double, Vec3, TranslationalMotion> m = this->getInternalMotionOfCenterOfMass();\n\n\tfor(MonotonicTreeNode<RelativeMotion>& elem : relativeMotionTree) {\n\t\telem.value.locationOfRelativeMotion -= std::get<1>(m);\n\t\telem.value.relativeMotion.translation -= std::get<2>(m);\n\t}\n\n\treturn COMMotionTree(this->motorPhys, std::move(this->relativeMotionTree), std::get<0>(m), std::get<1>(m), std::get<2>(m));\n}\n\nSymmetricMat3 COMMotionTree::getInertia() const {\n\tSymmetricMat3 totalInertia = getTranslatedInertiaAroundCenterOfMass(motorPhys->rigidBody.inertia, motorPhys->rigidBody.mass, this->mainCOMOffset);\n\tmotorPhys->mutuallyRecurse(relativeMotionTree, [&totalInertia](const MonotonicTreeNode<RelativeMotion>& node, const ConnectedPhysical& conPhys) {\n\t\ttotalInertia += getTransformedInertiaAroundCenterOfMass(conPhys.rigidBody.inertia, conPhys.rigidBody.mass, node.value.locationOfRelativeMotion);\n\t});\n\n\treturn totalInertia;\n}\n\nFullTaylor<SymmetricMat3> COMMotionTree::getInertiaDerivatives() const {\n\tFullTaylor<SymmetricMat3> totalInertia = getTranslatedInertiaDerivativesAroundCenterOfMass(motorPhys->rigidBody.inertia, motorPhys->rigidBody.mass, this->mainCOMOffset, -this->motionOfCenterOfMass);\n\tmotorPhys->mutuallyRecurse(relativeMotionTree, [&totalInertia](const MonotonicTreeNode<RelativeMotion>& node, const ConnectedPhysical& conPhys) {\n\t\ttotalInertia += getTransformedInertiaDerivativesAroundCenterOfMass(conPhys.rigidBody.inertia, conPhys.rigidBody.mass, node.value.locationOfRelativeMotion, node.value.relativeMotion);\n\t});\n\n\treturn totalInertia;\n}\n\nMotion COMMotionTree::getMotion() const {\n\tGlobalCFrame cf = this->motorPhys->getCFrame();\n\tTranslationalMotion motionOfCom = localToGlobal(cf.getRotation(), this->motionOfCenterOfMass);\n\n\treturn -motionOfCom + this->motorPhys->motionOfCenterOfMass.getMotionOfPoint(cf.localToRelative(-this->centerOfMass));\n}\n\nVec3 COMMotionTree::getInternalAngularMomentum() const {\n\tVec3 velocityOfMain = -motionOfCenterOfMass.getVelocity();\n\tVec3 totalAngularMomentum = getAngularMomentumFromOffsetOnlyVelocity(this->mainCOMOffset, velocityOfMain, motorPhys->rigidBody.mass);\n\n\tmotorPhys->mutuallyRecurse(relativeMotionTree, [&totalAngularMomentum](const MonotonicTreeNode<RelativeMotion>& node, const ConnectedPhysical& conPhys) {\n\t\tconst RelativeMotion& relMotion = node.value;\n\t\tSymmetricMat3 relativeInertia = relMotion.locationOfRelativeMotion.getRotation().localToGlobal(conPhys.rigidBody.inertia);\n\n\t\ttotalAngularMomentum += getAngularMomentumFromOffset(\n\t\t\trelMotion.locationOfRelativeMotion.getPosition(),\n\t\t\trelMotion.relativeMotion.getVelocity(),\n\t\t\trelMotion.relativeMotion.getAngularVelocity(),\n\t\t\trelativeInertia,\n\t\t\tconPhys.rigidBody.mass);\n\t});\n\n\treturn totalAngularMomentum;\n}\n\n#pragma endregion\n\n#pragma region isValid\n\nbool Physical::isValid() const {\n\tassert(rigidBody.isValid());\n\n\tfor(const ConnectedPhysical& p : childPhysicals) {\n\t\tassert(p.isValid());\n\t\tassert(p.parent == this);\n\t}\n\n\treturn true;\n}\nbool MotorizedPhysical::isValid() const {\n\tassert(Physical::isValid());\n\t\n\tassert(isVecValid(totalForce));\n\tassert(isVecValid(totalMoment));\n\tassert(std::isfinite(totalMass));\n\tassert(isVecValid(totalCenterOfMass));\n\tassert(isMatValid(forceResponse));\n\tassert(isMatValid(momentResponse));\n\n\treturn true;\n}\n\nbool ConnectedPhysical::isValid() const {\n\tassert(Physical::isValid());\n\n\tassert(isCFrameValid(connectionToParent.attachOnParent));\n\tassert(isCFrameValid(connectionToParent.attachOnChild));\n\n\treturn true;\n}\n\n#pragma endregion\n\nstd::vector<FoundLayerRepresentative> findAllLayersIn(MotorizedPhysical* phys) {\n\tstd::vector<FoundLayerRepresentative> result;\n\n\tphys->forEachPart([&result](Part& p) {\n\t\tfor(FoundLayerRepresentative& item : result) {\n\t\t\tif(item.layer == p.layer) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tresult.push_back(FoundLayerRepresentative{p.layer, &p});\n\t});\n\n\treturn result;\n}\n\nstd::vector<FoundLayerRepresentative> findAllLayersIn(Part* part) {\n\tif(part->layer != nullptr) {\n\t\tPhysical* partPhys = part->getPhysical();\n\t\tif(partPhys) {\n\t\t\treturn findAllLayersIn(partPhys->mainPhysical);\n\t\t} else {\n\t\t\treturn std::vector<FoundLayerRepresentative>{FoundLayerRepresentative{part->layer, part}};\n\t\t}\n\t} else {\n\t\treturn std::vector<FoundLayerRepresentative>{};\n\t}\n}\n};\n"
  },
  {
    "path": "Physics3D/physical.h",
    "content": "#pragma once\n\n#include \"math/linalg/vec.h\"\n#include \"math/linalg/mat.h\"\n#include \"math/cframe.h\"\n#include \"math/bounds.h\"\n#include \"math/position.h\"\n#include \"math/globalCFrame.h\"\n\n#include \"datastructures/unorderedVector.h\"\n#include \"datastructures/iteratorEnd.h\"\n#include \"datastructures/monotonicTree.h\"\n\n#include \"part.h\"\n#include \"rigidBody.h\"\n#include \"hardconstraints/hardConstraint.h\"\n#include \"hardconstraints/hardPhysicalConnection.h\"\n\n#include <stdint.h>\n\nnamespace P3D {\ntypedef Vec3 Vec3Local;\ntypedef Vec3 Vec3Relative;\n\nclass WorldPrototype;\n\nclass ConnectedPhysical;\nclass MotorizedPhysical;\n\nclass InternalMotionTree;\nclass COMMotionTree;\n\nclass Physical {\n\tvoid makeMainPart(AttachedPart& newMainPart);\nprotected:\n\tvoid updateAttachedPhysicals();\n\tvoid updateConstraints(double deltaT);\n\tvoid translateUnsafeRecursive(const Vec3Fix& translation);\n\n\tvoid setMainPhysicalRecursive(MotorizedPhysical* newMainPhysical);\n\n\t// deletes the given physical\n\tvoid attachPhysical(Physical* phys, const CFrame& attachment);\n\t// deletes the given physical\n\tvoid attachPhysical(MotorizedPhysical* phys, const CFrame& attachment);\n\n\t// deletes the given physical\n\tvoid attachPhysical(Physical* phys, HardConstraint* constraint, const CFrame& attachToThis, const CFrame& attachToThat);\n\n\t// deletes the given physical\n\tvoid attachPhysical(MotorizedPhysical* phys, HardConstraint* constraint, const CFrame& attachToThis, const CFrame& attachToThat);\n\n\tvoid removeChild(ConnectedPhysical* child);\n\tvoid detachFromRigidBody(Part* part);\n\tvoid detachFromRigidBody(AttachedPart&& part);\n\n\tvoid detachPartAssumingMultipleParts(Part* part);\n\n\t// expects a function of type void(const Part&)\n\ttemplate<typename Func>\n\tvoid forEachPartInChildren(const Func& func) const;\n\n\t// expects a function of type void(Part&)\n\ttemplate<typename Func>\n\tvoid forEachPartInChildren(const Func& func);\n\n\t// expects a function of type void(const Part&)\n\ttemplate<typename Func>\n\tvoid forEachPartInThisAndChildren(const Func& func) const;\n\n\t// expects a function of type void(Part&)\n\ttemplate<typename Func>\n\tvoid forEachPartInThisAndChildren(const Func& func);\n\n\t// expects a function of type void(const Physical& parent, const ConnectedPhysical& child)\n\ttemplate<typename Func>\n\tvoid forEachHardConstraintInChildren(const Func& func) const;\n\n\t// expects a function of type void(Physical& parent, ConnectedPhysical& child)\n\ttemplate<typename Func>\n\tvoid forEachHardConstraintInChildren(const Func& func);\n\n\t// expects a predicate of type bool(const Part& p)\n\ttemplate<typename Pred>\n\tconst Part* findFirstInThisAndChildren(const Pred& pred) const;\n\n\t// expects a predicate of type bool(Part& p)\n\ttemplate<typename Pred>\n\tPart* findFirstInThisAndChildren(const Pred& pred);\npublic:\n\tRigidBody rigidBody;\n\n\tMotorizedPhysical* mainPhysical;\n\tUnorderedVector<ConnectedPhysical> childPhysicals;\n\n\tPhysical() = default;\n\tPhysical(Part* mainPart, MotorizedPhysical* mainPhysical);\n\tPhysical(RigidBody&& rigidBody, MotorizedPhysical* mainPhysical);\n\n\tPhysical(Physical&& other) noexcept;\n\tPhysical& operator=(Physical&& other) noexcept;\n\tPhysical(const Physical&) = delete;\n\tvoid operator=(const Physical&) = delete;\n\n\tWorldPrototype* getWorld() const;\n\n\t// expects a function of type void(const Physical& parent, const ConnectedPhysical& child)\n\ttemplate<typename Func>\n\tvoid forEachHardConstraint(const Func& func);\n\n\tvoid setCFrame(const GlobalCFrame& newCFrame);\n\tvoid setPartCFrame(Part* part, const GlobalCFrame& newCFrame);\n\tinline const GlobalCFrame& getCFrame() const { return rigidBody.getCFrame(); }\n\n\tinline Position getPosition() const {\n\t\treturn getCFrame().getPosition();\n\t}\n\n\t/*\n\t\tReturns the motion of this physical positioned at it's getCFrame()\n\n\t\tThe motion is oriented globally\n\t*/\n\tMotion getMotion() const;\n\t/*\n\t\tReturns the motion of this physical positioned at it's center of mass\n\n\t\tThe motion is oriented globally\n\t*/\n\tMotion getMotionOfCenterOfMass() const;\n\n\tdouble getVelocityKineticEnergy() const;\n\tdouble getAngularKineticEnergy() const;\n\tdouble getKineticEnergy() const;\n\n\tvoid applyDragToPhysical(Vec3 origin, Vec3 drag);\n\tvoid applyForceToPhysical(Vec3 origin, Vec3 force);\n\tvoid applyImpulseToPhysical(Vec3 origin, Vec3 impulse);\n\n\tCFrame getRelativeCFrameToMain() const;\n\tVec3 localToMain(const Vec3Local& vec) const;\n\tVec3 localToMainCOMRelative(const Vec3Local& vec) const;\n\n\tvoid makeMainPart(Part* newMainPart);\n\tvoid attachPart(Part* part, const CFrame& attachment);\n\t/*\n\t\tdetaches a part from this Physical\n\t\tLeaves the detached part with a MotorizedPhysical parent in which it is the only part\n\t\tAs opposed to Physical::removePart(Part*)\n\n\t\tthis Physical may no longer be valid after calling detachPart\n\t*/\n\tvoid detachPart(Part* part);\n\t/*\n\t\tremoves a part from this Physical\n\t\tAfter this method: part->hasPhysical() == false\n\t\tAs opposed to Physical::detachPart(Part*)\n\n\t\tthis Physical may no longer be valid after calling removePart\n\t*/\n\tvoid removePart(Part* part);\n\tvoid attachPart(Part* part, HardConstraint* constraint, const CFrame& attachToThis, const CFrame& attachToThat);\n\n\tsize_t getNumberOfPhysicalsInThisAndChildren() const;\n\tsize_t getNumberOfPartsInThisAndChildren() const;\n\n\tvoid notifyPartPropertiesChanged(Part* part);\n\tvoid notifyPartStdMoved(Part* oldPartPtr, Part* newPartPtr) noexcept;\n\n\tbool isValid() const;\n\n\tbool isMainPhysical() const;\n\tMotorizedPhysical* makeMainPhysical();\n\nprivate:\n\tvoid detachAllChildPhysicals();\n};\n\n\nclass ConnectedPhysical : public Physical {\n\tfriend class Physical;\n\tfriend class MotorizedPhysical;\n\n\tvoid refreshCFrame();\n\tvoid refreshCFrameRecursive();\npublic:\n\tHardPhysicalConnection connectionToParent;\n\tPhysical* parent;\n\n\tConnectedPhysical() = default;\n\tConnectedPhysical(RigidBody&& rigidBody, Physical* parent, HardPhysicalConnection&& connectionToParent);\n\tConnectedPhysical(Physical&& phys, Physical* parent, HardPhysicalConnection&& connectionToParent);\n\tConnectedPhysical(Physical&& phys, Physical* parent, HardConstraint* constraintWithParent, const CFrame& attachOnThis, const CFrame& attachOnParent);\n\n\tvoid setCFrame(const GlobalCFrame& newCFrame);\n\tCFrame getRelativeCFrameToParent() const;\n\n\n\t/*\n\t\tReturns the motion of this physical positioned at it's getCFrame()\n\n\t\tThe motion is oriented globally\n\t*/\n\tMotion getMotion() const;\n\t/*\n\t\tReturns the motion of this physical positioned at it's center of mass\n\n\t\tThe motion is oriented globally\n\t*/\n\tMotion getMotionOfCenterOfMass() const;\n\n\t/*\n\t\tMakes this physical the main Physical\n\t*/\n\tvoid makeMainPhysical();\n\n\tstd::size_t getIndexInParent() const;\n\n\tRelativeMotion getRelativeMotionBetweenParentAndSelf() const;\n\n\tbool isValid() const;\n};\n\nclass MotorizedPhysical : public Physical {\n\tfriend class Physical;\n\tfriend class ConnectedPhysical;\npublic:\n\tvoid refreshPhysicalProperties();\n\tVec3 totalForce = Vec3(0.0, 0.0, 0.0);\n\tVec3 totalMoment = Vec3(0.0, 0.0, 0.0);\n\n\tdouble totalMass;\n\tVec3 totalCenterOfMass;\n\n\tSymmetricMat3 forceResponse;\n\tSymmetricMat3 momentResponse;\n\n\tMotion motionOfCenterOfMass;\n\n\texplicit MotorizedPhysical(Part* mainPart);\n\texplicit MotorizedPhysical(RigidBody&& rigidBody);\n\texplicit MotorizedPhysical(Physical&& movedPhys);\n\n\t/*\n\t\tReturns the motion of this physical positioned at it's getCFrame()\n\n\t\tThe motion is oriented globally\n\t*/\n\tMotion getMotion() const;\n\t/*\n\t\tReturns the motion of this physical positioned at it's center of mass\n\n\t\tThe motion is oriented globally\n\t*/\n\tMotion getMotionOfCenterOfMass() const;\n\tVec3 getVelocityOfCenterOfMass() const;\n\n\tPosition getCenterOfMass() const;\n\tGlobalCFrame getCenterOfMassCFrame() const;\n\n\tVec3 getTotalImpulse() const;\n\tVec3 getTotalAngularMomentum() const;\n\n\t// connectedPhysFunc is of the form void(const RelativeMotion& relativeMotionOfThisPhysical, const ConnectedPhysical& currentPhysical)\n\ttemplate<typename T, typename F>\n\tvoid mutuallyRecurse(const MonotonicTree<T>& tree, F connectedPhysFunc) const {\n\t\tstruct NestedRecurse {\n\t\t\tstatic void recurse(const MonotonicTreeNode<T>& currentNode, const Physical& currentPhys, F func) {\n\t\t\t\tstd::size_t childCount = currentPhys.childPhysicals.size();\n\t\t\t\tfor(std::size_t i = 0; i < childCount; i++) {\n\t\t\t\t\tconst ConnectedPhysical& conPhys = currentPhys.childPhysicals[i];\n\t\t\t\t\tMonotonicTreeNode<T>& currentChildNode = currentNode.children[i];\n\t\t\t\t\tfunc(currentChildNode, conPhys);\n\n\t\t\t\t\trecurse(currentChildNode, conPhys, func);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tstd::size_t childCount = this->childPhysicals.size();\n\t\tfor(std::size_t i = 0; i < childCount; i++) {\n\t\t\tconst ConnectedPhysical& conPhys = this->childPhysicals[i];\n\t\t\tconst MonotonicTreeNode<T>& currentChildNode = tree[i];\n\t\t\tconnectedPhysFunc(currentChildNode, conPhys);\n\n\t\t\tNestedRecurse::recurse(currentChildNode, conPhys, connectedPhysFunc);\n\t\t}\n\t}\n\tInternalMotionTree getInternalRelativeMotionTree(UnmanagedArray<MonotonicTreeNode<RelativeMotion>>&& mem) const noexcept;\n\tCOMMotionTree getCOMMotionTree(UnmanagedArray<MonotonicTreeNode<RelativeMotion>>&& mem) const noexcept;\n\n\tvoid update(double deltaT);\n\n\tvoid setCFrame(const GlobalCFrame& newCFrame);\n\n\tvoid translate(const Vec3& translation);\n\tvoid rotateAroundCenterOfMass(const Rotation& rotation);\n\n\tvoid applyForceAtCenterOfMass(Vec3 force);\n\tvoid applyForce(Vec3Relative origin, Vec3 force);\n\tvoid applyMoment(Vec3 moment);\n\tvoid applyImpulseAtCenterOfMass(Vec3 impulse);\n\tvoid applyImpulse(Vec3Relative origin, Vec3Relative impulse);\n\tvoid applyAngularImpulse(Vec3 angularImpulse);\n\tvoid applyDragAtCenterOfMass(Vec3 drag);\n\tvoid applyDrag(Vec3Relative origin, Vec3Relative drag);\n\tvoid applyAngularDrag(Vec3 angularDrag);\n\n\n\tSymmetricMat3 getResponseMatrix(const Vec3Local& localPoint) const;\n\tMat3 getResponseMatrix(const Vec3Local& actionPoint, const Vec3Local& responsePoint) const;\n\tdouble getInertiaOfPointInDirectionLocal(const Vec3Local& localPoint, const Vec3Local& localDirection) const;\n\tdouble getInertiaOfPointInDirectionRelative(const Vec3Relative& relativePoint, const Vec3Relative& relativeDirection) const;\n\tinline Part* getMainPart() { return this->rigidBody.mainPart; }\n\tinline const Part* getMainPart() const { return this->rigidBody.mainPart; }\n\n\tvoid fullRefreshOfConnectedPhysicals();\n\n\tbool isSinglePart() const { return this->childPhysicals.size() == 0 && this->rigidBody.getPartCount() == 1; }\n\n\t// expects a function of type void(const Part&)\n\ttemplate<typename Func>\n\tvoid forEachPart(const Func& func) const { this->forEachPartInThisAndChildren(func); }\n\n\t// expects a function of type void(Part&)\n\ttemplate<typename Func>\n\tvoid forEachPart(const Func& func) { this->forEachPartInThisAndChildren(func); }\n\n\t// expects a function of type void(const Part&)\n\ttemplate<typename Func>\n\tvoid forEachPartExceptMainPart(const Func& func) const {\n\t\tthis->rigidBody.forEachAttachedPart(func);\n\t\tthis->forEachPartInChildren(func);\n\t}\n\n\t// expects a function of type void(Part&)\n\ttemplate<typename Func>\n\tvoid forEachPartExceptMainPart(const Func& func) {\n\t\tthis->rigidBody.forEachAttachedPart(func);\n\t\tthis->forEachPartInChildren(func);\n\t}\n\n\t// expects a function of type void(const Physical& parent, const ConnectedPhysical& child)\n\ttemplate<typename Func>\n\tvoid forEachHardConstraint(const Func& func) const {\n\t\tthis->forEachHardConstraintInChildren(func);\n\t}\n\n\t// expects a function of type void(Physical& parent, ConnectedPhysical& child)\n\ttemplate<typename Func>\n\tvoid forEachHardConstraint(const Func& func) {\n\t\tthis->forEachHardConstraintInChildren(func);\n\t}\n\n\t// expects a predicate of type bool(const Part& p)\n\ttemplate<typename Pred>\n\tconst Part* findFirst(const Pred& pred) const {\n\t\treturn this->findFirstInThisAndChildren(pred);\n\t}\n\n\t// expects a predicate of type bool(Part& p)\n\ttemplate<typename Pred>\n\tPart* findFirst(const Pred& pred) {\n\t\treturn this->findFirstInThisAndChildren(pred);\n\t}\n\n\tbool isValid() const;\n};\n\n// expects a function of type void(const Part&)\ntemplate<typename Func>\nvoid Physical::forEachPartInChildren(const Func& func) const {\n\tfor(const ConnectedPhysical& conPhys : this->childPhysicals) {\n\t\tconPhys.forEachPartInThisAndChildren(func);\n\t}\n}\n\n// expects a function of type void(Part&)\ntemplate<typename Func>\nvoid Physical::forEachPartInChildren(const Func& func) {\n\tfor(ConnectedPhysical& conPhys : this->childPhysicals) {\n\t\tconPhys.forEachPartInThisAndChildren(func);\n\t}\n}\n\n// expects a function of type void(const Part&)\ntemplate<typename Func>\nvoid Physical::forEachPartInThisAndChildren(const Func& func) const {\n\tthis->rigidBody.forEachPart(func);\n\tthis->forEachPartInChildren(func);\n}\n\n// expects a function of type void(Part&)\ntemplate<typename Func>\nvoid Physical::forEachPartInThisAndChildren(const Func& func) {\n\tthis->rigidBody.forEachPart(func);\n\tthis->forEachPartInChildren(func);\n}\n\n// expects a function of type void(const Physical& parent, const ConnectedPhysical& child)\ntemplate<typename Func>\nvoid Physical::forEachHardConstraint(const Func& func) {\n\tif(!this->isMainPhysical()) {\n\t\tConnectedPhysical* conThis = static_cast<ConnectedPhysical*>(this);\n\t\tfunc(*conThis->parent, *conThis);\n\t}\n\n\tfor(ConnectedPhysical& conPhys : this->childPhysicals) {\n\t\tfunc(*this, conPhys);\n\t}\n}\n\n// expects a function of type void(const Physical& parent, const ConnectedPhysical& child)\ntemplate<typename Func>\nvoid Physical::forEachHardConstraintInChildren(const Func& func) const {\n\tfor(const ConnectedPhysical& conPhys : this->childPhysicals) {\n\t\tfunc(*this, conPhys);\n\t\tconPhys.forEachHardConstraintInChildren(func);\n\t}\n}\n\n// expects a function of type void(Physical& parent, ConnectedPhysical& child)\ntemplate<typename Func>\nvoid Physical::forEachHardConstraintInChildren(const Func& func) {\n\tfor(ConnectedPhysical& conPhys : this->childPhysicals) {\n\t\tfunc(*this, conPhys);\n\t\tconPhys.forEachHardConstraintInChildren(func);\n\t}\n}\n\n\n// expects a function of type bool(const Part& p)\ntemplate<typename Pred>\nconst Part* Physical::findFirstInThisAndChildren(const Pred& pred) const {\n\tif(pred(this->rigidBody.mainPart)) {\n\t\treturn this->rigidBody.mainPart;\n\t} else {\n\t\tfor(const AttachedPart& p : this->rigidBody.parts) {\n\t\t\tif(pred(p.part)) {\n\t\t\t\treturn p.part;\n\t\t\t}\n\t\t}\n\t\tfor(const ConnectedPhysical& conPhys : childPhysicals) {\n\t\t\tconst Part* found = conPhys.findFirstInThisAndChildren(pred);\n\t\t\tif(found != nullptr) {\n\t\t\t\treturn found;\n\t\t\t}\n\t\t}\n\t\treturn nullptr;\n\t}\n}\n\n// expects a function of type bool(Part& p)\ntemplate<typename Pred>\nPart* Physical::findFirstInThisAndChildren(const Pred& pred) {\n\tif(pred(*this->rigidBody.mainPart)) {\n\t\treturn this->rigidBody.mainPart;\n\t} else {\n\t\tfor(const AttachedPart& p : this->rigidBody.parts) {\n\t\t\tif(pred(*p.part)) {\n\t\t\t\treturn p.part;\n\t\t\t}\n\t\t}\n\t\tfor(ConnectedPhysical& conPhys : childPhysicals) {\n\t\t\tPart* found = conPhys.findFirstInThisAndChildren(pred);\n\t\t\tif(found != nullptr) {\n\t\t\t\treturn found;\n\t\t\t}\n\t\t}\n\t\treturn nullptr;\n\t}\n}\n\n// used to precompute all the internal motions in the MotorizedPhysical\nclass InternalMotionTree {\n\tconst MotorizedPhysical* motorPhys;\n\tMonotonicTree<RelativeMotion> relativeMotionTree;\npublic:\n\n\tinline InternalMotionTree(const MotorizedPhysical* motorPhys, MonotonicTree<RelativeMotion>&& relativeMotionTree) : motorPhys(motorPhys), relativeMotionTree(std::move(relativeMotionTree)) {}\n\n\t// connectedPhysFunc is of the form void(const RelativeMotion& relativeMotionOfThisPhysical, const ConnectedPhysical& currentPhysical)\n\ttemplate<typename F>\n\tvoid forEach(F connectedPhysFunc) const {\n\t\tmotorPhys->mutuallyRecurse(relativeMotionTree, connectedPhysFunc);\n\t}\n\n\t// returns the total mass, the center of mass relative to the MotorizedPhysical's CFrame, and the motion of the center of mass in that CFrame\n\tstd::tuple<double, Vec3, TranslationalMotion> getInternalMotionOfCenterOfMass() const;\n\t// normalizes this motion tree relative to this->getInternalMotionOfCenterOfMass()\n\tCOMMotionTree normalizeCenterOfMass()&&;\n\n\tMonotonicTreeNode<RelativeMotion>* getPtrToFree() {\n\t\treturn relativeMotionTree.getPtrToFree();\n\t}\n};\n\n// Same as InternalMotionTree, but relative to the position and speed of the center of mass\nclass COMMotionTree {\n\tfriend class InternalMotionTree;\n\npublic:\n\tconst MotorizedPhysical* motorPhys;\n\tMonotonicTree<RelativeMotion> relativeMotionTree;\n\tdouble totalMass;\n\tVec3 centerOfMass;\n\tTranslationalMotion motionOfCenterOfMass;\n\tVec3 mainCOMOffset;\nprivate:\n\tinline COMMotionTree(const MotorizedPhysical* motorPhys, MonotonicTree<RelativeMotion>&& relativeMotionTree, double totalMass, Vec3 centerOfMass, TranslationalMotion motionOfCenterOfMass) :\n\t\tmotorPhys(motorPhys),\n\t\trelativeMotionTree(std::move(relativeMotionTree)),\n\t\ttotalMass(totalMass),\n\t\tcenterOfMass(centerOfMass),\n\t\tmotionOfCenterOfMass(motionOfCenterOfMass),\n\t\tmainCOMOffset(motorPhys->rigidBody.localCenterOfMass - centerOfMass) {}\n\npublic:\n\n\t// connectedPhysFunc is of the form void(const RelativeMotion& relativeMotionOfThisPhysical, const ConnectedPhysical& currentPhysical)\n\ttemplate<typename F>\n\tvoid forEach(F connectedPhysFunc) const {\n\t\tmotorPhys->mutuallyRecurse(relativeMotionTree, connectedPhysFunc);\n\t}\n\n\tSymmetricMat3 getInertia() const;\n\tFullTaylor<SymmetricMat3> getInertiaDerivatives() const;\n\tMotion getMotion() const;\n\tVec3 getInternalAngularMomentum() const;\n\n\tinline Vec3 getRelativePosOfMain() const {\n\t\treturn motorPhys->rigidBody.localCenterOfMass - centerOfMass;\n\t}\n\n\tinline TranslationalMotion getMotionOfMain() const {\n\t\treturn -motionOfCenterOfMass;\n\t}\n\n\tinline MonotonicTreeNode<RelativeMotion>* getPtrToFree() {\n\t\treturn relativeMotionTree.getPtrToFree();\n\t}\n};\n\n// Introduces extra variables std::size_t sizeName and COMMotionTree resultName\n// Warning, make sure to use with braces, is not if() else proof\n#define ALLOCA_COMMotionTree(resultName, motorPhysName, sizeName) \\\n\tstd::size_t sizeName = motorPhysName->getNumberOfPhysicalsInThisAndChildren() - 1; \\\n\tCOMMotionTree resultName = motorPhysName->getCOMMotionTree(UnmanagedArray<MonotonicTreeNode<RelativeMotion>>(\\\n\t\tstatic_cast<MonotonicTreeNode<RelativeMotion>*>(alloca(sizeof(MonotonicTreeNode<RelativeMotion>) * sizeName)), sizeName)\\\n\t);\n\n// Introduces extra variables std::size_t sizeName and InternalMotionTree resultName\n// Warning, make sure to use with braces, is not if() else proof\n#define ALLOCA_InternalMotionTree(resultName, motorPhysName, sizeName) \\\n\tstd::size_t sizeName = motorPhysName->getNumberOfPhysicalsInThisAndChildren() - 1; \\\n\tInternalMotionTree resultName = motorPhysName->getInternalRelativeMotionTree(UnmanagedArray<MonotonicTreeNode<RelativeMotion>>(\\\n\t\tstatic_cast<MonotonicTreeNode<RelativeMotion>*>(alloca(sizeof(MonotonicTreeNode<RelativeMotion>) * sizeName)), sizeName)\\\n\t);\n\n\nstruct FoundLayerRepresentative {\n\tWorldLayer* layer;\n\tPart* part;\n};\nstd::vector<FoundLayerRepresentative> findAllLayersIn(MotorizedPhysical* phys);\nstd::vector<FoundLayerRepresentative> findAllLayersIn(Part* part);\n};"
  },
  {
    "path": "Physics3D/relativeMotion.h",
    "content": "#pragma once\n\n#include \"math/cframe.h\"\n#include \"motion.h\"\n\nnamespace P3D {\nstruct RelativeMotion {\n\tMotion relativeMotion;\n\tCFrame locationOfRelativeMotion;\n\n\tRelativeMotion() = default;\n\n\tinline RelativeMotion(const Motion& relativeMotion, const CFrame& locationOfRelativeMotion) : \n\t\trelativeMotion(relativeMotion), \n\t\tlocationOfRelativeMotion(locationOfRelativeMotion) {}\n\n\t/*\n\t\tReturns a new RelativeMotion of the new endpoint where the new endpoint is rigidly attached to the old endpoint via extension\n\t\tThe extension vector is in the local space of the end point\n\t*/\n\tinline RelativeMotion extendEnd(const Vec3& extension) const {\n\t\tVec3 relativeExtension = locationOfRelativeMotion.localToRelative(extension);\n\n\t\tMotion resultingMotion = relativeMotion.getMotionOfPoint(relativeExtension);\n\t\t\n\t\treturn RelativeMotion(resultingMotion, locationOfRelativeMotion + relativeExtension);\n\t}\n\n\t/*\n\t\tReturns a new RelativeMotion of the new endpoint where the new endpoint is rigidly attached to the old endpoint via extension\n\t\tThe extension vector is in the local space of the end point\n\t*/\n\tinline RelativeMotion extendEnd(const CFrame& extension) const {\n\t\tVec3 relativeExtension = locationOfRelativeMotion.localToRelative(extension.getPosition());\n\n\t\tMotion resultingMotion = relativeMotion.getMotionOfPoint(relativeExtension);\n\n\t\treturn RelativeMotion(resultingMotion, locationOfRelativeMotion.localToGlobal(extension));\n\t}\n\n\n\t/*\n\t\tReturns a new RelativeMotion where this relativeMotion has been attached onto an extension\n\t*/\n\tinline RelativeMotion extendBegin(const Vec3& extension) const {\n\t\treturn RelativeMotion(relativeMotion, locationOfRelativeMotion + extension);\n\t}\n\n\t/*\n\t\tReturns a new RelativeMotion where this relativeMotion has been attached onto an extension\n\t*/\n\tinline RelativeMotion extendBegin(const CFrame& extension) const {\n\t\treturn RelativeMotion(localToGlobal(extension.getRotation() , relativeMotion), extension.localToGlobal(locationOfRelativeMotion));\n\t}\n\n\tinline Motion applyTo(const Motion& originMotion) const {\n\t\treturn originMotion.addOffsetRelativeMotion(locationOfRelativeMotion.getPosition(), relativeMotion);\n\t}\n};\n\n/*\n\tAppends the second RelativeMotion onto the end of the first one\n*/\ninline RelativeMotion operator+(const RelativeMotion& first, const RelativeMotion& second) {\n\tCFrame relativeCFrameToBeAdded = first.locationOfRelativeMotion.localToRelative(second.locationOfRelativeMotion);\n\t\n\tMotion rotatedSecondMotion = localToGlobal(first.locationOfRelativeMotion.getRotation(), second.relativeMotion);\n\tMotion motionOfEndpointWithSecondMotion = first.relativeMotion.addOffsetRelativeMotion(relativeCFrameToBeAdded.getPosition(), rotatedSecondMotion);\n\n\tCFrame resultingOffset = relativeCFrameToBeAdded + first.locationOfRelativeMotion.getPosition();\n\n\treturn RelativeMotion(motionOfEndpointWithSecondMotion, resultingOffset);\n}\n/*\n\tAppends the second RelativeMotion onto the end of the first one\n*/\ninline RelativeMotion& operator+=(RelativeMotion& first, const RelativeMotion& second) {\n\tfirst = first + second;\n\treturn first;\n}\n};"
  },
  {
    "path": "Physics3D/rigidBody.cpp",
    "content": "#include \"rigidBody.h\"\n\n#include \"inertia.h\"\n\n#include \"misc/validityHelper.h\"\n\n#include <assert.h>\n\nnamespace P3D {\nRigidBody::RigidBody(Part* mainPart) : \n\tmainPart(mainPart), \n\tmass(mainPart->getMass()),\n\tlocalCenterOfMass(mainPart->getLocalCenterOfMass()),\n\tinertia(mainPart->getInertia()) {}\n\nvoid RigidBody::attach(RigidBody&& otherBody, const CFrame& attachment) {\n\tconst GlobalCFrame& cf = this->getCFrame();\n\totherBody.mainPart->cframe = cf.localToGlobal(attachment);\n\tthis->parts.push_back(AttachedPart{attachment, otherBody.mainPart});\n\n\tfor(AttachedPart& ap : otherBody.parts) {\n\t\tCFrame globalAttach = attachment.localToGlobal(ap.attachment);\n\t\tthis->parts.push_back(AttachedPart{globalAttach, ap.part});\n\t\tap.part->cframe = cf.localToGlobal(globalAttach);\n\t}\n}\nvoid RigidBody::attach(Part* part, const CFrame& attachment) {\n\tparts.push_back(AttachedPart{attachment, part});\n\tpart->cframe = getCFrame().localToGlobal(attachment);\n\n\trefreshWithNewParts();\n}\nvoid RigidBody::detach(Part* part) {\n\tfor(AttachedPart& atPart : parts) {\n\t\tif(atPart.part == part) {\n\t\t\tparts.remove(std::move(atPart));\n\t\t\trefreshWithNewParts();\n\t\t\treturn;\n\t\t}\n\t}\n\n\tthrow \"part not found!\";\n}\nvoid RigidBody::detach(AttachedPart&& part) {\n\tparts.remove(std::move(part));\n\trefreshWithNewParts();\n\treturn;\n}\n\nconst AttachedPart& RigidBody::getAttachFor(const Part* attachedPart) const {\n\tfor(const AttachedPart& p : parts) {\n\t\tif(p.part == attachedPart) {\n\t\t\treturn p;\n\t\t}\n\t}\n\n\tthrow \"Part not in this physical!\";\n}\n\nAttachedPart& RigidBody::getAttachFor(const Part* attachedPart) {\n\tfor(AttachedPart& p : parts) {\n\t\tif(p.part == attachedPart) {\n\t\t\treturn p;\n\t\t}\n\t}\n\n\tthrow \"Part not in this physical!\";\n}\n\ntemplate<typename T>\nstatic inline bool liesInVector(const std::vector<T>& vec, const T* ptr) {\n\treturn &vec[0] <= ptr && &vec[0]+vec.size() > ptr;\n}\n\n// Not to be used by \nCFrame RigidBody::makeMainPart(AttachedPart& newMainPart) {\n\tif(liesInVector(parts, &newMainPart)) {\n\t\t// Update parts\n\t\tCFrame newCenterCFrame = newMainPart.attachment;\n\t\tstd::swap(mainPart, newMainPart.part);\n\t\tfor(AttachedPart& atPart : parts) {\n\t\t\tif(&atPart != &newMainPart) {\n\t\t\t\tatPart.attachment = newCenterCFrame.globalToLocal(atPart.attachment);\n\t\t\t}\n\t\t}\n\t\tnewMainPart.attachment = ~newCenterCFrame; // since this CFrame is now the attachment of the former mainPart, we can just invert the original CFrame\n\n\t\t// refresh is needed for resyncing inertia, center of mass, etc\n\t\trefreshWithNewParts();\n\n\t\treturn newCenterCFrame;\n\t} else {\n\t\tthrow \"Attempting to make a part not in this physical the mainPart!\";\n\t}\n}\n\nvoid RigidBody::notifyPartStdMoved(Part* oldPartPtr, Part* newPartPtr) noexcept {\n\tif(this->mainPart == oldPartPtr) {\n\t\tthis->mainPart = newPartPtr;\n\t} else {\n\t\tfor(AttachedPart& atPart : this->parts) {\n\t\t\tif(atPart.part == oldPartPtr) {\n\t\t\t\tatPart.part = newPartPtr;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tassert(false); // cannot happen, part must be in this rigidbody\n\t}\n}\n\nvoid RigidBody::refreshWithNewParts() {\n\tdouble totalMass = mainPart->getMass();\n\tVec3 totalCenterOfMass = mainPart->getLocalCenterOfMass() * mainPart->getMass();\n\tfor(const AttachedPart& p : parts) {\n\t\ttotalMass += p.part->getMass();\n\t\ttotalCenterOfMass += p.attachment.localToGlobal(p.part->getLocalCenterOfMass()) * p.part->getMass();\n\t}\n\ttotalCenterOfMass /= totalMass;\n\n\tSymmetricMat3 totalInertia = getTranslatedInertiaAroundCenterOfMass(mainPart->getInertia(), mainPart->getMass(), mainPart->getLocalCenterOfMass() - totalCenterOfMass);;\n\n\tfor(const AttachedPart& p : parts) {\n\t\tconst Part* part = p.part;\n\t\tCFrame attachRelativeToCOM = CFrame(p.attachment.getPosition() - totalCenterOfMass, p.attachment.getRotation());\n\t\ttotalInertia += getTransformedInertiaAroundCenterOfMass(part->getInertia(), part->getMass(), part->getLocalCenterOfMass(), attachRelativeToCOM);\n\t}\n\tthis->mass = totalMass;\n\tthis->localCenterOfMass = totalCenterOfMass;\n\tthis->inertia = totalInertia;\n}\n\nvoid RigidBody::setCFrame(const GlobalCFrame& newCFrame) {\n\tthis->mainPart->cframe = newCFrame;\n\tfor(const AttachedPart& p : parts) {\n\t\tp.part->cframe = newCFrame.localToGlobal(p.attachment);\n\t}\n}\n\nvoid RigidBody::setCFrameOfPart(Part* part, const GlobalCFrame& newCFrame) {\n\tif(part == mainPart) {\n\t\tsetCFrame(newCFrame);\n\t} else {\n\t\tCFrame attach = getAttachFor(part).attachment;\n\t\tGlobalCFrame newMainCFrame = newCFrame.localToGlobal(~attach);\n\n\t\tsetCFrame(newMainCFrame);\n\t}\n}\n\nvoid RigidBody::translate(const Vec3Fix& translation) {\n\tmainPart->cframe += translation;\n\tfor(AttachedPart& atPart : parts) {\n\t\tatPart.part->cframe += translation;\n\t}\n}\n\nvoid RigidBody::rotateAroundLocalPoint(const Vec3& localPoint, const Rotation& rotation) {\n\tVec3 relPoint = getCFrame().localToRelative(localPoint);\n\tVec3 relativeRotationOffset = rotation * relPoint - relPoint;\n\tmainPart->cframe.rotate(rotation);\n\tmainPart->cframe -= relativeRotationOffset;\n\tfor(AttachedPart& atPart : parts) {\n\t\tatPart.part->cframe = mainPart->cframe.localToGlobal(atPart.attachment);\n\t}\n}\n\nvoid RigidBody::setAttachFor(Part* part, const CFrame& attach) {\n\tif(mainPart == part) {\n\t\tfor(AttachedPart& ap : parts) {\n\t\t\tap.attachment = attach.globalToLocal(ap.attachment);\n\t\t}\n\t} else {\n\t\tAttachedPart& atPart = getAttachFor(part);\n\t\tatPart.attachment = attach;\n\t}\n\trefreshWithNewParts();\n}\n\nbool RigidBody::isValid() const {\n\tassert(std::isfinite(mass));\n\tassert(isVecValid(localCenterOfMass));\n\tassert(isMatValid(inertia));\n\tassert(mainPart->isValid());\n\tfor(const AttachedPart& ap : parts) {\n\t\tassert(isCFrameValid(ap.attachment));\n\t\tassert(ap.part->isValid());\n\t}\n\treturn true;\n}\n};"
  },
  {
    "path": "Physics3D/rigidBody.h",
    "content": "#pragma once\n\n#include \"datastructures/unorderedVector.h\"\n#include \"datastructures/iteratorEnd.h\"\n#include \"part.h\"\n\nnamespace P3D {\n\tstruct AttachedPart {\n\t\tCFrame attachment = CFrame();\n\t\tPart* part = nullptr;\n\t};\n\n\tstruct PartIter {\n\t\tAttachedPart* iter;\n\t\tAttachedPart* iterEnd;\n\t\tPart* first;\n\n\t\tPartIter() = default;\n\n\t\tPartIter(AttachedPart* iter, AttachedPart* iterEnd, Part* first)\n\t\t\t: iter(iter - 1)\n\t\t\t, iterEnd(iterEnd)\n\t\t\t, first(first) {}\n\n\t\tinline Part& operator*() const {\n\t\t\treturn (first != nullptr) ? *first : *iter->part;\n\t\t}\n\n\t\tinline void operator++() {\n\t\t\t++iter;\n\t\t\tfirst = nullptr;\n\t\t}\n\n\t\tinline bool operator!=(IteratorEnd) const {\n\t\t\treturn this->iter != this->iterEnd;\n\t\t}\n\n\t\tinline bool operator==(IteratorEnd) const {\n\t\t\treturn this->iter == this->iterEnd;\n\t\t}\n\t};\n\n\tstruct ConstPartIter {\n\t\tconst AttachedPart* iter;\n\t\tconst AttachedPart* iterEnd;\n\t\tconst Part* first;\n\n\t\tConstPartIter() = default;\n\n\t\tConstPartIter(const AttachedPart* iter, const AttachedPart* iterEnd, const Part* first)\n\t\t\t: iter(iter - 1)\n\t\t\t, iterEnd(iterEnd)\n\t\t\t, first(first) {}\n\n\t\tinline const Part& operator*() const {\n\t\t\treturn (first != nullptr) ? *first : *iter->part;\n\t\t}\n\n\t\tinline void operator++() {\n\t\t\t++iter;\n\t\t\tfirst = nullptr;\n\t\t}\n\n\t\tinline bool operator!=(IteratorEnd) const {\n\t\t\treturn this->iter != this->iterEnd;\n\t\t}\n\n\t\tinline bool operator==(IteratorEnd) const {\n\t\t\treturn this->iter == this->iterEnd;\n\t\t}\n\t};\n\n\tclass RigidBody {\n\tpublic:\n\t\tPart* mainPart;\n\t\tUnorderedVector<AttachedPart> parts;\n\t\tdouble mass; // precomputed cached value for this whole physical\n\t\tVec3 localCenterOfMass; // precomputed cached value for this whole physical\n\t\tSymmetricMat3 inertia; // precomputed cached value for this whole physical\n\n\t\tRigidBody() = default;\n\t\tRigidBody(Part* mainPart);\n\n\t\tRigidBody(RigidBody&& other) = default;\n\t\tRigidBody& operator=(RigidBody&& other) = default;\n\t\tRigidBody(const RigidBody&) = delete;\n\t\tvoid operator=(const RigidBody&) = delete;\n\n\t\tvoid attach(RigidBody&& otherBody, const CFrame& attachment);\n\t\tvoid attach(Part* part, const CFrame& attachment);\n\t\tvoid detach(Part* part);\n\t\tvoid detach(AttachedPart&& part);\n\t\tconst AttachedPart& getAttachFor(const Part* attachedPart) const;\n\t\tAttachedPart& getAttachFor(const Part* attachedPart);\n\n\t\tinline const Part* getMainPart() const {\n\t\t\treturn mainPart;\n\t\t}\n\n\t\tinline Part* getMainPart() {\n\t\t\treturn mainPart;\n\t\t}\n\n\t\t// returns the offset CFrame from the original mainPart, can be used for syncing calling function\n\t\tCFrame makeMainPart(AttachedPart& newMainPart);\n\n\t\tvoid notifyPartStdMoved(Part* oldPartPtr, Part* newPartPtr) noexcept;\n\n\t\t// expects a function of type void(const Part&)\n\t\ttemplate <typename Func>\n\t\tvoid forEachAttachedPart(const Func& func) const {\n\t\t\tfor (const AttachedPart& atPart : parts) {\n\t\t\t\tfunc(static_cast<const Part&>(*atPart.part));\n\t\t\t}\n\t\t}\n\n\t\t// expects a function of type void(Part&)\n\t\ttemplate <typename Func>\n\t\tvoid forEachAttachedPart(const Func& func) {\n\t\t\tfor (const AttachedPart& atPart : parts) {\n\t\t\t\tfunc(*atPart.part);\n\t\t\t}\n\t\t}\n\n\t\t// expects a function of type void(const Part&)\n\t\ttemplate <typename Func>\n\t\tvoid forEachPart(const Func& func) const {\n\t\t\tfunc(static_cast<const Part&>(*this->mainPart));\n\t\t\tthis->forEachAttachedPart(func);\n\t\t}\n\n\t\t// expects a function of type void(Part&)\n\t\ttemplate <typename Func>\n\t\tvoid forEachPart(const Func& func) {\n\t\t\tfunc(*this->mainPart);\n\t\t\tthis->forEachAttachedPart(func);\n\t\t}\n\n\t\tPartIter begin() {\n\t\t\tif (parts.empty()) {\n\t\t\t\treturn PartIter(nullptr, nullptr, mainPart);\n\t\t\t} else {\n\t\t\t\treturn PartIter(&parts[0], &parts[0] + parts.size(), mainPart);\n\t\t\t}\n\t\t}\n\n\t\tConstPartIter begin() const {\n\t\t\tif (parts.empty()) {\n\t\t\t\treturn ConstPartIter(nullptr, nullptr, mainPart);\n\t\t\t} else {\n\t\t\t\treturn ConstPartIter(&parts[0], &parts[0] + parts.size(), mainPart);\n\t\t\t}\n\t\t}\n\n\t\tIteratorEnd end() const {\n\t\t\treturn IteratorEnd();\n\t\t}\n\n\t\tconst Part& operator[](size_t index) const {\n\t\t\treturn (index == 0) ? *mainPart : *parts[index - 1].part;\n\t\t}\n\n\t\tPart& operator[](size_t index) {\n\t\t\treturn (index == 0) ? *mainPart : *parts[index - 1].part;\n\t\t}\n\n\t\tinline size_t getPartCount() const {\n\t\t\treturn parts.size() + 1;\n\t\t}\n\n\t\tvoid setCFrame(const GlobalCFrame& newCFrame);\n\t\tvoid setCFrameOfPart(Part* part, const GlobalCFrame& newCFrame);\n\t\tvoid translate(const Vec3Fix& translation);\n\t\tvoid rotateAroundLocalPoint(const Vec3& localPoint, const Rotation& rotation);\n\n\t\tvoid setAttachFor(Part* part, const CFrame& newAttach);\n\n\t\tinline const GlobalCFrame& getCFrame() const {\n\t\t\treturn mainPart->getCFrame();\n\t\t}\n\n\t\tinline Position getPosition() const {\n\t\t\treturn getCFrame().getPosition();\n\t\t}\n\n\t\tinline Position getCenterOfMass() const {\n\t\t\treturn getCFrame().localToGlobal(localCenterOfMass);\n\t\t}\n\n\t\tinline GlobalCFrame getCenterOfMassCFrame() const {\n\t\t\treturn GlobalCFrame(getCFrame().localToGlobal(localCenterOfMass), getCFrame().getRotation());\n\t\t}\n\n\t\tbool isValid() const;\n\n\t\tvoid refreshWithNewParts();\n\tprivate:\n\t};\n};\n"
  },
  {
    "path": "Physics3D/softlinks/alignmentLink.cpp",
    "content": "#include \"alignmentLink.h\"\n\nnamespace P3D {\nAlignmentLink::AlignmentLink(const AttachedPart& partA, const AttachedPart& partB) :\n\tSoftLink(partA, partB) {\n\n\toffset = this->attachedPartA.part->getCFrame().rotation.localToGlobal(this->attachedPartB.part->getCFrame().rotation);\n}\n\nvoid AlignmentLink::update() {\n\tVec3 momentDir = getGlobalMoment();\n\tthis->attachedPartA.part->applyMoment(momentDir);\n\tthis->attachedPartB.part->applyMoment(momentDir);\n}\n\nVec3 AlignmentLink::getGlobalMoment() noexcept {\n\tRotation rot1 = this->attachedPartA.part->getCFrame().getRotation().localToGlobal(this->offset);\n\tRotation rot2 = this->attachedPartB.part->getCFrame().getRotation();\n\n\tRotation deltRot = rot2.globalToLocal(rot1);\n\tVec3 momentDir = deltRot.asRotationVector();\n\n\treturn momentDir;\t\n}\n};"
  },
  {
    "path": "Physics3D/softlinks/alignmentLink.h",
    "content": "#pragma once\n\n#include \"softLink.h\"\n\nnamespace P3D {\nclass AlignmentLink : public SoftLink {\npublic:\n\tRotation offset;\n\n\tAlignmentLink(const AttachedPart& partA, const AttachedPart& partB);\n\t~AlignmentLink() override = default;\n\n\tAlignmentLink(const AlignmentLink& other) = delete;\n\tAlignmentLink& operator=(const AlignmentLink& other) = delete;\n\tAlignmentLink(AlignmentLink&& other) = delete;\n\tAlignmentLink& operator=(AlignmentLink&& other) = delete;\n\n\tvoid update() override;\n\nprivate:\n\t[[nodiscard]] Vec3 getGlobalMoment() noexcept;\n};\n};"
  },
  {
    "path": "Physics3D/softlinks/elasticLink.cpp",
    "content": "#include \"elasticLink.h\"\n\nnamespace P3D {\nElasticLink::ElasticLink(const AttachedPart& partA, const AttachedPart& partB, double restLength, double stiffness)\n\t: SoftLink(partA, partB)\n\t, restLength(restLength)\n\t, stiffness(stiffness) {}\n\nvoid ElasticLink::update() {\n\tauto optionalForce = forceAppliedToTheLink();\n\n\tif (!optionalForce)\n\t\treturn;\n\n\tVec3 force = optionalForce.value();\n\n\tthis->attachedPartA.part->applyForce(this->getRelativePositionOfAttachmentB(), force);\n\tthis->attachedPartB.part->applyForce(this->getRelativePositionOfAttachmentA(), -force);\n}\n\nstd::optional<Vec3> ElasticLink::forceAppliedToTheLink() {\n\tVec3 difference = this->getGlobalPositionOfAttachmentA() - this->getGlobalPositionOfAttachmentB();\n\tdouble distance = length(difference);\n\n\tif (distance <= this->restLength)\n\t\treturn std::nullopt;\n\n\tdouble magnitude = std::abs(distance - this->restLength) * this->stiffness;\n\tVec3 forceDirection = normalize(difference);\n\tVec3 force = magnitude * -forceDirection;\n\n\treturn force;\n}\n};\n"
  },
  {
    "path": "Physics3D/softlinks/elasticLink.h",
    "content": "#pragma once\n\n\n#include \"softLink.h\"\n#include <optional>\n\nnamespace P3D {\nclass ElasticLink : public SoftLink {\n\npublic:\n\tdouble restLength;\n\tdouble stiffness;\n\n\tElasticLink(const AttachedPart& partA, const AttachedPart& partB, double restLength, double stiffness);\n\t~ElasticLink() override = default;\n\n\tElasticLink(const ElasticLink&) = delete;\n\tElasticLink& operator=(const ElasticLink&) = delete;\n\tElasticLink(ElasticLink&&) = delete;\n\tElasticLink& operator=(ElasticLink&&) = delete;\n\n\tvoid update() override;\n\nprivate:\n\tstd::optional<Vec3> forceAppliedToTheLink();\n};\n};\n"
  },
  {
    "path": "Physics3D/softlinks/magneticLink.cpp",
    "content": "#include \"magneticLink.h\"\n\nnamespace P3D {\nMagneticLink::MagneticLink(const AttachedPart& partA, const AttachedPart& partB, double magneticStrength)\n\t: SoftLink(partA, partB)\n\t, magneticStrength(magneticStrength) {}\n\nvoid MagneticLink::update() {\n\tVec3 force = forceAppliedToTheLink();\n\n\tthis->attachedPartB.part->applyForce(this->getRelativePositionOfAttachmentA(), force);\n\tthis->attachedPartA.part->applyForce(this->getRelativePositionOfAttachmentB(), -force);\n}\n\nVec3 MagneticLink::forceAppliedToTheLink() noexcept {\n\tVec3 difference = this->getGlobalPositionOfAttachmentA() - this->getGlobalPositionOfAttachmentB();\n\n\tVec3 forceDirection = normalize(difference);\n\tdouble distance = lengthSquared(difference);\n\n\treturn this->magneticStrength * forceDirection / distance;\n\n}\n};\n"
  },
  {
    "path": "Physics3D/softlinks/magneticLink.h",
    "content": "#pragma once\n\n#include \"softLink.h\"\n\nnamespace P3D {\nclass MagneticLink : public SoftLink {\npublic:\n\tdouble magneticStrength;\n\n\tMagneticLink(const AttachedPart& partA, const AttachedPart& partB, double magneticStrength);\n\t~MagneticLink() override = default;\n\n\tMagneticLink(const MagneticLink& other) = delete;\n\tMagneticLink& operator=(const MagneticLink& other) = delete;\n\tMagneticLink(MagneticLink&& other) = delete;\n\tMagneticLink& operator=(MagneticLink&& other) = delete;\n\n\tvoid update() override;\n\nprivate:\n\t[[nodiscard]] Vec3 forceAppliedToTheLink() noexcept;\n\n};\n};"
  },
  {
    "path": "Physics3D/softlinks/softLink.cpp",
    "content": "#include \"softLink.h\"\n\nnamespace P3D {\n\nSoftLink::SoftLink(const AttachedPart& attachedPartA, const AttachedPart& attachedPartB)\n\t: attachedPartA(attachedPartA)\n\t, attachedPartB(attachedPartB) {}\n\nSoftLink::~SoftLink() = default;\n\nGlobalCFrame SoftLink::getGlobalCFrameOfAttachmentA() const {\n\treturn this->attachedPartA.part->getCFrame();\n}\n\nGlobalCFrame SoftLink::getGlobalCFrameOfAttachmentB() const {\n\treturn this->attachedPartB.part->getCFrame();\n}\n\nCFrame SoftLink::getLocalCFrameOfAttachmentA() const {\n\treturn this->attachedPartA.attachment;\n}\n\nCFrame SoftLink::getLocalCFrameOfAttachmentB() const {\n\treturn this->attachedPartB.attachment;\n}\n\nCFrame SoftLink::getRelativeOfAttachmentA() const {\n\treturn this->getGlobalCFrameOfAttachmentA().localToRelative(this->attachedPartA.attachment);\n\n}\nCFrame SoftLink::getRelativeOfAttachmentB() const {\n\treturn this->getGlobalCFrameOfAttachmentB().localToRelative(this->attachedPartB.attachment);\n}\n\nPosition SoftLink::getGlobalPositionOfAttachmentB() const {\n\treturn this->getGlobalCFrameOfAttachmentB().getPosition();\n}\nPosition SoftLink::getGlobalPositionOfAttachmentA() const {\n\treturn this->getGlobalCFrameOfAttachmentA().getPosition();\n}\nVec3 SoftLink::getLocalPositionOfAttachmentA() const {\n\treturn this->getLocalCFrameOfAttachmentA().getPosition();\n}\nVec3 SoftLink::getLocalPositionOfAttachmentB() const {\n\treturn this->getLocalCFrameOfAttachmentB().getPosition();\n}\nVec3 SoftLink::getRelativePositionOfAttachmentA() const {\n\treturn this->getRelativeOfAttachmentA().getPosition();\n}\nVec3 SoftLink::getRelativePositionOfAttachmentB() const {\n\treturn this->getRelativeOfAttachmentB().getPosition();\n}\n\n};\n"
  },
  {
    "path": "Physics3D/softlinks/softLink.h",
    "content": "#pragma once\n\n#include \"../math/linalg/vec.h\"\n#include \"../rigidBody.h\"\n#include \"../part.h\"\n\nnamespace P3D {\n\n\tclass SoftLink {\n\tpublic:\n\t\tAttachedPart attachedPartA;\n\t\tAttachedPart attachedPartB;\n\n\t\tSoftLink(const SoftLink& other) = delete;\n\t\tSoftLink& operator=(const SoftLink& other) = delete;\n\t\tSoftLink(SoftLink&& other) = delete;\n\t\tSoftLink& operator=(SoftLink&& other) = delete;\n\n\t\tvirtual ~SoftLink();\n\t\tvirtual void update() = 0;\n\n\t\tSoftLink(const AttachedPart& attachedPartA, const AttachedPart& attachedPartB);\n\n\t\tGlobalCFrame getGlobalCFrameOfAttachmentA() const;\n\t\tGlobalCFrame getGlobalCFrameOfAttachmentB() const;\n\n\t\tCFrame getLocalCFrameOfAttachmentA() const;\n\t\tCFrame getLocalCFrameOfAttachmentB() const;\n\n\t\tCFrame getRelativeOfAttachmentA() const;\n\t\tCFrame getRelativeOfAttachmentB() const;\n\n\t\tPosition getGlobalPositionOfAttachmentA() const;\n\t\tPosition getGlobalPositionOfAttachmentB() const;\n\n\t\tVec3 getLocalPositionOfAttachmentA() const;\n\t\tVec3 getLocalPositionOfAttachmentB() const;\n\n\t\tVec3 getRelativePositionOfAttachmentA() const;\n\t\tVec3 getRelativePositionOfAttachmentB() const;\n\t};\n};\n"
  },
  {
    "path": "Physics3D/softlinks/springLink.cpp",
    "content": "#include \"springLink.h\"\n\nnamespace P3D {\nSpringLink::SpringLink(const AttachedPart& partA, const AttachedPart& partB, double restLength, double stiffness)\n\t: SoftLink(partA, partB)\n\t, restLength(restLength)\n\t, stiffness(stiffness) {}\n\nvoid SpringLink::update() {\n\tVec3 force = forceAppliedToTheLink();\n\n\tthis->attachedPartB.part->applyForce(this->getRelativePositionOfAttachmentA(), force);\n\tthis->attachedPartA.part->applyForce(this->getRelativePositionOfAttachmentB(), -force);\n}\n\nVec3 SpringLink::forceAppliedToTheLink() noexcept {\n\tVec3 difference = this->getGlobalPositionOfAttachmentB() - this->getGlobalPositionOfAttachmentA();\n\tdouble distance = length(difference);\n\n\tdouble magnitude = std::abs(distance - this->restLength) * this->stiffness;\n\n\tVec3 forceDirection = normalize(difference);\n\treturn forceDirection * -magnitude;\n}\n};\n"
  },
  {
    "path": "Physics3D/softlinks/springLink.h",
    "content": "#pragma once\n\n#include \"softLink.h\"\n\nnamespace P3D {\nclass SpringLink : public SoftLink {\npublic:\n\tdouble restLength;\n\tdouble stiffness;\n\n\tSpringLink(const AttachedPart& partA, const AttachedPart& partB, double restLength, double stiffness);\n\t~SpringLink() override = default;\n\n\tSpringLink(const SpringLink& other) = delete;\n\tSpringLink& operator=(const SpringLink& other) = delete;\n\tSpringLink(SpringLink&& other) = delete;\n\tSpringLink& operator=(SpringLink&& other) = delete;\n\n\tvoid update() override;\n\nprivate:\n\t[[nodiscard]] Vec3 forceAppliedToTheLink() noexcept;\n\n};\n};"
  },
  {
    "path": "Physics3D/threading/physicsThread.cpp",
    "content": "#include \"physicsThread.h\"\n#include \"../world.h\"\n#include \"../worldPhysics.h\"\n#include \"../misc/physicsProfiler.h\"\n\n#include <iostream>\n\nnamespace P3D {\nusing namespace std::chrono;\n\nstatic void emptyFunc(WorldPrototype*) {}\n\nPhysicsThread::PhysicsThread(WorldPrototype* world, UpgradeableMutex* worldMutex, void(&tickFunction)(WorldPrototype*), std::chrono::milliseconds tickSkipTimeout, unsigned int threadCount) :\n\tworld(world),\n\tworldMutex(worldMutex),\n\ttickFunction(tickFunction),\n\ttickSkipTimeout(tickSkipTimeout),\n\tthreadPool(threadCount == 0 ? std::thread::hardware_concurrency() : threadCount) {}\n\nPhysicsThread::PhysicsThread(WorldPrototype* world, UpgradeableMutex* worldMutex, std::chrono::milliseconds tickSkipTimeout, unsigned int threadCount) :\n\tPhysicsThread(world, worldMutex, emptyFunc, tickSkipTimeout, threadCount) {}\n\nPhysicsThread::PhysicsThread(void(&tickFunction)(WorldPrototype*), std::chrono::milliseconds tickSkipTimeout, unsigned int threadCount) : \n\tPhysicsThread(nullptr, nullptr, tickFunction, tickSkipTimeout, threadCount) {}\n\nPhysicsThread::PhysicsThread(std::chrono::milliseconds tickSkipTimeout, unsigned int threadCount) : \n\tPhysicsThread(nullptr, nullptr, emptyFunc, tickSkipTimeout, threadCount) {}\n\nPhysicsThread::~PhysicsThread() {\n\tthis->stop();\n}\n\nvoid PhysicsThread::runTick() {\n\tphysicsMeasure.mark(PhysicsProcess::OTHER);\n\n\tthis->world->tick(this->threadPool);\n\n\tphysicsMeasure.mark(PhysicsProcess::OTHER);\n\ttickFunction(this->world);\n\n\tphysicsMeasure.end();\n\n\tGJKCollidesIterationStatistics.nextTally();\n\tGJKNoCollidesIterationStatistics.nextTally();\n\tEPAIterationStatistics.nextTally();\n}\n\nvoid PhysicsThread::start() {\n\tassert(!this->shouldBeRunning);\n\tif(this->thread.joinable()) this->thread.join();\n\tthis->shouldBeRunning = true;\n\n\tthis->thread = std::thread([this] () {\n\t\ttime_point<system_clock> nextTarget = system_clock::now();\n\n\t\twhile (this->shouldBeRunning) {\n\n\t\t\tmicroseconds tickTime = microseconds((long long) (1000000 * this->world->deltaT / this->speed));\n\n\t\t\tthis->runTick();\n\n\t\t\tnextTarget += tickTime;\n\t\t\ttime_point<system_clock>  curTime = system_clock::now();\n\t\t\tif (curTime < nextTarget) {\n\t\t\t\tstd::this_thread::sleep_until(nextTarget);\n\t\t\t} else {\n\t\t\t\t// We're behind schedule\n\t\t\t\tmilliseconds tickSkipTimeout = this->tickSkipTimeout.load();\n\t\t\t\tif (nextTarget < curTime - tickSkipTimeout) {\n\t\t\t\t\tdouble ticksToSkip = (curTime - nextTarget).count() / (1000.0 * tickSkipTimeout.count());\n\t\t\t\t\tstd::cout << \"Can't keep up! Skipping \" << ticksToSkip << \" ticks!\";\n\n\t\t\t\t\tnextTarget = curTime;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n}\nvoid PhysicsThread::stopAsync() {\n\tthis->shouldBeRunning = false;\n}\nvoid PhysicsThread::stop() {\n\tthis->stopAsync();\n\tif(this->thread.joinable()) this->thread.join();\n}\nbool PhysicsThread::isRunning() {\n\treturn this->shouldBeRunning;\n}\nvoid PhysicsThread::toggleRunningAsync() {\n\tif(this->shouldBeRunning) {\n\t\tthis->stopAsync();\n\t} else {\n\t\tthis->start();\n\t}\n}\nvoid PhysicsThread::toggleRunning() {\n\tif(this->shouldBeRunning) {\n\t\tthis->stop();\n\t} else {\n\t\tthis->start();\n\t}\n}\n}\n"
  },
  {
    "path": "Physics3D/threading/physicsThread.h",
    "content": "#pragma once\n\n#include <thread>\n#include <atomic>\n\n#include \"threadPool.h\"\n#include \"upgradeableMutex.h\"\n\nnamespace P3D {\nclass WorldPrototype;\n\nclass PhysicsThread {\n\tstd::thread thread;\n\tThreadPool threadPool;\n\tstd::atomic<bool> shouldBeRunning = false;\n\npublic:\n\tstd::atomic<double> speed = 1.0;\n\tstd::atomic<std::chrono::milliseconds> tickSkipTimeout;\n\tWorldPrototype* world;\n\tUpgradeableMutex* worldMutex;\n\tvoid(*tickFunction)(WorldPrototype*);\n\n\tPhysicsThread(WorldPrototype* world, UpgradeableMutex* worldMutex, void(&tickFunction)(WorldPrototype*), std::chrono::milliseconds tickSkipTimeout = std::chrono::milliseconds(1000), unsigned int threadCount = 0);\n\tPhysicsThread(WorldPrototype* world, UpgradeableMutex* worldMutex, std::chrono::milliseconds tickSkipTimeout = std::chrono::milliseconds(1000), unsigned int threadCount = 0);\n\tPhysicsThread(void(&tickFunction)(WorldPrototype*), std::chrono::milliseconds tickSkipTimeout = std::chrono::milliseconds(1000), unsigned int threadCount = 0);\n\tPhysicsThread(std::chrono::milliseconds tickSkipTimeout = std::chrono::milliseconds(1000), unsigned int threadCount = 0);\n\t~PhysicsThread();\n\t// Runs one tick. The PhysicsThread must not be running!\n\tvoid runTick();\n\t// Starts the PhysicsThread\n\tvoid start();\n\t// Stops the PhysicsThread, and returns once it has been stopped completely\n\tvoid stop();\n\t// instructs the PhysicsThread to stop, but returns immediately. PhysicsThread may still be running for some time before finally stopping\n\tvoid stopAsync();\n\tbool isRunning();\n\t// Starts if isRunning() == false, stop() if isRunning() == true\n\tvoid toggleRunning();\n\t// Starts if isRunning() == false, stopAsync() if isRunning() == true\n\tvoid toggleRunningAsync();\n};\n}\n"
  },
  {
    "path": "Physics3D/threading/sharedLockGuard.h",
    "content": "#pragma once\n\n#include <shared_mutex>\n\nnamespace P3D {\nclass SharedLockGuard {\n\tstd::shared_mutex& mutex;\n\tbool isHard = false;\n\npublic:\n\tinline SharedLockGuard(std::shared_mutex& mutex) : mutex(mutex) {\n\t\tmutex.lock_shared();\n\t}\n\n\tinline ~SharedLockGuard() {\n\t\tif(isHard) {\n\t\t\tmutex.unlock();\n\t\t} else {\n\t\t\tmutex.unlock_shared();\n\t\t}\n\t}\n\n\tinline void upgrade() {\n\t\tif(isHard) {\n\t\t\tthrow \"Attemt to upgrade already hard lock!\";\n\t\t}\n\t\tmutex.unlock_shared();\n\t\tmutex.lock();\n\t\tisHard = true;\n\t}\n\n\tinline void downgrade() {\n\t\tif(!isHard) {\n\t\t\tthrow \"Attempt to downgrade already soft lock!\";\n\t\t}\n\t\tmutex.unlock();\n\t\tmutex.lock_shared();\n\t\tisHard = false;\n\t}\n};\n\nclass UnlockOnDestroy {\n\tstd::shared_mutex& mutex;\npublic:\n\t/* assumes it is given a locked mutex\n\tUnlocks when destroyed*/\n\tinline UnlockOnDestroy(std::shared_mutex& mutex) : mutex(mutex) {}\n\t~UnlockOnDestroy() { mutex.unlock(); }\n};\n\nclass UnlockSharedOnDestroy {\n\tstd::shared_mutex& mutex;\npublic:\n\t/* assumes it is given a shared_locked mutex\n\tUnlocks when destroyed*/\n\tinline UnlockSharedOnDestroy(std::shared_mutex& mutex) : mutex(mutex) {}\n\t~UnlockSharedOnDestroy() { mutex.unlock_shared(); }\n};\n};"
  },
  {
    "path": "Physics3D/threading/threadPool.h",
    "content": "#pragma once\n\n#include <functional>\n#include <vector>\n#include <thread>\n#include <mutex>\n#include <condition_variable>\n\nnamespace P3D {\nclass ThreadPool {\n\tstd::function<void()> funcToRun = []() {};\n\tstd::vector<std::thread> threads{};\n\n\t// protects shouldStart, threadsWorking and their condition variables\n\tstd::mutex mtx;\n\n\t// this tells the threads to start working\n\tstd::condition_variable threadStarter;\n\tbool shouldStart = false;\n\n\t// this keeps track of the number of threads that are currently performing work, main thread may only return once all threads have finished working. \n\tstd::condition_variable threadsFinished;\n\tint threadsWorking = 0;\n\n\t// No explicit protection required since only the main thread may write to it and only in the destructor, so not when a new job is presented\n\tbool shouldExit = false;\n\npublic:\n\tThreadPool(unsigned int numThreads) : threads(numThreads - 1) {\n\t\tfor(std::thread& t : threads) {\n\t\t\tt = std::thread([this]() {\n\t\t\t\tstd::unique_lock<std::mutex> selfLock(mtx); // locks mtx\n\t\t\t\twhile(true) {\n\t\t\t\t\tthreadStarter.wait(selfLock, [this]() -> bool {return shouldStart; }); // this unlocks the mutex. And relocks when exiting\n\t\t\t\t\tthreadsWorking++;\n\t\t\t\t\tselfLock.unlock();\n\n\t\t\t\t\tif(shouldExit) break;\n\t\t\t\t\tfuncToRun();\n\n\t\t\t\t\tselfLock.lock();\n\t\t\t\t\tshouldStart = false; // once any thread finishes we assume we've reached the end, keep all threads from \n\t\t\t\t\tthreadsWorking--;\n\t\t\t\t\tif(threadsWorking == 0) {\n\t\t\t\t\t\tthreadsFinished.notify_one();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\tThreadPool() : ThreadPool(std::thread::hardware_concurrency()) {}\n\n\t// cleanup\n\t~ThreadPool() {\n\t\tshouldExit = true;\n\t\tmtx.lock();\n\t\tshouldStart = true;\n\t\tmtx.unlock();\n\t\tthreadStarter.notify_all();// all threads start running\n\t\tfor(std::thread& t : threads) t.join(); // let threads exit\n\t}\n\n\t// this work function may only return once all work has been completed\n\tvoid doInParallel(std::function<void()>&& work) {\n\t\tfuncToRun = std::move(work);\n\t\tstd::unique_lock<std::mutex> selfLock(mtx); // locks mtx\n\t\tshouldStart = true;\n\t\tselfLock.unlock();\n\t\tthreadStarter.notify_all();// all threads start running\n\t\tfuncToRun();\n\t\tselfLock.lock();\n\t\tshouldStart = false;\n\t\tthreadsFinished.wait(selfLock, [this]() -> bool {return threadsWorking == 0; });\n\t\tselfLock.unlock();\n\t}\n};\n};"
  },
  {
    "path": "Physics3D/threading/upgradeableMutex.cpp",
    "content": "#include \"upgradeableMutex.h\"\n\n// disable \"Caller failing to hold lock 'this->writerLockout' before calling function 'std::_Mutex_base::unlock'\" warning. \n#pragma warning(disable : 26110)\n\nnamespace P3D {\n// Unlocked -> Exclusive\nvoid UpgradeableMutex::lock() {\n\twriterLockout.lock();\n\tstateMutex.lock();\n}\n\n// Exclusive -> Unlocked\nvoid UpgradeableMutex::unlock() {\n\tstateMutex.unlock();\n\twriterLockout.unlock();\n}\n\n// Unlocked -> Shared\nvoid UpgradeableMutex::lock_shared() {\n\tstateMutex.lock_shared();\n}\n\n// Shared -> Unlocked\nvoid UpgradeableMutex::unlock_shared() {\n\tstateMutex.unlock_shared();\n}\n\n// Unlocked -> Shared Upgradeable\nvoid UpgradeableMutex::lock_upgradeable() {\n\twriterLockout.lock();\n\tstateMutex.lock_shared();\n}\n\n// Shared Upgradeable -> Unlocked\nvoid UpgradeableMutex::unlock_upgradeable() {\n\tstateMutex.unlock_shared();\n\twriterLockout.unlock();\n}\n\n// Shared Upgradeable -> Exclusive\nvoid UpgradeableMutex::upgrade() {\n\tstateMutex.unlock_shared();\n\tstateMutex.lock();\n}\n\n// Exclusive -> Shared Upgradeable\nvoid UpgradeableMutex::downgrade() {\n\tstateMutex.unlock();\n\tstateMutex.lock_shared();\n}\n\n// Exclusive -> Shared\nvoid UpgradeableMutex::final_downgrade() {\n\tstateMutex.unlock();\n\tstateMutex.lock_shared();\n\twriterLockout.unlock();\n}\n\n// Shared Upgradeable -> Shared\nvoid UpgradeableMutex::cancel_upgrade() {\n\twriterLockout.unlock();\n}\n};\n"
  },
  {
    "path": "Physics3D/threading/upgradeableMutex.h",
    "content": "#pragma once\n\n#include <mutex>\n#include <shared_mutex>\n\nnamespace P3D {\n/*\nThis mutex allows minimal reader interference for operations that require read/write exclusivity.\nIt allows a read lock with promise of upgrading to a write lock later, ensuring no writers in between.\nFor everything else, acts like a shared_mutex\n\nEach actor has 4 states:\n\t- Unlocked\n\t- Shared\n\t- Shared Upgradeable\n\t- Exclusive\n\nMost basic usage:\nmtx.lock_shared_upgradeable();\n// Shared read operations here, writers must wait until unlock.\n// Build some state here from reading, other readers allowed.\nmtx.upgrade();\n// Write here, other readers are excluded, other writers are exluded.\n// State is consistent with read section.\nmtx.unlock();\n\nRead-Write-Read usage:\nmtx.lock_shared_upgradeable();\n// Shared read operations here, writers must wait until unlock.\n// Build some state here from reading, other readers allowed.\nmtx.upgrade();\n// Write here, other readers are excluded, other writers are exluded.\n// State is consistent with read section.\nmtx.downgrade();\n// Read section, still maintain upgradability, other readers allowed.\nmtx.upgrade();\n// Write section\nmtx.final_downgrade();\n// Read section again, other readers allowed. Writers still excluded.\n// State is consistent with previous read and write sections.\nmtx.unlock_shared();\n// Other writers now allowed.\n\n\nAll function names are formatted snake_case to be compatible with std::lock and std::shared_lock\n*/\nclass UpgradeableMutex {\n\tstd::shared_mutex stateMutex;\n\n\t// Only one thread can be upgrading or have an exclusive lock at a time\n\tstd::mutex writerLockout;\n\npublic:\n\t// Unlocked -> Exclusive\n\tvoid lock();\n\t// Exclusive -> Unlocked\n\tvoid unlock();\n\t\n\t// Unlocked -> Shared\n\tvoid lock_shared();\n\t// Shared -> Unlocked\n\tvoid unlock_shared();\n\t\n\t// Unlocked -> Shared Upgradeable\n\tvoid lock_upgradeable();\n\t// Shared Upgradeable -> Unlocked\n\tvoid unlock_upgradeable();\n\n\t// Shared Upgradeable -> Exclusive\n\tvoid upgrade();\n\t// Exclusive -> Shared Upgradeable\n\tvoid downgrade();\n\t// Exclusive -> Shared\n\tvoid final_downgrade(); // calling final_downgrade instead of downgrade will allow another lock_upgradeable to make a reservation\n\t// Shared Upgradeable -> Shared\n\tvoid cancel_upgrade();\n};\n};\n"
  },
  {
    "path": "Physics3D/world.cpp",
    "content": "#include \"world.h\"\n\n#include <algorithm>\n#include \"misc/debug.h\"\n#include \"layer.h\"\n#include \"misc/validityHelper.h\"\n#include \"worldIteration.h\"\n#include \"threading/threadPool.h\"\n\nnamespace P3D {\n// #define CHECK_WORLD_VALIDITY\n#ifdef CHECK_WORLD_VALIDITY\n#define ASSERT_VALID if (!isValid()) throw \"World not valid!\";\n#else\n#define ASSERT_VALID\n#endif\n\n#pragma region worldValidity\n\nbool WorldPrototype::isValid() const {\n\tfor(const MotorizedPhysical* phys : this->physicals) {\n\t\tif(phys->getWorld() != this) {\n\t\t\tDebug::logError(\"physicals's world is not correct!\");\n\t\t\tDEBUGBREAK;\n\t\t\treturn false;\n\t\t}\n\n\t\tif(!isMotorizedPhysicalValid(phys)) {\n\t\t\tDebug::logError(\"Physical invalid!\");\n\t\t\tDEBUGBREAK;\n\t\t\treturn false;\n\t\t}\n\n\t\tbool result = true;\n\t\tphys->forEachPart([&result](const Part& part) {\n\t\t\tif(part.layer == nullptr) {\n\t\t\t\tDebug::logError(\"Part in physical has no layer!\");\n\t\t\t\tDEBUGBREAK;\n\t\t\t\tresult = false;\n\t\t\t} else {\n\t\t\t\tif(!part.layer->tree.contains(&part)) {\n\t\t\t\t\tDebug::logError(\"Part not in tree!\");\n\t\t\t\t\tDEBUGBREAK;\n\t\t\t\t\tresult = false;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tif(result == false) return false;\n\t}\n\n\tfor(const ColissionLayer& cl : layers) {\n\t\tfor(const WorldLayer& l : cl.subLayers) {\n\t\t\ttreeValidCheck(l.tree);\n\t\t\tfor(const Part& p : l.tree) {\n\t\t\t\tif(p.layer != &l) {\n\t\t\t\t\tDebug::logError(\"Part contained in layer, but it's layer field is not the layer\");\n\t\t\t\t\tDEBUGBREAK;\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn true;\n}\n#pragma endregion\n\nWorldPrototype::WorldPrototype(double deltaT) :\n\tdeltaT(deltaT),\n\tlayers(),\n\tcolissionMask() {\n\n\tlayers.emplace_back(this, true);\n}\n\nWorldPrototype::~WorldPrototype() {\n\n}\n\nstatic std::pair<int, int> pairLayers(int layer1, int layer2) {\n\tif(layer1 < layer2) {\n\t\treturn std::make_pair(layer1, layer2);\n\t} else {\n\t\treturn std::make_pair(layer2, layer1);\n\t}\n}\n\nbool WorldPrototype::doLayersCollide(int layer1, int layer2) const {\n\tif(layer1 == layer2) {\n\t\treturn layers[layer1].collidesInternally;\n\t} else {\n\t\tstd::pair<int, int> checkPair = pairLayers(layer1, layer2);\n\t\tfor(std::pair<int, int> itemInColissionMask : colissionMask) {\n\t\t\tif(itemInColissionMask == checkPair) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n}\nvoid WorldPrototype::setLayersCollide(int layer1, int layer2, bool collide) {\n\tif(layer1 == layer2) {\n\t\tlayers[layer1].collidesInternally = collide;\n\t} else {\n\t\tstd::pair<int, int> checkAddPair = pairLayers(layer1, layer2);\n\t\tfor(std::pair<int, int>& itemInColissionMask : colissionMask) {\n\t\t\tif(itemInColissionMask == checkAddPair) {\n\t\t\t\tif(!collide) {\n\t\t\t\t\t// remove for no collide\n\t\t\t\t\titemInColissionMask = colissionMask.back();\n\t\t\t\t\tcolissionMask.pop_back();\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tif(collide) {\n\t\t\tcolissionMask.push_back(checkAddPair);\n\t\t}\n\t}\n}\n\nint WorldPrototype::createLayer(bool collidesInternally, bool collidesWithOthers) {\n\tint layerIndex = static_cast<int>(layers.size());\n\tlayers.emplace_back(this, collidesInternally);\n\tif(collidesWithOthers) {\n\t\tfor(int i = 0; i < layerIndex; i++) {\n\t\t\tcolissionMask.emplace_back(i, layerIndex);\n\t\t}\n\t}\n\treturn layerIndex;\n}\nvoid WorldPrototype::deleteLayer(int layerIndex, int layerToMoveTo) {\n\n}\n\nstatic void createNodeFor(P3D::BoundsTree<Part>& tree, MotorizedPhysical* phys) {\n\tif(phys->isSinglePart()) {\n\t\ttree.add(phys->getMainPart());\n\t} else {\n\t\tP3D::TrunkAllocator& alloc = tree.getPrototype().getAllocator();\n\t\tP3D::TreeTrunk* newNode = alloc.allocTrunk();\n\t\tint newNodeSize = 0;\n\n\t\tphys->forEachPart([&alloc, &newNode, &newNodeSize, &tree](Part& p) {\n\t\t\tnewNodeSize = P3D::addRecursive(alloc, *newNode, newNodeSize, P3D::TreeNodeRef(static_cast<void*>(&p)), p.getBounds());\n\t\t});\n\t\ttree.getPrototype().addGroupTrunk(newNode, newNodeSize);\n\t}\n}\n\nvoid WorldPrototype::addPart(Part* part, int layerIndex) {\n\tASSERT_VALID;\n\n\tif(part->layer) {\n\t\tDebug::logWarn(\"This part is already in a world\");\n\t\tASSERT_VALID;\n\t\treturn;\n\t}\n\n\tPhysical* partPhys = part->ensureHasPhysical();\n\tphysicals.push_back(partPhys->mainPhysical);\n\n\tWorldLayer* worldLayer = &layers[layerIndex].subLayers[ColissionLayer::FREE_PARTS_LAYER];\n\tpartPhys->mainPhysical->forEachPart([worldLayer](Part& p) {\n\t\tp.layer = worldLayer;\n\t});\n\tcreateNodeFor(worldLayer->tree, partPhys->mainPhysical);\n\n\n\tobjectCount += partPhys->mainPhysical->getNumberOfPartsInThisAndChildren();\n\n\tASSERT_VALID;\n\n\tpartPhys->mainPhysical->forEachPart([this](Part& p) {\n\t\tthis->onPartAdded(&p);\n\t});\n\n\tASSERT_VALID;\n}\n\nstatic void createNewNodeFor(MotorizedPhysical* motorPhys, BoundsTree<Part>& layer, Part* repPart) {\n\tsize_t totalParts = 0;\n\tmotorPhys->forEachPart([&layer, &totalParts](Part& p) {\n\t\tif(&p.layer->tree == &layer) {\n\t\t\ttotalParts++;\n\t\t}\n\t});\n\n\tassert(totalParts >= 1);\n\tif(totalParts == 1) {\n\t\tlayer.add(repPart);\n\t} else {\n\t\tTrunkAllocator& alloc = layer.getPrototype().getAllocator();\n\t\tTreeTrunk* newNode = alloc.allocTrunk();\n\t\tint newNodeSize = 0;\n\n\t\tmotorPhys->forEachPart([&alloc, &newNode, &newNodeSize, &layer, repPart](Part& p) {\n\t\t\tif(&p.layer->tree == &layer) {\n\t\t\t\tnewNodeSize = addRecursive(alloc, *newNode, newNodeSize, TreeNodeRef(static_cast<void*>(&p)), p.getBounds());\n\t\t\t}\n\t\t});\n\t\tlayer.getPrototype().addGroupTrunk(newNode, newNodeSize);\n\t}\n}\n\nvoid WorldPrototype::addPhysicalWithExistingLayers(MotorizedPhysical* motorPhys) {\n\tphysicals.push_back(motorPhys);\n\n\tstd::vector<FoundLayerRepresentative> foundLayers = findAllLayersIn(motorPhys);\n\n\tfor(const FoundLayerRepresentative& l : foundLayers) {\n\t\tcreateNewNodeFor(motorPhys, l.layer->tree, l.part);\n\t}\n\n\tASSERT_VALID;\n}\n\nvoid WorldPrototype::addTerrainPart(Part* part, int layerIndex) {\n\tobjectCount++;\n\n\tWorldLayer* worldLayer = &layers[layerIndex].subLayers[ColissionLayer::TERRAIN_PARTS_LAYER];\n\tpart->layer = worldLayer;\n\tworldLayer->addPart(part);\n\n\tASSERT_VALID;\n\n\tthis->onPartAdded(part);\n\n\tASSERT_VALID;\n}\nvoid WorldPrototype::removePart(Part* part) {\n\tASSERT_VALID;\n\n\tpart->removeFromWorld();\n\n\tASSERT_VALID;\n}\n\nvoid WorldPrototype::deletePart(Part* partToDelete) const {\n\tdelete partToDelete;\n}\n\nvoid WorldPrototype::clear() {\n\tthis->constraints.clear();\n\tthis->externalForces.clear();\n\tfor(MotorizedPhysical* phys : this->physicals) {\n\t\tdelete phys;\n\t}\n\tthis->physicals.clear();\n\tstd::vector<Part*> partsToDelete;\n\tthis->forEachPart([&partsToDelete](Part& part) {\n\t\tpart.parent = nullptr;\n\t\tpart.layer = nullptr;\n\t\tpartsToDelete.push_back(&part);\n\t});\n\tthis->objectCount = 0;\n\tfor(ColissionLayer& cl : this->layers) {\n\t\tfor(WorldLayer& layer : cl.subLayers) {\n\t\t\tlayer.tree.clear();\n\t\t}\n\t}\n\tfor(Part* p : partsToDelete) {\n\t\tthis->onPartRemoved(p);\n\t\tthis->deletePart(p);\n\t}\n}\n\nint WorldPrototype::getLayerCount() const {\n\treturn static_cast<int>(this->layers.size());\n}\n\nvoid WorldPrototype::optimizeLayers() {\n\tfor(ColissionLayer& layer : layers) {\n\t\tlayer.subLayers[ColissionLayer::TERRAIN_PARTS_LAYER].optimize();\n\t}\n\tASSERT_VALID;\n}\n\nstatic void assignLayersForPhysicalRecurse(const Physical& phys, std::vector<std::pair<WorldLayer*, std::vector<const Part*>>>& foundLayers) {\n\tphys.rigidBody.forEachPart([&foundLayers](const Part& part) {\n\t\tfor(std::pair<WorldLayer*, std::vector<const Part*>>& knownLayer : foundLayers) {\n\t\t\tif(part.layer == knownLayer.first) {\n\t\t\t\tknownLayer.second.push_back(&part);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tfoundLayers.emplace_back(part.layer, std::vector<const Part*>{&part});\n\t});\n\tfor(const ConnectedPhysical& conPhys : phys.childPhysicals) {\n\t\tassignLayersForPhysicalRecurse(conPhys, foundLayers);\n\t}\n}\n\nvoid WorldPrototype::notifyPhysicalHasBeenSplit(const MotorizedPhysical* mainPhysical, MotorizedPhysical* newlySplitPhysical) {\n\tassert(mainPhysical->getWorld() == this);\n\tassert(newlySplitPhysical->getWorld() == nullptr);\n\tthis->physicals.push_back(newlySplitPhysical);\n\n\tstd::vector<std::pair<WorldLayer*, std::vector<const Part*>>> layersThatNeedToBeSplit;\n\tassignLayersForPhysicalRecurse(*newlySplitPhysical, layersThatNeedToBeSplit);\n\n\tfor(const std::pair<WorldLayer*, std::vector<const Part*>>& layer : layersThatNeedToBeSplit) {\n\t\tlayer.first->splitGroup(layer.second.begin(), layer.second.end());\n\t}\n\n\n\t// split object tree\n\t// TODO: The findGroupFor and grap calls can be merged as an optimization\n\t/*NodeStack stack = objectTree.findGroupFor(newlySplitPhysical->getMainPart(), newlySplitPhysical->getMainPart()->getBounds());\n\n\tTreeNode* node = *stack;\n\n\tTreeNode newNode = objectTree.grab(newlySplitPhysical->getMainPart(), newlySplitPhysical->getMainPart()->getBounds());\n\tif(!newNode.isGroupHead) {\n\t\tnewNode.isGroupHead = true;\n\n\t\t// node should still be valid at this time\n\n\t\tfor(TreeIterator iter(*node); iter != IteratorEnd();) {\n\t\t\tTreeNode* objectNode = *iter;\n\t\t\tPart* part = static_cast<Part*>(objectNode->object);\n\t\t\tif(part->parent->mainPhysical == newlySplitPhysical) {\n\t\t\t\tnewNode.addInside(iter.remove());\n\t\t\t} else {\n\t\t\t\t++iter;\n\t\t\t}\n\t\t}\n\t\tstack.updateBoundsAllTheWayToTop();\n\t}\n\n\tobjectTree.add(std::move(newNode));\n\n\tassert(this->isValid());*/\n\n\n}\n\nvoid WorldPrototype::onPartAdded(Part* newPart) {}\nvoid WorldPrototype::onPartRemoved(Part* removedPart) {}\n\nvoid WorldPrototype::addExternalForce(ExternalForce* force) {\n\texternalForces.push_back(force);\n}\n\nvoid WorldPrototype::removeExternalForce(ExternalForce* force) {\n\texternalForces.erase(std::remove(externalForces.begin(), externalForces.end(), force));\n}\n};"
  },
  {
    "path": "Physics3D/world.h",
    "content": "#pragma once\n\n#include <vector>\n#include <mutex>\n#include <memory>\n\n#include \"part.h\"\n#include \"physical.h\"\n#include \"constraints/constraintGroup.h\"\n#include \"softlinks/softLink.h\"\n#include \"externalforces/externalForce.h\"\n#include \"colissionBuffer.h\"\n\nnamespace P3D {\nclass Physical;\nclass MotorizedPhysical;\nclass ConnectedPhysical;\nclass Part;\nclass WorldLayer;\nclass ColissionLayer;\nclass ThreadPool;\n\nclass WorldPrototype {\nprivate:\n\tfriend class Physical;\n\tfriend class MotorizedPhysical;\n\tfriend class ConnectedPhysical;\n\tfriend class Part;\n\tfriend class WorldLayer;\n\tfriend class ColissionLayer;\n\n\t/*\n\t\tSplits newlySplitPhysical from mainPhysical in the world tree, also adds the new physical to the list of physicals\n\t*/\n\tvoid notifyPhysicalHasBeenSplit(const MotorizedPhysical* mainPhysical, MotorizedPhysical* newlySplitPhysical);\n\nprotected:\n\n\n\t// event handlers\n\tvirtual void onPartAdded(Part* newPart);\n\tvirtual void onPartRemoved(Part* removedPart);\n\n\t// called when the part has already been removed from the world\n\tvirtual void deletePart(Part* partToDelete) const;\n\npublic:\n\t// AABB trees for storing parts\n\tstd::vector<ColissionLayer> layers;\n\t// Sparse matrix listing layer-layer colissions\n\tstd::vector<std::pair<int, int>> colissionMask;\n\t\n\t// All physicals\n\tstd::vector<MotorizedPhysical*> physicals;\n\n\tvoid addPhysicalWithExistingLayers(MotorizedPhysical* motorPhys);\n\n\t// Extra world features\n\tstd::vector<ExternalForce*> externalForces;\n\tstd::vector<ConstraintGroup> constraints;\n\tstd::vector<SoftLink*> softLinks;\n\n\tvoid addLink(SoftLink* link);\n\n\tColissionBuffer curColissions;\n\tsize_t age = 0;\n\tsize_t objectCount = 0;\n\tdouble deltaT;\n\n\n\tWorldPrototype(double deltaT);\n\t~WorldPrototype();\n\n\tWorldPrototype(const WorldPrototype&) = delete;\n\tWorldPrototype& operator=(const WorldPrototype&) = delete;\n\tWorldPrototype(WorldPrototype&&) = delete;\n\tWorldPrototype& operator=(WorldPrototype&&) = delete;\n\n\tvirtual void tick(ThreadPool& threadPool);\n\tvoid tick();\n\n\tvirtual void addPart(Part* part, int layerIndex = 0);\n\tvirtual void removePart(Part* part);\n\tvoid addTerrainPart(Part* part, int layerIndex = 0);\n\n\tbool doLayersCollide(int layer1, int layer2) const;\n\tvoid setLayersCollide(int layer1, int layer2, bool collide);\n\n\tint createLayer(bool collidesInternally, bool collidesWithOthers);\n\n\t// deletes a layer, moves all parts from the deleted layer to layerToMoveTo\n\tvoid deleteLayer(int layerIndex, int layerToMoveTo);\n\n\tvoid optimizeLayers();\n\n\t// removes everything from this world, parts, physicals, forces, constraints\n\tvoid clear();\n\n\tinline size_t getPartCount() const {\n\t\treturn objectCount;\n\t}\n\n\tint getLayerCount() const;\n\n\tvirtual double getTotalKineticEnergy() const;\n\tvirtual double getTotalPotentialEnergy() const;\n\tvirtual double getPotentialEnergyOfPhysical(const MotorizedPhysical& p) const;\n\tvirtual double getTotalEnergy() const;\n\n\tvoid addExternalForce(ExternalForce* force);\n\tvoid removeExternalForce(ExternalForce* force);\n\n\tvirtual bool isValid() const;\n\n\t// include worldIteration.h to use\n\t// expects a function of the form void(Part& part)\n\ttemplate<typename Func>\n\tvoid forEachPart(const Func& funcToRun) const;\n\n\t// include worldIteration.h to use\n\t// expects a function of the form void(Part& part)\n\ttemplate<typename Func, typename Filter>\n\tvoid forEachPartFiltered(const Filter& filter, const Func& funcToRun) const;\n};\n\ntemplate<typename T = Part>\nclass World : public WorldPrototype {\npublic:\n\tWorld(double deltaT) : WorldPrototype(deltaT) {}\n\n\tvirtual void onCollide(Part* partA, Part* partB) {}\n\tvirtual void onCollide(T* partA, T* partB) {}\n\n\tvirtual void onPartAdded(T* part) {}\n\tvirtual void onPartRemoved(T* part) {}\n\n\tvirtual void deletePart(T* part) const {\n\t\tdelete part;\n\t}\n\tvoid onPartAdded(Part* part) final override {\n\t\tthis->onPartAdded(static_cast<T*>(part));\n\t}\n\tvoid onPartRemoved(Part* part) final override {\n\t\tthis->onPartRemoved(static_cast<T*>(part));\n\t}\n\t// called when the part has already been removed from the world\n\tvoid deletePart(Part* partToDelete) const final override {\n\t\tthis->deletePart(static_cast<T*>(partToDelete));\n\t}\n\n\t// include worldIteration.h to use\n\t// expects a function of the form void(T& part)\n\ttemplate<typename Func>\n\tvoid forEachPart(const Func& funcToRun) const;\n\n\t// include worldIteration.h to use\n\t// expects a function of the form void(T& part)\n\ttemplate<typename Func, typename Filter>\n\tvoid forEachPartFiltered(const Filter& filter, const Func& funcToRun) const;\n};\n};"
  },
  {
    "path": "Physics3D/worldIteration.h",
    "content": "#pragma once\n\n#include \"world.h\"\n#include \"layer.h\"\n\nnamespace P3D {\n// expects a function of the form void(Part& part)\ntemplate<typename Func>\nvoid WorldPrototype::forEachPart(const Func& funcToRun) const {\n\tfor(const ColissionLayer& layer : this->layers) {\n\t\tlayer.forEach(funcToRun);\n\t}\n}\n// expects a function of the form void(Part& part)\ntemplate<typename Func, typename Filter>\nvoid WorldPrototype::forEachPartFiltered(const Filter& filter, const Func& funcToRun) const {\n\tfor(const ColissionLayer& layer : this->layers) {\n\t\tlayer.forEachFiltered(filter, funcToRun);\n\t}\n}\n\n// expects a function of the form void(T& part)\ntemplate<typename T>\ntemplate<typename Func>\nvoid World<T>::forEachPart(const Func& funcToRun) const {\n\tstatic_cast<const WorldPrototype*>(this)->forEachPart([&funcToRun](Part& part) {funcToRun(static_cast<T&>(part)); });\n}\n// expects a function of the form void(T& part)\ntemplate<typename T>\ntemplate<typename Func, typename Filter>\nvoid World<T>::forEachPartFiltered(const Filter& filter, const Func& funcToRun) const {\n\tstatic_cast<const WorldPrototype*>(this)->forEachPartFiltered(filter, [&funcToRun](Part& part) {funcToRun(static_cast<T&>(part)); });\n}\n};\n\n"
  },
  {
    "path": "Physics3D/worldPhysics.cpp",
    "content": "#include \"worldPhysics.h\"\n\n#include \"world.h\"\n#include \"layer.h\"\n\n#include \"math/mathUtil.h\"\n#include \"math/linalg/vec.h\"\n#include \"math/linalg/trigonometry.h\"\n\n#include \"misc/debug.h\"\n#include \"misc/physicsProfiler.h\"\n\n#include <vector>\n#include <cmath>\n#include <algorithm>\n\n#define COLLISSION_DEPTH_FORCE_MULTIPLIER 2000\n\nnamespace P3D {\n/*\n\texitVector is the distance p2 must travel so that the shapes are no longer colliding\n*/\n\nvoid handleCollision(Part& part1, Part& part2, Position collisionPoint, Vec3 exitVector) {\n\tDebug::logPoint(collisionPoint, Debug::INTERSECTION);\n\t\n\tMotorizedPhysical& phys1 = *part1.getPhysical()->mainPhysical;\n\tMotorizedPhysical& phys2 = *part2.getPhysical()->mainPhysical;\n\n\tdouble sizeOrder = std::min(part1.maxRadius, part2.maxRadius);\n\tif(lengthSquared(exitVector) <= 1E-8 * sizeOrder * sizeOrder) {\n\t\treturn; // don't do anything for very small colissions\n\t}\n\n\tVec3 collissionRelP1 = collisionPoint - phys1.getCenterOfMass();\n\tVec3 collissionRelP2 = collisionPoint - phys2.getCenterOfMass();\n\n\tdouble inertia1A = phys1.getInertiaOfPointInDirectionRelative(collissionRelP1, exitVector);\n\tdouble inertia2A = phys2.getInertiaOfPointInDirectionRelative(collissionRelP2, exitVector);\n\tdouble combinedInertia = 1 / (1 / inertia1A + 1 / inertia2A);\n\n\t// Friction\n\tdouble staticFriction = part1.properties.friction * part2.properties.friction;\n\tdouble dynamicFriction = part1.properties.friction * part2.properties.friction;\n\n\n\tVec3 depthForce = -exitVector * (COLLISSION_DEPTH_FORCE_MULTIPLIER * combinedInertia);\n\n\tphys1.applyForce(collissionRelP1, depthForce);\n\tphys2.applyForce(collissionRelP2, -depthForce);\n\n\tVec3 part1ToColission = collisionPoint - part1.getPosition();\n\tVec3 part2ToColission = collisionPoint - part2.getPosition();\n\n\tVec3 relativeVelocity = (part1.getMotion().getVelocityOfPoint(part1ToColission) - part1.properties.conveyorEffect) - (part2.getMotion().getVelocityOfPoint(part2ToColission) - part2.properties.conveyorEffect);\n\n\tbool isImpulseColission = relativeVelocity * exitVector > 0;\n\n\tVec3 impulse;\n\n\tdouble combinedBouncyness = part1.properties.bouncyness * part2.properties.bouncyness;\n\n\tif(isImpulseColission) { // moving towards the other object\n\t\tVec3 desiredAccel = -exitVector * (relativeVelocity * exitVector) / lengthSquared(exitVector) * (1.0 + combinedBouncyness);\n\t\tVec3 zeroRelVelImpulse = desiredAccel * combinedInertia;\n\t\timpulse = zeroRelVelImpulse;\n\t\tphys1.applyImpulse(collissionRelP1, impulse);\n\t\tphys2.applyImpulse(collissionRelP2, -impulse);\n\t\trelativeVelocity += desiredAccel;\n\t}\n\n\tVec3 slidingVelocity = exitVector % relativeVelocity % exitVector / lengthSquared(exitVector);\n\n\t// Compute combined inertia in the horizontal direction\n\tdouble inertia1B = phys1.getInertiaOfPointInDirectionRelative(collissionRelP1, slidingVelocity);\n\tdouble inertia2B = phys2.getInertiaOfPointInDirectionRelative(collissionRelP2, slidingVelocity);\n\tdouble combinedHorizontalInertia = 1 / (1 / inertia1B + 1 / inertia2B);\n\n\tif(isImpulseColission) {\n\t\tVec3 maxFrictionImpulse = -exitVector % impulse % exitVector / lengthSquared(exitVector) * staticFriction;\n\t\tVec3 stopFricImpulse = -slidingVelocity * combinedHorizontalInertia;\n\n\t\tVec3 fricImpulse = (lengthSquared(stopFricImpulse) < lengthSquared(maxFrictionImpulse)) ? stopFricImpulse : maxFrictionImpulse;\n\n\t\tphys1.applyImpulse(collissionRelP1, fricImpulse);\n\t\tphys2.applyImpulse(collissionRelP2, -fricImpulse);\n\t}\n\n\tdouble normalForce = length(depthForce);\n\tdouble frictionForce = normalForce * dynamicFriction;\n\tdouble slidingSpeed = length(slidingVelocity) + 1E-100;\n\tVec3 dynamicFricForce;\n\tdouble dynamicSaturationSpeed = sizeOrder * 0.01;\n\tif(slidingSpeed > dynamicSaturationSpeed) {\n\t\tdynamicFricForce = -slidingVelocity / slidingSpeed * frictionForce;\n\t} else {\n\t\tdouble effectFactor = slidingSpeed / (dynamicSaturationSpeed);\n\t\tdynamicFricForce = -slidingVelocity / slidingSpeed * frictionForce * effectFactor;\n\t}\n\tphys1.applyForce(collissionRelP1, dynamicFricForce);\n\tphys2.applyForce(collissionRelP2, -dynamicFricForce);\n\n\tassert(phys1.isValid());\n\tassert(phys2.isValid());\n}\n\n/*\n\texitVector is the distance p2 must travel so that the shapes are no longer colliding\n*/\nvoid handleTerrainCollision(Part& part1, Part& part2, Position collisionPoint, Vec3 exitVector) {\n\tDebug::logPoint(collisionPoint, Debug::INTERSECTION);\n\tMotorizedPhysical& phys1 = *part1.getPhysical()->mainPhysical;\n\n\tdouble sizeOrder = std::min(part1.maxRadius, part2.maxRadius);\n\tif(lengthSquared(exitVector) <= 1E-8 * sizeOrder * sizeOrder) {\n\t\treturn; // don't do anything for very small colissions\n\t}\n\n\tVec3 collissionRelP1 = collisionPoint - phys1.getCenterOfMass();\n\n\tdouble inertia = phys1.getInertiaOfPointInDirectionRelative(collissionRelP1, exitVector);\n\n\t// Friction\n\tdouble staticFriction = part1.properties.friction * part2.properties.friction;\n\tdouble dynamicFriction = part1.properties.friction * part2.properties.friction;\n\n\n\tVec3 depthForce = -exitVector * (COLLISSION_DEPTH_FORCE_MULTIPLIER * inertia);\n\n\tphys1.applyForce(collissionRelP1, depthForce);\n\n\t//Vec3 rigidBodyToPart = part1.getCFrame().getPosition() - part1.getPhysical()->rigidBody.getCenterOfMass();\n\tVec3 partToColission = collisionPoint - part1.getPosition();\n\tVec3 relativeVelocity = part1.getMotion().getVelocityOfPoint(partToColission) - part1.properties.conveyorEffect + part2.getCFrame().localToRelative(part2.properties.conveyorEffect);\n\n\tbool isImpulseColission = relativeVelocity * exitVector > 0;\n\n\tVec3 impulse;\n\n\tdouble combinedBouncyness = part1.properties.bouncyness * part2.properties.bouncyness;\n\n\tif(isImpulseColission) { // moving towards the other object\n\t\tVec3 desiredAccel = -exitVector * (relativeVelocity * exitVector) / lengthSquared(exitVector) * (1.0 + combinedBouncyness);\n\t\tVec3 zeroRelVelImpulse = desiredAccel * inertia;\n\t\timpulse = zeroRelVelImpulse;\n\t\tphys1.applyImpulse(collissionRelP1, impulse);\n\t\trelativeVelocity += desiredAccel;\n\t}\n\n\tVec3 slidingVelocity = exitVector % relativeVelocity % exitVector / lengthSquared(exitVector);\n\n\t// Compute combined inertia in the horizontal direction\n\tdouble combinedHorizontalInertia = phys1.getInertiaOfPointInDirectionRelative(collissionRelP1, slidingVelocity);\n\n\tif(isImpulseColission) {\n\t\tVec3 maxFrictionImpulse = -exitVector % impulse % exitVector / lengthSquared(exitVector) * staticFriction;\n\t\tVec3 stopFricImpulse = -slidingVelocity * combinedHorizontalInertia;\n\n\t\tVec3 fricImpulse = (lengthSquared(stopFricImpulse) < lengthSquared(maxFrictionImpulse)) ? stopFricImpulse : maxFrictionImpulse;\n\n\t\tphys1.applyImpulse(collissionRelP1, fricImpulse);\n\t}\n\n\tdouble normalForce = length(depthForce);\n\tdouble frictionForce = normalForce * dynamicFriction;\n\tdouble slidingSpeed = length(slidingVelocity) + 1E-100;\n\tVec3 dynamicFricForce;\n\tdouble dynamicSaturationSpeed = sizeOrder * 0.01;\n\tif(slidingSpeed > dynamicSaturationSpeed) {\n\t\tdynamicFricForce = -slidingVelocity / slidingSpeed * frictionForce;\n\t} else {\n\t\tdouble effectFactor = slidingSpeed / (dynamicSaturationSpeed);\n\t\tdynamicFricForce = -slidingVelocity / slidingSpeed * frictionForce * effectFactor;\n\t}\n\tphys1.applyForce(collissionRelP1, dynamicFricForce);\n\n\tassert(phys1.isValid());\n}\n\n/*\n\t===== World Tick =====\n*/\n\nvoid WorldPrototype::tick(ThreadPool& threadPool) {\n\ttickWorldUnsynchronized(*this, threadPool);\n}\n\nvoid WorldPrototype::tick() {\n\tThreadPool singleThreadPool(1);\n\ttickWorldUnsynchronized(*this, singleThreadPool);\n}\n\nvoid tickWorldUnsynchronized(WorldPrototype& world, ThreadPool& threadPool) {\n\tphysicsMeasure.mark(PhysicsProcess::COLISSION_OTHER);\n\tfindColissionsParallel(world, world.curColissions, threadPool);\n\n\tphysicsMeasure.mark(PhysicsProcess::EXTERNALS);\n\tapplyExternalForces(world);\n\n\tphysicsMeasure.mark(PhysicsProcess::COLISSION_HANDLING);\n\thandleColissions(world.curColissions);\n\n\tphysicsMeasure.mark(PhysicsProcess::OTHER);\n\tintersectionStatistics.nextTally();\n\n\tphysicsMeasure.mark(PhysicsProcess::CONSTRAINTS);\n\thandleConstraints(world);\n\n\tphysicsMeasure.mark(PhysicsProcess::UPDATING);\n\tupdate(world);\n}\n\nvoid tickWorldSynchronized(WorldPrototype& world, ThreadPool& threadPool, UpgradeableMutex& worldMutex) {\n\tphysicsMeasure.mark(PhysicsProcess::WAIT_FOR_LOCK);\n\tworldMutex.lock_upgradeable();\n\n\tphysicsMeasure.mark(PhysicsProcess::COLISSION_OTHER);\n\tfindColissionsParallel(world, world.curColissions, threadPool);\n\n\tphysicsMeasure.mark(PhysicsProcess::EXTERNALS);\n\tapplyExternalForces(world);\n\n\tphysicsMeasure.mark(PhysicsProcess::COLISSION_HANDLING);\n\thandleColissions(world.curColissions);\n\n\tphysicsMeasure.mark(PhysicsProcess::OTHER);\n\tintersectionStatistics.nextTally();\n\n\tphysicsMeasure.mark(PhysicsProcess::CONSTRAINTS);\n\thandleConstraints(world);\n\n\tphysicsMeasure.mark(PhysicsProcess::WAIT_FOR_LOCK);\n\tworldMutex.upgrade();\n\n\tphysicsMeasure.mark(PhysicsProcess::UPDATING);\n\tupdate(world);\n\n\tphysicsMeasure.mark(PhysicsProcess::WAIT_FOR_LOCK);\n\tworldMutex.unlock();\n}\n\nvoid applyExternalForces(WorldPrototype& world) {\n\tfor(ExternalForce* force : world.externalForces) {\n\t\tforce->apply(&world);\n\t}\n}\n\nPartIntersection safeIntersects(const Part& p1, const Part& p2) {\n#ifdef CATCH_INTERSECTION_ERRORS\n\ttry {\n\t\treturn p1.intersects(p2);\n\t} catch(const std::exception& err) {\n\t\tDebug::logError(\"Error occurred during intersection: %s\", err.what());\n\n\t\tDebug::saveIntersectionError(p1, p2, \"colError\");\n\n\t\tthrow err;\n\t} catch(...) {\n\t\tDebug::logError(\"Unknown error occured during intersection\");\n\n\t\tDebug::saveIntersectionError(p1, p2, \"colError\");\n\n\t\tthrow \"exit\";\n\t}\n#else\n\treturn p1.intersects(p2);\n#endif\n}\n\nvoid refineColissions(std::vector<Colission>& colissions) {\n\tfor (size_t i = 0; i < colissions.size();) {\n\n\t\tColission& col = colissions[i];\n\n\t\tPartIntersection result = safeIntersects(*col.p1, *col.p2);\n\n\t\tif (result.intersects) {\n\n\t\t\tintersectionStatistics.addToTally(IntersectionResult::COLISSION, 1);\n\n\t\t\t// add extra information\n\t\t\tcol.intersection = result.intersection;\n\t\t\tcol.exitVector = result.exitVector;\n\n\t\t\ti++;\n\t\t}\n\t\telse {\n\n\t\t\tintersectionStatistics.addToTally(IntersectionResult::GJK_REJECT, 1);\n\n\t\t\tcol = std::move(colissions.back());\n\t\t\tcolissions.pop_back();\n\n\t\t}\n\t}\n}\n\nvoid parallelRefineColissions(ThreadPool& threadPool, std::vector<Colission>& colissions) {\n\tstd::vector<Colission> wantedColission;\n\tconst size_t workEnd = colissions.size();\n\tsize_t currIndex = 0;\n\tstd::mutex colissionMutex, statsMutex, indexMutex, vecMutex;\n\n\tthreadPool.doInParallel([&] {\n\t\twhile(true) {\n\n\t\t\tindexMutex.lock();\n\t\t\tsize_t claimedWork = currIndex;\n\t\t\tcurrIndex++;\n\t\t\tindexMutex.unlock();\n\n\t\t\tif(claimedWork >= workEnd) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tColission col = colissions[claimedWork];\n\t\t\tPartIntersection result = safeIntersects(*col.p1, *col.p2);\n\n\t\t\tif(result.intersects) {\n\n\t\t\t\tstatsMutex.lock();\n\t\t\t\tintersectionStatistics.addToTally(IntersectionResult::COLISSION, 1);\n\t\t\t\tstatsMutex.unlock();\n\n\n\t\t\t\t// add extra information\n\t\t\t\tcol.intersection = result.intersection;\n\t\t\t\tcol.exitVector = result.exitVector;\n\n\n\t\t\t\tvecMutex.lock();\n\t\t\t\twantedColission.push_back(col);\n\t\t\t\tvecMutex.unlock();\n\t\t\t} else {\n\n\t\t\t\tstatsMutex.lock();\n\t\t\t\tintersectionStatistics.addToTally(IntersectionResult::GJK_REJECT, 1);\n\t\t\t\tstatsMutex.unlock();\n\n\n\t\t\t}\n\t\t}\n\t});\n\tcolissions.swap(wantedColission);\n}\n\nvoid findColissions(WorldPrototype& world, ColissionBuffer& curColissions) {\n\tcurColissions.clear();\n\n\tfor(const ColissionLayer& layer : world.layers) {\n\t\tif(layer.collidesInternally) {\n\t\t\tlayer.getInternalColissions(curColissions);\n\t\t}\n\t}\n\n\tfor(std::pair<int, int> collidingLayers : world.colissionMask) {\n\t\tgetColissionsBetween(world.layers[collidingLayers.first], world.layers[collidingLayers.second], curColissions);\n\t}\n\n\trefineColissions(curColissions.freePartColissions);\n\trefineColissions(curColissions.freeTerrainColissions);\n}\n\nvoid findColissionsParallel(WorldPrototype& world, ColissionBuffer& curColissions, ThreadPool& threadPool) {\n\tcurColissions.clear();\n\n\tfor(const ColissionLayer& layer : world.layers) {\n\t\tif(layer.collidesInternally) {\n\t\t\tlayer.getInternalColissions(curColissions);\n\t\t}\n\t}\n\n\tfor(std::pair<int, int> collidingLayers : world.colissionMask) {\n\t\tgetColissionsBetween(world.layers[collidingLayers.first], world.layers[collidingLayers.second], curColissions);\n\t}\n\n\tparallelRefineColissions(threadPool, curColissions.freePartColissions);\n\tparallelRefineColissions(threadPool, curColissions.freeTerrainColissions);\n}\n\nvoid handleColissions(ColissionBuffer& curColissions) {\n\tfor(Colission c : curColissions.freePartColissions) {\n\t\thandleCollision(*c.p1, *c.p2, c.intersection, c.exitVector);\n\t}\n\tfor(Colission c : curColissions.freeTerrainColissions) {\n\t\thandleTerrainCollision(*c.p1, *c.p2, c.intersection, c.exitVector);\n\t}\n}\n\nvoid handleConstraints(WorldPrototype& world) {\n\tfor(const ConstraintGroup& group : world.constraints) {\n\t\tgroup.apply();\n\t}\n}\nvoid update(WorldPrototype& world) {\n\tfor(MotorizedPhysical* physical : world.physicals) {\n\t\tphysical->update(world.deltaT);\n\t}\n\n\tfor(ColissionLayer& layer : world.layers) {\n\t\tlayer.refresh();\n\t}\n\tworld.age++;\n\n\tfor(SoftLink* springLink : world.softLinks) {\n\t\tspringLink->update();\n\t}\n}\n\ndouble WorldPrototype::getTotalKineticEnergy() const {\n\tdouble total = 0.0;\n\tfor(const MotorizedPhysical* p : this->physicals) {\n\t\ttotal += p->getKineticEnergy();\n\t}\n\treturn total;\n}\ndouble WorldPrototype::getTotalPotentialEnergy() const {\n\tdouble total = 0.0;\n\tfor(ExternalForce* force : externalForces) {\n\t\ttotal += force->getTotalPotentialEnergyForThisForce(this);\n\t}\n\treturn total;\n}\ndouble WorldPrototype::getPotentialEnergyOfPhysical(const MotorizedPhysical& p) const {\n\tdouble total = 0.0;\n\tfor(ExternalForce* force : externalForces) {\n\t\ttotal += force->getPotentialEnergyForObject(this, p);\n\t}\n\treturn total;\n}\ndouble WorldPrototype::getTotalEnergy() const {\n\treturn getTotalKineticEnergy() + getTotalPotentialEnergy();\n}\n\nvoid WorldPrototype::addLink(SoftLink* link) {\n\tsoftLinks.push_back(link);\n}\n};"
  },
  {
    "path": "Physics3D/worldPhysics.h",
    "content": "#pragma once\n\n#include \"part.h\"\n#include \"math/linalg/vec.h\"\n#include \"math/position.h\"\n#include \"colissionBuffer.h\"\n#include \"world.h\"\n#include \"threading/threadPool.h\"\n#include \"threading/upgradeableMutex.h\"\n\nnamespace P3D {\nvoid handleCollision(Part& part1, Part& part2, Position collisionPoint, Vec3 exitVector);\nvoid handleTerrainCollision(Part& part1, Part& part2, Position collisionPoint, Vec3 exitVector);\nPartIntersection safeIntersects(const Part& p1, const Part& p2);\nvoid refineColissions(std::vector<Colission>& colissions);\nvoid parallelRefineColissions(ThreadPool& threadPool, std::vector<Colission>& colissions);\nvoid findColissions(WorldPrototype& world, ColissionBuffer& curColissions);\nvoid findColissionsParallel(WorldPrototype& world, ColissionBuffer& curColissions, ThreadPool& threadPool);\nvoid applyExternalForces(WorldPrototype& world);\nvoid handleColissions(ColissionBuffer& curColissions);\nvoid handleConstraints(WorldPrototype& world);\nvoid update(WorldPrototype& world);\n\nvoid tickWorldUnsynchronized(WorldPrototype& world, ThreadPool& threadPool);\nvoid tickWorldSynchronized(WorldPrototype& world, ThreadPool& threadPool, UpgradeableMutex& worldMutex);\n};\n\n"
  },
  {
    "path": "Physics3D.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.29403.142\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Physics3D\", \"Physics3D\\Physics3D.vcxproj\", \"{DC20CBAC-AB67-4A0C-BBE2-65DC81DEF289}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"application\", \"application\\application.vcxproj\", \"{4DB099FF-8264-4262-8195-EBA4109123CC}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{ADC11C63-6986-41DC-9297-FC5DC58A2B55} = {ADC11C63-6986-41DC-9297-FC5DC58A2B55}\n\t\t{60F3448D-6447-47CD-BF64-8762F8DB9361} = {60F3448D-6447-47CD-BF64-8762F8DB9361}\n\t\t{DC20CBAC-AB67-4A0C-BBE2-65DC81DEF289} = {DC20CBAC-AB67-4A0C-BBE2-65DC81DEF289}\n\t\t{13E417C8-0C80-482C-A415-8C11A5C770DA} = {13E417C8-0C80-482C-A415-8C11A5C770DA}\n\tEndProjectSection\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"util\", \"util\\util.vcxproj\", \"{60F3448D-6447-47CD-BF64-8762F8DB9361}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"benchmarks\", \"benchmarks\\benchmarks.vcxproj\", \"{CA5FECF4-EDD2-4387-9967-66B047052B0B}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{ADC11C63-6986-41DC-9297-FC5DC58A2B55} = {ADC11C63-6986-41DC-9297-FC5DC58A2B55}\n\t\t{60F3448D-6447-47CD-BF64-8762F8DB9361} = {60F3448D-6447-47CD-BF64-8762F8DB9361}\n\t\t{DC20CBAC-AB67-4A0C-BBE2-65DC81DEF289} = {DC20CBAC-AB67-4A0C-BBE2-65DC81DEF289}\n\t\t{13E417C8-0C80-482C-A415-8C11A5C770DA} = {13E417C8-0C80-482C-A415-8C11A5C770DA}\n\tEndProjectSection\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"engine\", \"engine\\engine.vcxproj\", \"{ADC11C63-6986-41DC-9297-FC5DC58A2B55}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{60F3448D-6447-47CD-BF64-8762F8DB9361} = {60F3448D-6447-47CD-BF64-8762F8DB9361}\n\t\t{DC20CBAC-AB67-4A0C-BBE2-65DC81DEF289} = {DC20CBAC-AB67-4A0C-BBE2-65DC81DEF289}\n\t\t{13E417C8-0C80-482C-A415-8C11A5C770DA} = {13E417C8-0C80-482C-A415-8C11A5C770DA}\n\tEndProjectSection\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"graphics\", \"graphics\\graphics.vcxproj\", \"{13E417C8-0C80-482C-A415-8C11A5C770DA}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{60F3448D-6447-47CD-BF64-8762F8DB9361} = {60F3448D-6447-47CD-BF64-8762F8DB9361}\n\t\t{DC20CBAC-AB67-4A0C-BBE2-65DC81DEF289} = {DC20CBAC-AB67-4A0C-BBE2-65DC81DEF289}\n\tEndProjectSection\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"tests\", \"tests\\tests.vcxproj\", \"{874CA9E0-23D2-4B91-837B-BCE8B7C9668D}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{ADC11C63-6986-41DC-9297-FC5DC58A2B55} = {ADC11C63-6986-41DC-9297-FC5DC58A2B55}\n\t\t{60F3448D-6447-47CD-BF64-8762F8DB9361} = {60F3448D-6447-47CD-BF64-8762F8DB9361}\n\t\t{DC20CBAC-AB67-4A0C-BBE2-65DC81DEF289} = {DC20CBAC-AB67-4A0C-BBE2-65DC81DEF289}\n\t\t{13E417C8-0C80-482C-A415-8C11A5C770DA} = {13E417C8-0C80-482C-A415-8C11A5C770DA}\n\t\t{4DB099FF-8264-4262-8195-EBA4109123CC} = {4DB099FF-8264-4262-8195-EBA4109123CC}\n\tEndProjectSection\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"examples\", \"examples\\examples.vcxproj\", \"{BBE4C27E-7EDA-4F07-A5A0-9103BFB4C47C}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{DC20CBAC-AB67-4A0C-BBE2-65DC81DEF289} = {DC20CBAC-AB67-4A0C-BBE2-65DC81DEF289}\n\tEndProjectSection\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|x64 = Debug|x64\n\t\tDebug|x86 = Debug|x86\n\t\tRelease|x64 = Release|x64\n\t\tRelease|x86 = Release|x86\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{DC20CBAC-AB67-4A0C-BBE2-65DC81DEF289}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{DC20CBAC-AB67-4A0C-BBE2-65DC81DEF289}.Debug|x64.Build.0 = Debug|x64\n\t\t{DC20CBAC-AB67-4A0C-BBE2-65DC81DEF289}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{DC20CBAC-AB67-4A0C-BBE2-65DC81DEF289}.Debug|x86.Build.0 = Debug|Win32\n\t\t{DC20CBAC-AB67-4A0C-BBE2-65DC81DEF289}.Release|x64.ActiveCfg = Release|x64\n\t\t{DC20CBAC-AB67-4A0C-BBE2-65DC81DEF289}.Release|x64.Build.0 = Release|x64\n\t\t{DC20CBAC-AB67-4A0C-BBE2-65DC81DEF289}.Release|x86.ActiveCfg = Release|Win32\n\t\t{DC20CBAC-AB67-4A0C-BBE2-65DC81DEF289}.Release|x86.Build.0 = Release|Win32\n\t\t{4DB099FF-8264-4262-8195-EBA4109123CC}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{4DB099FF-8264-4262-8195-EBA4109123CC}.Debug|x64.Build.0 = Debug|x64\n\t\t{4DB099FF-8264-4262-8195-EBA4109123CC}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{4DB099FF-8264-4262-8195-EBA4109123CC}.Debug|x86.Build.0 = Debug|Win32\n\t\t{4DB099FF-8264-4262-8195-EBA4109123CC}.Release|x64.ActiveCfg = Release|x64\n\t\t{4DB099FF-8264-4262-8195-EBA4109123CC}.Release|x64.Build.0 = Release|x64\n\t\t{4DB099FF-8264-4262-8195-EBA4109123CC}.Release|x86.ActiveCfg = Release|Win32\n\t\t{4DB099FF-8264-4262-8195-EBA4109123CC}.Release|x86.Build.0 = Release|Win32\n\t\t{60F3448D-6447-47CD-BF64-8762F8DB9361}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{60F3448D-6447-47CD-BF64-8762F8DB9361}.Debug|x64.Build.0 = Debug|x64\n\t\t{60F3448D-6447-47CD-BF64-8762F8DB9361}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{60F3448D-6447-47CD-BF64-8762F8DB9361}.Debug|x86.Build.0 = Debug|Win32\n\t\t{60F3448D-6447-47CD-BF64-8762F8DB9361}.Release|x64.ActiveCfg = Release|x64\n\t\t{60F3448D-6447-47CD-BF64-8762F8DB9361}.Release|x64.Build.0 = Release|x64\n\t\t{60F3448D-6447-47CD-BF64-8762F8DB9361}.Release|x86.ActiveCfg = Release|Win32\n\t\t{60F3448D-6447-47CD-BF64-8762F8DB9361}.Release|x86.Build.0 = Release|Win32\n\t\t{CA5FECF4-EDD2-4387-9967-66B047052B0B}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{CA5FECF4-EDD2-4387-9967-66B047052B0B}.Debug|x64.Build.0 = Debug|x64\n\t\t{CA5FECF4-EDD2-4387-9967-66B047052B0B}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{CA5FECF4-EDD2-4387-9967-66B047052B0B}.Debug|x86.Build.0 = Debug|Win32\n\t\t{CA5FECF4-EDD2-4387-9967-66B047052B0B}.Release|x64.ActiveCfg = Release|x64\n\t\t{CA5FECF4-EDD2-4387-9967-66B047052B0B}.Release|x64.Build.0 = Release|x64\n\t\t{CA5FECF4-EDD2-4387-9967-66B047052B0B}.Release|x86.ActiveCfg = Release|Win32\n\t\t{CA5FECF4-EDD2-4387-9967-66B047052B0B}.Release|x86.Build.0 = Release|Win32\n\t\t{ADC11C63-6986-41DC-9297-FC5DC58A2B55}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{ADC11C63-6986-41DC-9297-FC5DC58A2B55}.Debug|x64.Build.0 = Debug|x64\n\t\t{ADC11C63-6986-41DC-9297-FC5DC58A2B55}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{ADC11C63-6986-41DC-9297-FC5DC58A2B55}.Debug|x86.Build.0 = Debug|Win32\n\t\t{ADC11C63-6986-41DC-9297-FC5DC58A2B55}.Release|x64.ActiveCfg = Release|x64\n\t\t{ADC11C63-6986-41DC-9297-FC5DC58A2B55}.Release|x64.Build.0 = Release|x64\n\t\t{ADC11C63-6986-41DC-9297-FC5DC58A2B55}.Release|x86.ActiveCfg = Release|Win32\n\t\t{ADC11C63-6986-41DC-9297-FC5DC58A2B55}.Release|x86.Build.0 = Release|Win32\n\t\t{13E417C8-0C80-482C-A415-8C11A5C770DA}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{13E417C8-0C80-482C-A415-8C11A5C770DA}.Debug|x64.Build.0 = Debug|x64\n\t\t{13E417C8-0C80-482C-A415-8C11A5C770DA}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{13E417C8-0C80-482C-A415-8C11A5C770DA}.Debug|x86.Build.0 = Debug|Win32\n\t\t{13E417C8-0C80-482C-A415-8C11A5C770DA}.Release|x64.ActiveCfg = Release|x64\n\t\t{13E417C8-0C80-482C-A415-8C11A5C770DA}.Release|x64.Build.0 = Release|x64\n\t\t{13E417C8-0C80-482C-A415-8C11A5C770DA}.Release|x86.ActiveCfg = Release|Win32\n\t\t{13E417C8-0C80-482C-A415-8C11A5C770DA}.Release|x86.Build.0 = Release|Win32\n\t\t{874CA9E0-23D2-4B91-837B-BCE8B7C9668D}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{874CA9E0-23D2-4B91-837B-BCE8B7C9668D}.Debug|x64.Build.0 = Debug|x64\n\t\t{874CA9E0-23D2-4B91-837B-BCE8B7C9668D}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{874CA9E0-23D2-4B91-837B-BCE8B7C9668D}.Debug|x86.Build.0 = Debug|Win32\n\t\t{874CA9E0-23D2-4B91-837B-BCE8B7C9668D}.Release|x64.ActiveCfg = Release|x64\n\t\t{874CA9E0-23D2-4B91-837B-BCE8B7C9668D}.Release|x64.Build.0 = Release|x64\n\t\t{874CA9E0-23D2-4B91-837B-BCE8B7C9668D}.Release|x86.ActiveCfg = Release|Win32\n\t\t{874CA9E0-23D2-4B91-837B-BCE8B7C9668D}.Release|x86.Build.0 = Release|Win32\n\t\t{BBE4C27E-7EDA-4F07-A5A0-9103BFB4C47C}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{BBE4C27E-7EDA-4F07-A5A0-9103BFB4C47C}.Debug|x64.Build.0 = Debug|x64\n\t\t{BBE4C27E-7EDA-4F07-A5A0-9103BFB4C47C}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{BBE4C27E-7EDA-4F07-A5A0-9103BFB4C47C}.Debug|x86.Build.0 = Debug|Win32\n\t\t{BBE4C27E-7EDA-4F07-A5A0-9103BFB4C47C}.Release|x64.ActiveCfg = Release|x64\n\t\t{BBE4C27E-7EDA-4F07-A5A0-9103BFB4C47C}.Release|x64.Build.0 = Release|x64\n\t\t{BBE4C27E-7EDA-4F07-A5A0-9103BFB4C47C}.Release|x86.ActiveCfg = Release|Win32\n\t\t{BBE4C27E-7EDA-4F07-A5A0-9103BFB4C47C}.Release|x86.Build.0 = Release|Win32\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {D9298BAF-A6CD-4B96-BF4B-DFB2F3FBAF00}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "README.md",
    "content": "# Physics3D\n![Ubuntu CI Badge](https://github.com/ThePhysicsGuys/Physics3D/workflows/Ubuntu/badge.svg)\n![MSVC CI Badge](https://github.com/ThePhysicsGuys/Physics3D/workflows/MSVC/badge.svg)\n\nA 3D physics engine, written in C++\n\n![Different Shapes](pictures/frontPage.png)\n[Imgur Library with the history of the engine](https://imgur.com/a/history-of-physics3d-engine-JrVHmMI)\nOther images can be found in [pictures/](pictures/)\n\n## Project structure\nThe Physics3D project consists of 7 projects, each with its own role:\n- The [Physics3D](/Physics3D) project contains the physics engine can be compiled separately.\n- The [graphics](/graphics) project contains all the logic to interact with OpenGL, visual debugging and gui code.\n- The [engine](/engine) project contains general concepts that can be applied in multiple environments like a layer systems and an event system.\n- The [util](/util) project contains code that can be used in all project, like logging, utilities and resource management.\n- The [application](/application) project contains an executable example application for visualizing, debugging and testing the physics engine. This project depends on the engine, graphics and physics project. Every project, including the physics project depends on util. \n- The [tests](/tests) project contains an executable with unit test for the physics engine.\n- The [benchmarks](/benchmarks) project contains an executable with benchmarks to evaluate the physics engine's performance.\n- [examples](/examples) contains minimal examples on how to use the library. These include a bare bones graphics implementation. \n\n## Dependencies\n### Application & engine & graphics\n- [GLFW](https://www.glfw.org/) Verified working with GLFW 3.2.1\n- [GLEW](http://glew.sourceforge.net/) Verified with GLEW 2.1.0\n- [stb_image](https://github.com/nothings/stb) Verified with stb_image.h v2.22\n- [FreeType](https://www.freetype.org/) Verified with FreeType v2.9.0\n- [Dear ImGui](https://github.com/ocornut/imgui/tree/docking) Verified with ImGui v1.77. Make sure to grab the files from the experimental docking branch.\n- some OpenGL functionality may not be available on virtual machines, enabling 3D acceleration might solve this\n\n## Setup Guide\n\n### CMake\nIf you suddenly can't build the project anymore after pulling, perhaps one of the dependencies has changed. Try running [install/clean.sh](/install/clean.sh) (Unix) or [install/clean.bat](/install/clean.bat) (Windows) and rerun the setup script in the steps below. \n\nIf you still have build problems, please create an issue as we want setting up to be as easy as possible. \n\n#### Platform independent using vcpkg\n1. Clone the repository\n2. If you do not have cmake already: download it from [cmake.org/download/](https://cmake.org/download/)\n3. Run [install/setup.sh](/install/setup.sh) (Unix) or [install/setup.bat](/install/setup.bat) (Windows) from the Physics3D directory, this will install the necessary dependencies using [vcpkg](https://github.com/microsoft/vcpkg) and create the build folders. It will also run cmake for debug and release. \n  The dependencies can be installed on their own with [install/setupDependencies.sh](/install/setupDependencies.sh) (Unix) or [install/setupDependencies.bat](/install/setupDependencies.bat) (Windows)\n  The build directories can be generated on their own with [install/setupBuild.sh](/install/setupBuild.sh) (Unix) or [install/setupBuild.bat](/install/setupBuild.bat) (Windows)\n4. Make the build from the build directory `cd build` with `cmake --build .`. To speed up the build, multithreaded building can be enabled by addding `--parallel` or `-- -j 5` to the end of the build command.\n5. To run the application, you must also run it from the build directory: `cd build` `Debug\\.\\application`. Tests and benchmarks can be run from anywhere. \n\n#### Ubuntu specific using apt-get\nIf you are using Ubuntu, we recommend using this installation method instead, as setting up using vcpkg can take a very long time. This method should get you a working version of the engine starting from a clean Ubuntu 18.04. \n\n1. Clone the repository\n2. Run [install/setupUbuntu.sh](/install/setupUbuntu.sh) from the Physics3D directory, this will install the necessary dependencies and create the build folders. It will also run cmake for debug and release. \n  The dependencies can be installed on their own with [install/setupDependenciesUbuntu.sh](/install/setupDependenciesUbuntu.sh)\n  The build directories can be generated on their own with [install/setupBuildUbuntu.sh](/install/setupBuildUbuntu.sh)\n3. Make the build from the build directory `cd build` with `cmake --build .`. To speed up the build, multithreaded building can be enabled by addding `--parallel` or `-- -j 5` to the end of the build command.\n4. To run the application, you must also run it from the build directory: `./application`. Tests and benchmarks can be run from anywhere. \n\n### Visual Studio\n1. Clone the repository\n2. The physics project on its own does not depend on any libraries, so if you wish to only build it then you may skip step 3.\n3. Download the dependencies, the Visual Studio configuration expects the libraries to be stored in Physics3D/lib/, includes should be stored in Physics3D/include/, with Physics3D/ the root folder of the git project. \n  Your project structure should look like this:  \n  Physics3D/  \n  | - include/  \n  | | - freetype/  \n  | | | - (freetype headers)  \n  | | - GL  \n  | | | - (glew headers)  \n  | | - GLFW/  \n  | | | - (glfw3 headers)  \n  | | - imgui/  \n  | | | - imconfig.h  \n  | | | - imgui.h & .cpp  \n  | | | - imgui_draw.h  \n  | | | - imgui_internal.h  \n  | | | - imgui_widgets.cpp  \n  | | | - imgui_rectpack.h  \n  | | | - imgui_textedit.h  \n  | | | - imgui_truetype.h  \n  | | | - imgui_impl_glfw.h & .cpp  \n  | | | - imgui_impl_opengl3.h & .cpp  \n  | | - stb_image.h  \n  | | - ft2build.h  \n  | - lib/  \n  | | - freetype.lib  \n  | | - glew32.lib  \n  | | - glew32s.lib  \n  | | - glfw3.lib   \n  | - (Project and other files)  \n4. The configuration should already be configured in the provided project and solution files\n5. You are done!\n\n## Authors\n* **Lennart Van Hirtum** - [VonTum](https://github.com/VonTum)\n* **Matthias Vandersanden** - [olympus112](https://github.com/olympus112)\n\nThis list is inconclusive as new contributors are always welcome! \n\n## License\nThis project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details\n"
  },
  {
    "path": "_config.yml",
    "content": "theme: jekyll-theme-cayman"
  },
  {
    "path": "application/application.cpp",
    "content": "#include \"core.h\"\n\n#include \"application.h\"\n\n#include <thread>\n#include <chrono>\n#include <iostream>\n#include <fstream>\n#include <filesystem>\n\n#include \"view/screen.h\"\n#include \"ecs/entityBuilder.h\"\n#include \"input/standardInputHandler.h\"\n#include \"ecs/components.h\"\n#include \"../graphics/texture.h\"\n#include \"../graphics/ecs/components.h\"\n#include \"../graphics/debug/guiDebug.h\"\n#include \"../graphics/debug/visualDebug.h\"\n#include <Physics3D/geometry/shapeCreation.h>\n#include <Physics3D/math/linalg/commonMatrices.h>\n#include <Physics3D/part.h>\n#include <Physics3D/world.h>\n#include <Physics3D/externalforces/directionalGravity.h>\n#include <Physics3D/misc/physicsProfiler.h>\n#include <Physics3D/hardconstraints/motorConstraint.h>\n#include <Physics3D/hardconstraints/sinusoidalPistonConstraint.h>\n#include <Physics3D/hardconstraints/fixedConstraint.h>\n#include <Physics3D/constraints/ballConstraint.h>\n#include <Physics3D/constraints/hingeConstraint.h>\n#include <Physics3D/constraints/barConstraint.h>\n#include <Physics3D/softlinks/elasticLink.h>\n\n#include <Physics3D/misc/serialization/serialization.h>\n#include <Physics3D/threading/physicsThread.h>\n\n#include \"worlds.h\"\n#include \"worldBuilder.h\"\n\n#include \"io/serialization.h\"\n#include \"io/saveDialog.h\"\n\n#include \"../util/parseCPUIDArgs.h\"\n#include \"../util/cmdParser.h\"\n#include \"../graphics/meshRegistry.h\"\n#include \"../engine/event/keyEvent.h\"\n#include \"../engine/input/keyboard.h\"\n#include \"../engine/event/windowEvent.h\"\n\n#include \"../util/stringUtil.h\"\n\n#include <Physics3D/misc/toString.h>\n\n#include \"builtinWorlds.h\"\n#include \"engine/resource/meshResource.h\"\n#include \"graphics/ecs/materials.h\"\n#include \"graphics/resource/textureResource.h\"\n#include \"util/resource/resourceManager.h\"\n\n\n#define TICKS_PER_SECOND 120.0\n#define TICK_SKIP_TIME std::chrono::milliseconds(1000)\n\nnamespace P3D::Application {\n\nPlayerWorld world(1 / TICKS_PER_SECOND);\nUpgradeableMutex worldMutex;\nPhysicsThread physicsThread(&world, &worldMutex, Graphics::AppDebug::logTickEnd, TICK_SKIP_TIME);\nScreen screen;\n\nvoid init(const ::Util::ParsedArgs& cmdArgs);\nvoid setupWorld(const ::Util::ParsedArgs& cmdArgs);\nvoid setupGL();\nvoid setupDebug();\n\nvoid loadFile(const char* file);\n\nvoid init(const ::Util::ParsedArgs& cmdArgs) {\n\tauto start = std::chrono::high_resolution_clock::now();\n\n\tLog::init(\"latest.log\");\n\n\tLog::info(::Util::printAndParseCPUIDArgs(cmdArgs));\n\tbool quickBoot = cmdArgs.hasFlag(\"quickBoot\");\n\n\tsetupGL();\n\n\tLog::info(\"Init MeshRegistry\");\n\tGraphics::MeshRegistry::init();\n\n\t/*ResourceManager::add<Graphics::TextureResource>(\"floorMaterial\", \"../res/textures/floor/floor_color.jpg\");\n\tWorldImportExport::registerTexture(ResourceManager::get<Graphics::TextureResource>(\"floorMaterial\"));*/\n\n\tLog::info(\"Initializing world\");\n\tWorldBuilder::init();\n\n\tif(cmdArgs.argCount() >= 1) {\n\t\tloadFile(cmdArgs[0].c_str());\n\t} else {\n\t\tLog::info(\"Creating default world\");\n\t\tsetupWorld(cmdArgs);\n\t}\n\n\tLog::info(\"Initializing screen\");\n\tscreen.onInit(quickBoot);\n\t\n\tif(!world.isValid()) {\n\t\tthrow \"World not valid!\";\n\t}\n\n\tLog::info(\"Initializing debug\");\n\tsetupDebug();\n\n\tauto stop = std::chrono::high_resolution_clock::now();\n\tauto duration = std::chrono::duration_cast<std::chrono::milliseconds>(stop - start);\n\tLog::info(\"Init Physics3D in %.4f ms\", duration.count() / 1.0f);\n}\n\nvoid setupGL() {\n\tLog::info(\"Initializing GLFW\");\n\tif (!initGLFW()) {\n\t\tLog::error(\"GLFW not initialised\");\n\t\tstd::cin.get();\n\t\tstop(-1);\n\t}\n\n\tnew(&screen) Screen(1800, 900, &world, &worldMutex);\n\n\tLog::info(\"Initializing GLEW\");\n\tif (!initGLEW()) {\n\t\tLog::error(\"GLEW not initialised\");\n\t\tstd::cin.get();\n\t\tstop(-1);\n\t}\n\n\tstd::filesystem::copy_file(\"../res/default_imgui.ini\", \"../res/imgui.ini\", std::filesystem::copy_options::skip_existing);\n}\n\nvoid setupWorld(const ::Util::ParsedArgs& cmdArgs) {\n\tLog::info(\"Initializing world\");\n\n\tworld.addExternalForce(new DirectionalGravity(Vec3(0, -10.0, 0.0)));\n\n\t//buildFloorWorld(screen, world); return;\n\t//buildBallWorld(screen, world); return;\n\t//buildDebugWorld(screen, world); return;\n\t//buildShowcaseWorld(screen, world); return;\n\tbuildBoxWorld(screen, world); return;\n\n\tPartProperties basicProperties{1.0, 0.7, 0.3};\n\n\tWorldBuilder::buildFloorAndWalls(50.0, 50.0, 1.0);\n\t\n\tGlobalCFrame origin(0.0, 5.0, 0.0, Rotation::fromEulerAngles(-3.14 / 4, 3.14 / 4, 0.0));\n\n\t// Load textures\n\tGraphics::TextureResource* wallAlbedo = ResourceManager::add<Graphics::TextureResource>(\"wall albedo\", \"../res/textures/wall/wall_color.jpg\");\n\tGraphics::TextureResource* wallNormal = ResourceManager::add<Graphics::TextureResource>(\"wall normal\", \"../res/textures/wall/wall_normal.jpg\");\n\twallAlbedo->generateMipmap();\n\twallNormal->generateMipmap();\n\n\tint n = 3;\n\tfor(int x = 0; x < n; x++) {\n\t\tfor(int y = 0; y < n; y++) {\n\t\t\tfor(int z = 0; z < n; z++) {\n\t\t\t\tGlobalCFrame cf = origin.localToGlobal(CFrame(x, y, z));\n\t\t\t\tstd::string name = \"part \" + std::to_string((x * n + y) * n + z);\n\t\t\t\tExtendedPart* part = new ExtendedPart(boxShape(0.5, 0.5, 0.5), cf, basicProperties, name);\n\n\t\t\t\tIRef<Graphics::Comp::Material> material = screen.registry.add<Graphics::Comp::Material>(part->entity, Graphics::Materials::GREEN);\n\t\t\t\tmaterial->set(Graphics::Comp::Material::Map_Albedo, SRef<Graphics::Texture>(wallAlbedo));\n\t\t\t\tmaterial->set(Graphics::Comp::Material::Map_Normal, SRef<Graphics::Texture>(wallNormal));\n\n\t\t\t\tworld.addPart(part);\n\t\t\t}\n\t\t}\n\t}\n\t\n\t{\n\t\tExtendedPart* partA = new ExtendedPart(boxShape(1.0, 0.49, 3.0), GlobalCFrame(3.0, 3.0, 0.0), {1.0, 1.0, 1.0}, \"partA\");\n\t\tExtendedPart* partB = new ExtendedPart(boxShape(1.0, 0.5, 3.0), GlobalCFrame(2.0, 3.0, 0.0), {1.0, 1.0, 1.0}, \"partB\");\n\t\tscreen.registry.add<Graphics::Comp::Material>(partA->entity, Graphics::Materials::GOLD);\n\t\tscreen.registry.add<Graphics::Comp::Material>(partB->entity, Graphics::Materials::SILVER);\n\t\tworld.addPart(partA);\n\t\tpartA->attach(partB, CFrame(0.0, 1.0, 0.0));\n\t}\n\t{\n\t\tExtendedPart* partA = new ExtendedPart(boxShape(1.0, 0.49, 3.0), GlobalCFrame(-3.0, 3.0, 0.0), {1.0, 1.0, 1.0}, \"partA\");\n\t\tExtendedPart* partB = new ExtendedPart(boxShape(1.0, 0.5, 3.0), GlobalCFrame(-2.0, 3.0, 0.0), {1.0, 1.0, 1.0}, \"partB\");\n\t\tscreen.registry.add<Graphics::Comp::Material>(partA->entity, Graphics::Materials::RED);\n\t\tscreen.registry.add<Graphics::Comp::Material>(partB->entity, Graphics::Materials::BLUE);\n\t\tworld.addPart(partA);\n\t\tpartA->attach(partB, new MotorConstraintTemplate<ConstantMotorTurner>(0.5), CFrame(0.0, 1.0, 0.0), CFrame(1.0, 0.0, 0.0));\n\t}\n\t\n\t// Lights\n\t{\n\t\tComp::Light::Attenuation attenuation = {1, 1, 1};\n\t\tauto lights = EntityBuilder(screen.registry).name(\"Lights\").get();\n\t\tauto sphereData = Graphics::MeshRegistry::getMesh(&SphereClass::instance);\n\t\tEntityBuilder(screen.registry).parent(lights).transform(Position(10, 5, -10), 0.2).light(Graphics::Color(1, 0.84f, 0.69f), 300, attenuation).hitbox(sphereShape(1.0)).mesh(sphereData);\n\t\tEntityBuilder(screen.registry).parent(lights).transform(Position(10, 5, 10), 0.2).light(Graphics::Color(1, 0.84f, 0.69f), 300, attenuation).hitbox(sphereShape(1.0)).mesh(sphereData);\n\t\tEntityBuilder(screen.registry).parent(lights).transform(Position(-10, 5, -10), 0.2).light(Graphics::Color(1, 0.84f, 0.69f), 200, attenuation).hitbox(sphereShape(1.0)).mesh(sphereData);\n\t\tEntityBuilder(screen.registry).parent(lights).transform(Position(-10, 5, 10), 0.2).light(Graphics::Color(1, 0.84f, 0.69f), 500, attenuation).hitbox(sphereShape(1.0)).mesh(sphereData);\n\t\tEntityBuilder(screen.registry).parent(lights).transform(Position(0, 5, 0), 0.2).light(Graphics::Color(1, 0.90f, 0.75f), 400, attenuation).hitbox(sphereShape(1.0)).mesh(sphereData);\n\t}\n\t{\n\t\tExtendedPart* cornerPart = new ExtendedPart(cornerShape(2.0, 2.0, 2.0), GlobalCFrame(3.0, 3.0, -5.0), {1.0, 1.0, 1.0}, \"CORNER\");\n\t\tExtendedPart* wedgePart = new ExtendedPart(wedgeShape(2.0, 2.0, 2.0), GlobalCFrame(-3.0, 3.0, -5.0), {1.0, 1.0, 1.0}, \"WEDGE\");\n\t\tscreen.registry.add<Graphics::Comp::Material>(cornerPart->entity, Graphics::Materials::metalDiffuse(Graphics::Colors::ACCENT));\n\t\tscreen.registry.add<Graphics::Comp::Material>(wedgePart->entity, Graphics::Materials::metalNoReflection(Graphics::Colors::FUCHSIA));\n\t\tworld.addPart(cornerPart);\n\t\tworld.addPart(wedgePart);\n\t}\n\n\t{\n\t\tExtendedPart* partA = new ExtendedPart(boxShape(1.0, 0.49, 3.0), GlobalCFrame(3.0, 3.0, 0.0), {1.0, 1.0, 1.0}, \"partA\");\n\t\tExtendedPart* partB = new ExtendedPart(boxShape(1.0, 0.5, 3.0), GlobalCFrame(2.0, 3.0, 0.0), {1.0, 1.0, 1.0}, \"partB\");\n\t\tEntityBuilder(screen.registry, partA->entity).light(Graphics::Color(0.1f, 0.94f, 0.49f), 500, Comp::Light::Attenuation{0.8, 0.5, 0.2});\n\n\t\tworld.addPart(partA);\n\t\tworld.addPart(partB);\n\n\t\t//world.addLink(new SpringLink({ CFrame{1.0, 0.0, 0.0}, partA }, { CFrame{0.0, 0.0, 0.0}, partB }, 5.0, 5.0));\n\t\tworld.addLink(new ElasticLink({CFrame{1.0, 0.0, 0.0}, partA}, {CFrame{0.0, 0.0, 0.0}, partB}, 5.0, 5.0));\n\t}\n\n\t{\n\t\tExtendedPart* partA = new ExtendedPart(boxShape(1.0, 0.49, 1.0), GlobalCFrame(12.0, 3.0, 0.0), {1.0, 1.0, 1.0}, \"partA\");\n\t\tExtendedPart* partB = new ExtendedPart(boxShape(1.0, 0.5, 1.0), GlobalCFrame(14.0, 3.0, 0.0), {1.0, 1.0, 1.0}, \"partB\");\n\t\tExtendedPart* partC = new ExtendedPart(boxShape(1.0, 0.5, 1.0), GlobalCFrame(16.0, 3.0, 0.0), {1.0, 1.0, 1.0}, \"partC\");\n\n\t\tConstraintGroup cg;\n\t\tcg.add(partA, partB, new BarConstraint(Vec3(0.5, 0.0, 0.0), Vec3(-0.5, 0.0, 0.0), 1.0));\n\t\tcg.add(partB, partC, new BallConstraint(Vec3(1, 0.0, 0.0), Vec3(-1, 0.0, 0.0)));\n\t\tcg.add(partC, partA, new HingeConstraint(Vec3(-2, 2.0, 0.0), Vec3(0,0,1), Vec3(2, 2.0, 0.0), Vec3(0, 0, 1)));\n\t\tworld.constraints.push_back(cg);\n\t\tworld.addPart(partA);\n\t\tworld.addPart(partB);\n\t\tworld.addPart(partC);\n\t}\n\n\tExtendedPart* tetrahedron = new ExtendedPart(polyhedronShape(ShapeLibrary::tetrahedron), GlobalCFrame(-7.0, 3.0, 6.0), WorldBuilder::basicProperties);\n\tExtendedPart* octahedron = new ExtendedPart(polyhedronShape(ShapeLibrary::octahedron), GlobalCFrame(-7.0, 3.0, 8.0), WorldBuilder::basicProperties);\n\tExtendedPart* icosahedron = new ExtendedPart(polyhedronShape(ShapeLibrary::icosahedron), GlobalCFrame(-7.0, 3.0, 10.0), WorldBuilder::basicProperties);\n\n\tworld.addPart(tetrahedron);\n\tworld.addPart(octahedron);\n\tworld.addPart(icosahedron);\n\n\t//world.addLink(new MagneticLink({ CFrame{1.0, 0.0, 0.0}, partA }, { CFrame{0.0, 0.0, 0.0}, partB }, +8.0));\n\t//world.addLink(new AlignmentLink({ CFrame{1.0, 0.0, 0.0}, partA}, { CFrame{0.0, 0.0, 0.0}, partB }));\n\t//return;\n\t\n\tExtendedPart* partA = new ExtendedPart(boxShape(5.0, 10.0, 5.0), GlobalCFrame(0.0, 6.0, -10.0), WorldBuilder::basicProperties);\n\tExtendedPart* partB = new ExtendedPart(sphereShape(0.45), GlobalCFrame(8.0, 6.0, -10.0), WorldBuilder::basicProperties);\n\tExtendedPart* partC = new ExtendedPart(boxShape(0.9, 0.15, 0.15), GlobalCFrame(9.0, 6.0, -10.0), WorldBuilder::basicProperties);\n\tExtendedPart* partD = new ExtendedPart(boxShape(0.9, 0.15, 0.15), GlobalCFrame(10.0, 6.0, -10.0), WorldBuilder::basicProperties);\n\tExtendedPart* partE = new ExtendedPart(cylinderShape(0.3, 1.3), GlobalCFrame(11.0, 6.0, -10.0), WorldBuilder::basicProperties);\n\n\tworld.createLayer(false, true);\n\n\tworld.addPart(partA, 1);\n\tworld.addPart(partB, 1);\n\tworld.addPart(partC, 1);\n\tworld.addPart(partD, 1);\n\tworld.addPart(partE, 1);\n\n\tConstraintGroup cg;\n\tcg.add(partA, partB, new BallConstraint(Vec3(7.0, 0.0, 0.0), Vec3(-1.0, 0.0, 0.0)));\n\tcg.add(partB, partC, new BallConstraint(Vec3(0.5, 0.0, 0.0), Vec3(-0.5, 0.0, 0.0)));\n\tcg.add(partC, partD, new BallConstraint(Vec3(0.5, 0.0, 0.0), Vec3(-0.5, 0.0, 0.0)));\n\tcg.add(partD, partE, new BallConstraint(Vec3(0.5, 0.0, 0.0), Vec3(-0.5, 0.0, 0.0)));\n\tworld.constraints.push_back(std::move(cg));\n}\n\nvoid setupDebug() {\n\tGraphics::AppDebug::setupDebugHooks();\n}\n\nvoid loadFile(const char* file) {\n\tLog::info(\"Loading file %s\", file);\n\tauto startTime = std::chrono::high_resolution_clock::now();\n\tif(::Util::endsWith(file, \".parts\")) {\n\t\tWorldImportExport::loadLoosePartsIntoWorld(file, world);\n\t} else if(::Util::endsWith(file, \".nativeParts\")) {\n\t\tWorldImportExport::loadNativePartsIntoWorld(file, world);\n\t} else if(::Util::endsWith(file, \".world\")) {\n\t\tWorldImportExport::loadWorld(file, world);\n\t}\n\tstd::chrono::nanoseconds deltaTime = std::chrono::high_resolution_clock::now() - startTime;\n\tLog::info(\"File loaded, took %.4f ms\", deltaTime.count() / 1E6);\n}\n\nbool onFileDrop(Engine::WindowDropEvent& event) {\n\tloadFile(event.getPath().c_str());\n\n\treturn true;\n}\n\nbool onKeyPress(Engine::KeyPressEvent& keyEvent) {\n\tusing namespace Engine;\n\n\tKey pressedKey = keyEvent.getKey();\n\tif(pressedKey == Keyboard::KEY_S && keyEvent.getModifiers().isCtrlPressed()) {\n\t\thandler->setKey(Keyboard::KEY_S, false);\n\t\tchar pathBuffer[MAX_PATH_LENGTH];\n\t\tif(saveWorldDialog(pathBuffer)) {\n\t\t\tLog::info(\"Saving world to: %s\", pathBuffer);\n\t\t\tstd::unique_lock<UpgradeableMutex>(worldMutex);\n\t\t\tWorldImportExport::saveWorld(pathBuffer, world);\n\t\t}\n\t\treturn true;\n\t} else if(pressedKey == Keyboard::KEY_O && keyEvent.getModifiers().isCtrlPressed()) {\n\t\thandler->setKey(Keyboard::KEY_O, false);\n\t\tchar pathBuffer[MAX_PATH_LENGTH];\n\t\tif(openWorldDialog(pathBuffer)) {\n\t\t\tLog::info(\"Opening world: %s\", pathBuffer);\n\t\t\tstd::unique_lock<UpgradeableMutex>(worldMutex);\n\t\t\tWorldImportExport::loadWorld(pathBuffer, world);\n\t\t}\n\t\treturn true;\n\t} else {\n\t\treturn false;\n\t}\n}\n\nvoid onEvent(Engine::Event& event) {\n\tusing namespace Engine;\n\n\tscreen.onEvent(event);\n\n\tEventDispatcher dispatcher(event);\n\tdispatcher.dispatch<WindowDropEvent>(onFileDrop);\n\tdispatcher.dispatch<KeyPressEvent>(onKeyPress);\n}\n\nvoid stop(int returnCode) {\n\tLog::info(\"Closing physics\");\n\tphysicsThread.stop();\n\n\tLog::info(\"Closing screen\");\n\tscreen.onClose();\n\n\tLog::stop();\n\texit(returnCode);\n}\n\n\n// Ticks\nvoid togglePause() {\n\tphysicsThread.toggleRunning();\n}\n\nvoid pause() {\n\tphysicsThread.stop();\n}\n\nvoid unpause() {\n\tphysicsThread.start();\n}\n\nbool isPaused() {\n\treturn !physicsThread.isRunning();\n}\n\nvoid setSpeed(double newSpeed) {\n\tphysicsThread.speed = newSpeed;\n}\n\ndouble getSpeed() {\n\treturn physicsThread.speed;\n}\n\nvoid runTick() {\n\tphysicsThread.runTick();\n}\n\nvoid toggleFlying() {\n\t// Through using syncModification, we ensure that the creation or deletion of the player shape is not handled by the physics thread, thus avoiding a race condition with the Registry\n\t// TODO this is not a proper solution, it should be an asyncModification! But at least it fixes the sporadic crash\n\tstd::unique_lock<UpgradeableMutex> worldLock(worldMutex);\n\tif (screen.camera.flying) {\n\t\tLog::info(\"Creating player\");\n\t\tscreen.camera.flying = false;\n\t\t// this modifies Registry, which may or may not be a race condition\n\t\tscreen.camera.attachment = new ExtendedPart(polyhedronShape(ShapeLibrary::createPrism(50, 0.3f, 1.5f)), GlobalCFrame(screen.camera.cframe.getPosition()), {1.0, 5.0, 0.0}, \"Player\");\n\t\tscreen.world->addPart(screen.camera.attachment);\n\t} else {\n\t\tLog::info(\"Destroying player\");\n\t\tdelete screen.camera.attachment;\n\t\tscreen.camera.flying = true;\n\t}\n}\n}; // namespace P3D::Application\n\nint main(int argc, const char** args) {\n\tusing namespace P3D::Application;\n\tusing namespace P3D::Graphics;\n\n\tUtil::ParsedArgs inputArgs(argc, args);\n\n\tinit(inputArgs);\n\n\tLog::info(\"Started rendering\");\n\twhile (!screen.shouldClose()) {\n\t\tgraphicsMeasure.mark(GraphicsProcess::UPDATE);\n\n\t\tscreen.onUpdate();\n\t\tscreen.onRender();\n\n\t\tgraphicsMeasure.end();\n\t}\n\n\tLog::info(\"Closing by screen.shouldClose()\");\n\n\tstop(0);\n}"
  },
  {
    "path": "application/application.h",
    "content": "#pragma once\n\n#include <Physics3D/threading/upgradeableMutex.h>\n\nnamespace P3D::Engine {\nstruct Event;\n};\n\nnamespace P3D::Application {\n\nclass Screen;\nclass PlayerWorld;\n\nextern PlayerWorld world;\nextern UpgradeableMutex worldMutex;\nextern Screen screen;\n\nvoid pause();\nvoid unpause();\nbool isPaused();\nvoid togglePause();\nvoid runTick();\nvoid setSpeed(double newSpeed);\ndouble getSpeed();\nvoid stop(int returnCode);\nvoid toggleFlying();\nvoid onEvent(Engine::Event& event);\n\n};"
  },
  {
    "path": "application/application.rc",
    "content": "// Microsoft Visual C++ generated resource script.\r\n//\r\n#pragma code_page(65001)\r\n\r\n#include \"resource.h\"\r\n\r\n#define APSTUDIO_READONLY_SYMBOLS\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// Generated from the TEXTINCLUDE 2 resource.\r\n//\r\n#include \"winres.h\"\r\n\r\n/////////////////////////////////////////////////////////////////////////////\r\n#undef APSTUDIO_READONLY_SYMBOLS\r\n\r\n/////////////////////////////////////////////////////////////////////////////\r\n// English (United States) resources\r\n\r\n#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\nLANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r\n\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// SHADER\r\n//\r\n\r\nIDR_SHADER1             SHADER                  \"..\\\\res\\\\shaders\\\\basic.shader\"\r\n\r\nIDR_SHADER2             SHADER                  \"..\\\\res\\\\shaders\\\\vector.shader\"\r\n\r\nIDR_SHADER3             SHADER                  \"..\\\\res\\\\shaders\\\\origin.shader\"\r\n\r\nIDR_SHADER4             SHADER                  \"..\\\\res\\\\shaders\\\\font.shader\"\r\n\r\nIDR_SHADER5             SHADER                  \"..\\\\res\\\\shaders\\\\depth.shader\"\r\n\r\nIDR_SHADER6             SHADER                  \"..\\\\res\\\\shaders\\\\quad.shader\"\r\n\r\nIDR_SHADER7             SHADER                  \"..\\\\res\\\\shaders\\\\postprocess.shader\"\r\n\r\nIDR_SHADER8             SHADER                  \"..\\\\res\\\\shaders\\\\skybox.shader\"\r\n\r\nIDR_SHADER9             SHADER                  \"..\\\\res\\\\shaders\\\\mask.shader\"\r\n\r\nIDR_SHADER10            SHADER                  \"..\\\\res\\\\shaders\\\\point.shader\"\r\n\r\nIDR_SHADER11            SHADER                  \"..\\\\res\\\\shaders\\\\test.shader\"\r\n\r\nIDR_SHADER12            SHADER                  \"..\\\\res\\\\shaders\\\\blur.shader\"\r\n\r\nIDR_SHADER13            SHADER                  \"..\\\\res\\\\shaders\\\\line.shader\"\r\n\r\nIDR_SHADER14            SHADER                  \"..\\\\res\\\\shaders\\\\instance.shader\"\r\n\r\nIDR_SHADER15            SHADER                  \"..\\\\res\\\\shaders\\\\sky.shader\"\r\n\r\nIDR_SHADER16            SHADER                  \"..\\\\res\\\\shaders\\\\lighting.shader\"\r\n\r\nIDR_SHADER17            SHADER                  \"..\\\\res\\\\shaders\\\\debug.shader\"\r\n\r\nIDR_SHADER18            SHADER                  \"..\\\\res\\\\shaders\\\\depthbuffer.shader\"\r\n\r\n#ifdef APSTUDIO_INVOKED\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// TEXTINCLUDE\r\n//\r\n\r\n1 TEXTINCLUDE \r\nBEGIN\r\n    \"resource.h\\0\"\r\nEND\r\n\r\n2 TEXTINCLUDE \r\nBEGIN\r\n    \"#include \"\"winres.h\"\"\\r\\n\"\r\n    \"\\0\"\r\nEND\r\n\r\n3 TEXTINCLUDE \r\nBEGIN\r\n    \"\\r\\n\"\r\n    \"\\0\"\r\nEND\r\n\r\n#endif    // APSTUDIO_INVOKED\r\n\r\n\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// OBJ\r\n//\r\n\r\nIDR_OBJ2                OBJ                     \"..\\\\res\\\\models\\\\stall.obj\"\r\n\r\nIDR_OBJ1                OBJ                     \"..\\\\res\\\\models\\\\sphere.obj\"\r\n\r\n\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// Icon\r\n//\r\n\r\n// Icon with lowest ID value placed first to ensure application icon\r\n// remains consistent on all systems.\r\nMAINICON                ICON                    \"..\\\\res\\\\icon.ico\"\r\n\r\n#endif    // English (United States) resources\r\n/////////////////////////////////////////////////////////////////////////////\r\n\r\n#ifndef APSTUDIO_INVOKED\r\n/////////////////////////////////////////////////////////////////////////////\r\n//\r\n// Generated from the TEXTINCLUDE 3 resource.\r\n//\r\n\r\n\r\n/////////////////////////////////////////////////////////////////////////////\r\n#endif    // not APSTUDIO_INVOKED\r\n\r\n"
  },
  {
    "path": "application/application.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <VCProjectVersion>15.0</VCProjectVersion>\n    <ProjectGuid>{4DB099FF-8264-4262-8195-EBA4109123CC}</ProjectGuid>\n    <RootNamespace>application</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <CodeAnalysisRuleSet>NativeRecommendedRules.ruleset</CodeAnalysisRuleSet>\n    <RunCodeAnalysis>false</RunCodeAnalysis>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalIncludeDirectories>$(SolutionDir)include</AdditionalIncludeDirectories>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalIncludeDirectories>$(SolutionDir)include;$(SolutionDir)application;$(SolutionDir)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>_MBCS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>core.h</PrecompiledHeaderFile>\n      <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <AdditionalLibraryDirectories>$(SolutionDir)lib;$(OutDir)</AdditionalLibraryDirectories>\n      <AdditionalDependencies>Physics3D.lib;util.lib;engine.lib;graphics.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalOptions>/NODEFAULTLIB:LIBCMT</AdditionalOptions>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <Link>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalIncludeDirectories>$(SolutionDir)include;$(SolutionDir)application;$(SolutionDir)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>_MBCS;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>\n      <EnablePREfast>false</EnablePREfast>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>core.h</PrecompiledHeaderFile>\n      <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>\n      <WholeProgramOptimization>true</WholeProgramOptimization>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <AdditionalLibraryDirectories>$(SolutionDir)lib;$(OutDir)</AdditionalLibraryDirectories>\n      <AdditionalDependencies>Physics3D.lib;util.lib;engine.lib;graphics.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalOptions>/NODEFAULTLIB:LIBCMT</AdditionalOptions>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"application.h\" />\n    <ClInclude Include=\"builtinWorlds.h\" />\n    <ClInclude Include=\"ecs\\components.h\" />\n    <ClInclude Include=\"ecs\\entityBuilder.h\" />\n    <ClInclude Include=\"input\\playerController.h\" />\n    <ClInclude Include=\"io\\saveDialog.h\" />\n    <ClInclude Include=\"layer\\cameraLayer.h\" />\n    <ClInclude Include=\"layer\\constraintLayer.h\" />\n    <ClInclude Include=\"core.h\" />\n    <ClInclude Include=\"io\\serialization.h\" />\n    <ClInclude Include=\"layer\\imguiLayer.h\" />\n    <ClInclude Include=\"layer\\shadowLayer.h\" />\n    <ClInclude Include=\"layer\\testLayer.h\" />\n    <ClInclude Include=\"layer\\debugLayer.h\" />\n    <ClInclude Include=\"layer\\debugOverlay.h\" />\n    <ClInclude Include=\"layer\\guiLayer.h\" />\n    <ClInclude Include=\"layer\\modelLayer.h\" />\n    <ClInclude Include=\"layer\\pickerLayer.h\" />\n    <ClInclude Include=\"layer\\postprocessLayer.h\" />\n    <ClInclude Include=\"layer\\skyboxLayer.h\" />\n    <ClInclude Include=\"eventHandler.h\" />\n    <ClInclude Include=\"extendedPart.h\" />\n    <ClInclude Include=\"input\\standardInputHandler.h\" />\n    <ClInclude Include=\"picker\\selection.h\" />\n    <ClInclude Include=\"picker\\tools\\alignmentLinkTool.h\" />\n    <ClInclude Include=\"picker\\tools\\attachmentTool.h\" />\n    <ClInclude Include=\"picker\\tools\\elasticLinkTool.h\" />\n    <ClInclude Include=\"picker\\tools\\fixedConstraintTool.h\" />\n    <ClInclude Include=\"picker\\tools\\magneticLinkTool.h\" />\n    <ClInclude Include=\"picker\\tools\\motorConstraintTool.h\" />\n    <ClInclude Include=\"picker\\tools\\pathTool.h\" />\n    <ClInclude Include=\"picker\\tools\\pistonConstraintTool.h\" />\n    <ClInclude Include=\"picker\\tools\\regionSelectionTool.h\" />\n    <ClInclude Include=\"picker\\tools\\rotationTool.h\" />\n    <ClInclude Include=\"picker\\tools\\scaleTool.h\" />\n    <ClInclude Include=\"picker\\tools\\selectionTool.h\" />\n    <ClInclude Include=\"picker\\tools\\springLinkTool.h\" />\n    <ClInclude Include=\"picker\\tools\\toolSpacing.h\" />\n    <ClInclude Include=\"picker\\tools\\translationTool.h\" />\n    <ClInclude Include=\"resource.h\" />\n    <ClInclude Include=\"resources.h\" />\n    <ClInclude Include=\"shader\\basicShader.h\" />\n    <ClInclude Include=\"shader\\shaderBase.h\" />\n    <ClInclude Include=\"shader\\shaders.h\" />\n    <ClInclude Include=\"picker\\ray.h\" />\n    <ClInclude Include=\"view\\camera.h\" />\n    <ClInclude Include=\"view\\debugFrame.h\" />\n    <ClInclude Include=\"view\\ecsFrame.h\" />\n    <ClInclude Include=\"view\\environmentFrame.h\" />\n    <ClInclude Include=\"view\\frames.h\" />\n    <ClInclude Include=\"view\\layerFrame.h\" />\n    <ClInclude Include=\"view\\propertiesFrame.h\" />\n    <ClInclude Include=\"view\\resourceFrame.h\" />\n    <ClInclude Include=\"view\\screen.h\" />\n    <ClInclude Include=\"view\\toolbarFrame.h\" />\n    <ClInclude Include=\"worldBuilder.h\" />\n    <ClInclude Include=\"worlds.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"application.cpp\" />\n    <ClCompile Include=\"builtinWorlds.cpp\" />\n    <ClCompile Include=\"input\\playerController.cpp\" />\n    <ClCompile Include=\"io\\saveDialog.cpp\" />\n    <ClCompile Include=\"layer\\cameraLayer.cpp\" />\n    <ClCompile Include=\"layer\\constraintLayer.cpp\" />\n    <ClCompile Include=\"core.cpp\">\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeaderFile Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">core.h</PrecompiledHeaderFile>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeaderFile Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">core.h</PrecompiledHeaderFile>\n    </ClCompile>\n    <ClCompile Include=\"io\\serialization.cpp\" />\n    <ClCompile Include=\"layer\\shadowLayer.cpp\" />\n    <ClCompile Include=\"layer\\imguiLayer.cpp\" />\n    <ClCompile Include=\"layer\\postprocessLayer.cpp\" />\n    <ClCompile Include=\"picker\\selection.cpp\" />\n    <ClCompile Include=\"picker\\tools\\alignmentLinkTool.cpp\" />\n    <ClCompile Include=\"picker\\tools\\attachmentTool.cpp\" />\n    <ClCompile Include=\"picker\\tools\\elasticLinkTool.cpp\" />\n    <ClCompile Include=\"picker\\tools\\fixedConstraintTool.cpp\" />\n    <ClCompile Include=\"picker\\tools\\magneticLinkTool.cpp\" />\n    <ClCompile Include=\"picker\\tools\\motorConstraintTool.cpp\" />\n    <ClCompile Include=\"picker\\tools\\pathTool.cpp\" />\n    <ClCompile Include=\"picker\\tools\\pistonConstraintTool.cpp\" />\n    <ClCompile Include=\"picker\\tools\\regionSelectionTool.cpp\" />\n    <ClCompile Include=\"picker\\tools\\rotationTool.cpp\" />\n    <ClCompile Include=\"picker\\tools\\scaleTool.cpp\" />\n    <ClCompile Include=\"picker\\tools\\selectionTool.cpp\" />\n    <ClCompile Include=\"picker\\tools\\springLinkTool.cpp\" />\n    <ClCompile Include=\"picker\\tools\\translationTool.cpp\" />\n    <ClCompile Include=\"resources.cpp\" />\n    <ClCompile Include=\"layer\\testLayer.cpp\" />\n    <ClCompile Include=\"layer\\debugLayer.cpp\" />\n    <ClCompile Include=\"layer\\debugOverlay.cpp\" />\n    <ClCompile Include=\"layer\\guiLayer.cpp\" />\n    <ClCompile Include=\"layer\\modelLayer.cpp\" />\n    <ClCompile Include=\"layer\\pickerLayer.cpp\" />\n    <ClCompile Include=\"layer\\skyboxLayer.cpp\" />\n    <ClCompile Include=\"eventHandler.cpp\" />\n    <ClCompile Include=\"extendedPart.cpp\" />\n    <ClCompile Include=\"picker\\ray.cpp\" />\n    <ClCompile Include=\"input\\standardInputHandler.cpp\" />\n    <ClCompile Include=\"shader\\basicShader.cpp\" />\n    <ClCompile Include=\"shader\\shaderBase.cpp\" />\n    <ClCompile Include=\"shader\\shaders.cpp\" />\n    <ClCompile Include=\"view\\camera.cpp\" />\n    <ClCompile Include=\"view\\debugFrame.cpp\" />\n    <ClCompile Include=\"view\\ecsFrame.cpp\" />\n    <ClCompile Include=\"view\\environmentFrame.cpp\" />\n    <ClCompile Include=\"view\\frames.cpp\" />\n    <ClCompile Include=\"view\\layerFrame.cpp\" />\n    <ClCompile Include=\"view\\propertiesFrame.cpp\" />\n    <ClCompile Include=\"view\\resourceFrame.cpp\" />\n    <ClCompile Include=\"view\\screen.cpp\" />\n    <ClCompile Include=\"view\\toolbarFrame.cpp\" />\n    <ClCompile Include=\"worldBuilder.cpp\" />\n    <ClCompile Include=\"worlds.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"application.rc\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"..\\res\\icon.ico\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Natvis Include=\"debugData.natvis\" />\n    <Natvis Include=\"math.natvis\">\n      <SubType>Designer</SubType>\n    </Natvis>\n    <Natvis Include=\"view.natvis\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"..\\res\\shaders\\basic.shader\" />\n    <None Include=\"..\\res\\shaders\\blur.shader\" />\n    <None Include=\"..\\res\\shaders\\debug.shader\" />\n    <None Include=\"..\\res\\shaders\\depth.shader\" />\n    <None Include=\"..\\res\\shaders\\depthbuffer.shader\" />\n    <None Include=\"..\\res\\shaders\\font.shader\" />\n    <None Include=\"..\\res\\shaders\\instance.shader\" />\n    <None Include=\"..\\res\\shaders\\lighting.shader\" />\n    <None Include=\"..\\res\\shaders\\line.shader\" />\n    <None Include=\"..\\res\\shaders\\mask.shader\" />\n    <None Include=\"..\\res\\shaders\\origin.shader\" />\n    <None Include=\"..\\res\\shaders\\point.shader\" />\n    <None Include=\"..\\res\\shaders\\postprocess.shader\" />\n    <None Include=\"..\\res\\shaders\\quad.shader\" />\n    <None Include=\"..\\res\\shaders\\sky.shader\" />\n    <None Include=\"..\\res\\shaders\\skybox.shader\" />\n    <None Include=\"..\\res\\shaders\\test.shader\" />\n    <None Include=\"..\\res\\shaders\\vector.shader\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "application/builtinWorlds.cpp",
    "content": "#include \"core.h\"\n\n#include \"builtinWorlds.h\"\n\n#include \"worldBuilder.h\"\n\n#include \"extendedPart.h\"\n\n#include \"ecs/entityBuilder.h\"\n#include \"ecs/components.h\"\n#include \"../graphics/meshRegistry.h\"\n\n#include <Physics3D/geometry/shapeCreation.h>\n#include <Physics3D/hardconstraints/motorConstraint.h>\n#include <Physics3D/hardconstraints/sinusoidalPistonConstraint.h>\n#include <Physics3D/hardconstraints/fixedConstraint.h>\n#include <Physics3D/constraints/ballConstraint.h>\n#include <Physics3D/constraints/hingeConstraint.h>\n#include <Physics3D/softlinks/springLink.h>\n#include <Physics3D/math/constants.h>\n\n#include \"engine/resource/meshResource.h\"\n#include \"graphics/resource/textureResource.h\"\n#include \"util/resource/resourceManager.h\"\n#include \"graphics/meshRegistry.h\"\n\nnamespace P3D::Application {\n\nusing namespace WorldBuilder;\n\nvoid buildBenchmarkWorld(PlayerWorld& world) {\n\tWorldBuilder::buildFloor(150.0, 150.0);\n\n\tGlobalCFrame origin(0, 20, 0, Rotation::fromEulerAngles(0, PI / 4, PI / 4));\n\tfor(int i = 0; i < 10; i++) {\n\t\tfor(int j = 0; j < 10; j++) {\n\t\t\tfor(int k = 0; k < 10; k++) {\n\t\t\t\tworld.addPart(new ExtendedPart(boxShape(1.0, 1.0, 1.0), origin.localToGlobal(CFrame(i * 1.00001, j * 1.00001, k * 1.0001)), basicProperties));\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid buildShowcaseWorld(Screen& screen, PlayerWorld& world) {\n\tbuildFloorWorld(screen, world);\n\n\t// Part factories\n\tWorldBuilder::SpiderFactory spiderFactories[]{{0.5, 4},{0.5, 6},{0.5, 8},{0.5, 10}};\n\t\n\t{\n\t\tExtendedPart* partA = new ExtendedPart(boxShape(1.0, 0.49, 3.0), GlobalCFrame(3.0, 3.0, 0.0), {1.0, 1.0, 1.0}, \"partA\");\n\t\tExtendedPart* partB = new ExtendedPart(boxShape(1.0, 0.5, 3.0), GlobalCFrame(2.0, 3.0, 0.0), {1.0, 1.0, 1.0}, \"partA\");\n\t\tEntityBuilder(screen.registry, partA->entity).light(Graphics::Color(0.1f, 0.94f, 0.49f), 500, Comp::Light::Attenuation{0.8, 0.5, 0.2});\n\n\t\tworld.addPart(partA);\n\t\tworld.addPart(partB);\n\t}\n\n\t{\n\t\t\n\t\tauto pistonFolder = EntityBuilder(screen.registry).name(\"PistonPart\").get();\n\n\t\tExtendedPart* centerPart = new ExtendedPart(sphereShape(1.0), GlobalCFrame(-15.0, 4.0, 13.0), basicProperties, \"Center\", pistonFolder);\n\t\tShape box = boxShape(1.0, 1.0, 1.0);\n\n\t\tnew ExtendedPart(Part(box, *centerPart, new SinusoidalPistonConstraint(1.0, 3.0, 1.0), CFrame(0.0, 0.0, 0.0, Rotation::Predefined::IDENTITY), CFrame(0.0, 0.0, 0.0), basicProperties), \"IDENTITY\", pistonFolder);\n\t\tnew ExtendedPart(Part(box, *centerPart, new SinusoidalPistonConstraint(1.0, 3.0, 1.0), CFrame(0.0, 0.0, 0.0, Rotation::Predefined::X_90), CFrame(0.0, 0.0, 0.0), basicProperties), \"X_90\", pistonFolder);\n\t\tnew ExtendedPart(Part(box, *centerPart, new SinusoidalPistonConstraint(1.0, 3.0, 1.0), CFrame(0.0, 0.0, 0.0, Rotation::Predefined::Y_90), CFrame(0.0, 0.0, 0.0), basicProperties), \"Y_90\", pistonFolder);\n\t\tnew ExtendedPart(Part(box, *centerPart, new SinusoidalPistonConstraint(1.0, 3.0, 1.0), CFrame(0.0, 0.0, 0.0, Rotation::Predefined::X_180), CFrame(0.0, 0.0, 0.0), basicProperties), \"X_180\", pistonFolder);\n\t\tnew ExtendedPart(Part(box, *centerPart, new SinusoidalPistonConstraint(1.0, 3.0, 1.0), CFrame(0.0, 0.0, 0.0, Rotation::Predefined::X_270), CFrame(0.0, 0.0, 0.0), basicProperties), \"X_270\", pistonFolder);\n\t\tnew ExtendedPart(Part(box, *centerPart, new SinusoidalPistonConstraint(1.0, 3.0, 1.0), CFrame(0.0, 0.0, 0.0, Rotation::Predefined::Y_270), CFrame(0.0, 0.0, 0.0), basicProperties), \"Y_270\", pistonFolder);\n\n\t\tworld.addPart(centerPart);\n\t}\n\n\n\t{\n\t\tExtendedPart* sateliteBody = new ExtendedPart(cylinderShape(0.5, 1.0), GlobalCFrame(0.0, 7.0, 0.0, Rotation::Predefined::X_90), basicProperties, \"Satelite Body\");\n\t\tExtendedPart* wing1 = new ExtendedPart(boxShape(1.0, 1.0, 1.0), GlobalCFrame(), basicProperties, \"Wing 1\");\n\t\tExtendedPart* wing2 = new ExtendedPart(boxShape(1.0, 1.0, 1.0), GlobalCFrame(), basicProperties, \"Wing 2\");\n\n\n\t\tsateliteBody->attach(wing1, new SinusoidalPistonConstraint(0.0, 5.0, 1.0), CFrame(0.5, 0.0, 0.0, Rotation::Predefined::Y_90), CFrame(-0.5, 0.0, 0.0, Rotation::Predefined::Y_90));\n\t\tsateliteBody->attach(wing2, new SinusoidalPistonConstraint(0.0, 5.0, 1.0), CFrame(-0.5, 0.0, 0.0, Rotation::Predefined::Y_270), CFrame(-0.5, 0.0, 0.0, Rotation::Predefined::Y_90));\n\t\t//sateliteBody->attach(wing2, new SinusoidalPistonConstraint(Vec3(-1.0, 0.0, 0.0), 1.0, 3.0, 1.0), CFrame(-0.5, 0.0, 0.0), CFrame(0.5, 0.0, 0.0));\n\n\t\tworld.addPart(sateliteBody);\n\n\t\tsateliteBody->getMainPhysical()->motionOfCenterOfMass.rotation.rotation[0] = Vec3(0, 2, 0);\n\t}\n\n\n\n\tworld.addPart(new ExtendedPart(sphereShape(2.0), GlobalCFrame(10, 3, 10), {1.0, 0.3, 0.7}, \"SphereThing\"));\n\n\t/*ExtendedPart* conveyor = new ExtendedPart(boxShape(1.0, 0.3, 50.0), GlobalCFrame(10.0, 0.65, 0.0), {2.0, 1.0, 0.3});\n\n\tconveyor->properties.conveyorEffect = Vec3(0, 0, 2.0);\n\tworld.addTerrainPart(conveyor);\n\n\tworld.addPart(new ExtendedPart(boxShape(0.2, 0.2, 0.2), GlobalCFrame(10, 1.0, 0.0), {1.0, 0.2, 0.3}, \"TinyCube\"));*/\n\n\t// hollow box\n\tWorldBuilder::HollowBoxParts parts = WorldBuilder::buildHollowBox(Bounds(Position(12.0, 3.0, 14.0), Position(20.0, 8.0, 20.0)), 0.3);\n\n\tparts.front->setMaterial(Graphics::Comp::Material(Graphics::Color(0.4f, 0.6f, 1.0f, 0.3f)));\n\tparts.back->setMaterial(Graphics::Comp::Material(Graphics::Color(0.4f, 0.6f, 1.0f, 0.3f)));\n\n\t// Rotating walls\n\t/*ExtendedPart* rotatingWall = new ExtendedPart(boxShape(5.0, 3.0, 0.5), GlobalCFrame(Position(-12.0, 1.7, 0.0)), {1.0, 1.0, 0.7});\n\tExtendedPart* rotatingWall2 = new ExtendedPart(boxShape(5.0, 3.0, 0.5), GlobalCFrame(Position(-12.0, 1.7, 5.0)), {1.0, 1.0, 0.7});\n\tworld.addPart(rotatingWall, true);\n\tworld.addPart(rotatingWall2, true);\n\trotatingWall->getMainPhysical()->motionOfCenterOfMass.angularVelocity = Vec3(0, -0.7, 0);\n\trotatingWall2->getMainPhysical()->motionOfCenterOfMass.angularVelocity = Vec3(0, 0.7, 0);*/\n\n\t// Many many parts\n\t/*for(int i = 0; i < 3; i++) {\n\t\tExtendedPart* newCube = new ExtendedPart(boxShape(1.0, 1.0, 1.0), GlobalCFrame(fRand(-10.0, 0.0), fRand(1.0, 1.0), fRand(-10.0, 0.0)), {1.0, 0.2, 0.7});\n\t\tworld.addPart(newCube);\n\t}*/\n\n\tWorldBuilder::buildCar(GlobalCFrame(5.0, 1.0, 5.0));\n\n\n\tWorldBuilder::buildConveyor(1.5, 7.0, GlobalCFrame(-10.0, 1.0, -10.0, Rotation::fromEulerAngles(0.15, 0.0, 0.0)), 1.5);\n\tWorldBuilder::buildConveyor(1.5, 7.0, GlobalCFrame(-12.5, 1.0, -14.0, Rotation::fromEulerAngles(0.0, 3.1415 / 2, -0.15)), 1.5);\n\tWorldBuilder::buildConveyor(1.5, 7.0, GlobalCFrame(-16.5, 1.0, -11.5, Rotation::fromEulerAngles(-0.15, 0.0, -0.0)), -1.5);\n\tWorldBuilder::buildConveyor(1.5, 7.0, GlobalCFrame(-14.0, 1.0, -7.5, Rotation::fromEulerAngles(0.0, 3.1415 / 2, 0.15)), -1.5);\n\n\tint minX = 0;\n\tint maxX = 3;\n\tint minY = 0;\n\tint maxY = 3;\n\tint minZ = 0;\n\tint maxZ = 3;\n\n\tauto cubeFolder = EntityBuilder(screen.registry).name(\"Cubes\").get();\n\tauto cylinderFolder = EntityBuilder(screen.registry).name(\"Cylinders\").get();\n\tauto triangleFolder = EntityBuilder(screen.registry).name(\"Triangles\").get();\n\tauto sphereFolder = EntityBuilder(screen.registry).name(\"Spheres\").get();\n\tauto spiderFolder = EntityBuilder(screen.registry).name(\"Spiders\").get();\n\n\tGlobalCFrame rootFrame(Position(0.0, 15.0, 0.0), Rotation::fromEulerAngles(3.1415 / 4, 3.1415 / 4, 0.0));\n\tfor(double x = minX; x < maxX; x += 1.00001) {\n\t\tfor(double y = minY; y < maxY; y += 1.00001) {\n\t\t\tfor(double z = minZ; z < maxZ; z += 1.00001) {\n\t\t\t\tExtendedPart* newCube = new ExtendedPart(boxShape(1.0, 1.0, 1.0), GlobalCFrame(Position(x - 5, y + 10, z - 5)), {1.0, 1.0, 0.0}, \"Box\", cubeFolder);\n\t\t\t\tnewCube->setMaterial(Graphics::Comp::Material(Vec4f(float((x - minX) / (maxX - minX)), float((y - minY) / (maxY - minY)), float((z - minZ) / (maxZ - minZ)), 1.0f)));\n\n\t\t\t\tworld.addPart(newCube);\n\t\t\t\tworld.addPart(new ExtendedPart(sphereShape(0.5), GlobalCFrame(Position(x + 5, y + 1, z - 5)), {1.0, 0.2, 0.5}, \"Sphere\", sphereFolder));\n\t\t\t\tspiderFactories[rand() & 0x00000003].buildSpider(GlobalCFrame(Position(x + y * 0.1, y + 1, z)), spiderFolder);\n\t\t\t\tworld.addPart(new ExtendedPart(WorldBuilder::triangle, GlobalCFrame(Position(x - 20, y + 1, z + 20)), {1.0, 0.2, 0.5}, \"Triangle\", triangleFolder));\n\n\t\t\t\tworld.addPart(new ExtendedPart(cylinderShape(0.3, 1.2), GlobalCFrame(x - 5, y + 1, z + 5, Rotation::fromEulerAngles(3.1415 / 4, 3.1415 / 4, 0.0)), {1.0, 0.2, 0.5}, \"cylinderShape\", cylinderFolder));\n\t\t\t}\n\t\t}\n\t}\n\n\t//auto terrainFolder = screen.registry.create();\n\t//screen.registry.add<Comp::Tag>(terrainFolder, \"Terrain\");\n\t//WorldBuilder::buildTerrain(150, 150, terrainFolder);\n\n\tauto ropeFolder = EntityBuilder(screen.registry).name(\"Ropes\").get();\n\tExtendedPart* ropeA = new ExtendedPart(boxShape(2.0, 1.5, 0.7), GlobalCFrame(10.0, 2.0, -10.0), {1.0, 0.7, 0.3}, \"RopeA\", ropeFolder);\n\tExtendedPart* ropeB = new ExtendedPart(boxShape(1.5, 1.2, 0.9), GlobalCFrame(10.0, 2.0, -14.0), {1.0, 0.7, 0.3}, \"RopeB\", ropeFolder);\n\tExtendedPart* ropeC = new ExtendedPart(boxShape(2.0, 1.5, 0.7), GlobalCFrame(10.0, 2.0, -18.0), {1.0, 0.7, 0.3}, \"RopeC\", ropeFolder);\n\n\tworld.addPart(ropeA);\n\tworld.addPart(ropeB);\n\tworld.addPart(ropeC);\n\n\tConstraintGroup group;\n\n\tgroup.add(ropeA, ropeB, new BallConstraint(Vec3(0.0, 0.0, -2.0), Vec3(0.0, 0.0, 2.0)));\n\tgroup.add(ropeB, ropeC, new BallConstraint(Vec3(0.0, 0.0, -2.0), Vec3(0.0, 0.0, 2.0)));\n\n\tworld.constraints.push_back(group);\n\n\tExtendedPart* singularPart = new ExtendedPart(boxShape(1.0, 2.0, 1.0), GlobalCFrame(7.0, 1.0, 5.0), {1.3, 1.2, 1.1}, \"SingularPart\");\n\tworld.addPart(singularPart);\n\n\tExtendedPart* ep1 = new ExtendedPart(boxShape(1.0, 2.0, 1.0), GlobalCFrame(3.0, 3.0, 0.0), {1.0, 1.0, 1.0}, \"MainPart\");\n\tExtendedPart* ap1 = new ExtendedPart(boxShape(1.0, 2.0, 1.0), GlobalCFrame(), {1.0, 1.0, 1.0}, \"AttachedPart\");\n\n\tep1->attach(ap1, new FixedConstraint(), CFrame(1.0, 0.0, 0.0), CFrame(0.0, 0.0, 0.0));\n\n\tworld.addPart(ep1);\n\tworld.addPart(ap1);\n\n\tep1->getMainPhysical()->applyAngularImpulse(Vec3(1.0, 0.5, 0.0) * 1);\n\n\tExtendedPart* ep1ap2 = new ExtendedPart(boxShape(0.5, 0.5, 0.5), ep1, CFrame(-0.5, 0.5, 0.5), {1.0, 1.0, 1.0}, \"Ep1Ap2\");\n\tExtendedPart* ep2 = new ExtendedPart(boxShape(1.0, 2.0, 1.0), GlobalCFrame(-3.0, 3.0, 0.0), {1.0, 1.0, 1.0}, \"MainPart\");\n\tExtendedPart* ap2 = new ExtendedPart(boxShape(1.0, 2.0, 1.0), GlobalCFrame(), {1.0, 1.0, 1.0}, \"AttachedPart\");\n\n\tep2->attach(ap2, CFrame(1.0, 0.0, 0.0));\n\n\tworld.addPart(ep2);\n\tworld.addPart(ap2);\n\n\tep2->getMainPhysical()->applyAngularImpulse(Vec3(1.0, 0.5, 0.0) * 1);\n\n\t//SoftLink.\n\t{\n\t\tExtendedPart* a = new ExtendedPart(boxShape(1.0, 1.0, 1.0), GlobalCFrame(3.0, 3.0, 0.0), {1.0, 1.0, 1.0}, \"SpringLinkMain1\");\n\t\tExtendedPart* b = new ExtendedPart(boxShape(1.0, 2.0, 1.0), GlobalCFrame(), {1.0, 1.0, 1.0}, \"SpringLinkPart1\");\n\n\t\tworld.addPart(a);\n\t\tworld.addPart(b);\n\n\t\tworld.addLink(new SpringLink({CFrame{1.0, 0.0, 0.0}, a}, {CFrame{0.0, 0.0, 0.0}, b}, 15.0, 0.5));\n\t}\n\t{\n\t\tExtendedPart* a = new ExtendedPart(boxShape(2.0, 0.5, 1.0), GlobalCFrame(3.0, 3.0, 0.0), {1.0, 1.0, 1.0}, \"SpringLinkMain2\");\n\t\tExtendedPart* b = new ExtendedPart(boxShape(1.0, 1.0, 1.0), GlobalCFrame(), {2.0, 1.0, 1.0}, \"SpringLinkPart2\");\n\n\t\tworld.addPart(a);\n\t\tworld.addPart(b);\n\n\t\tworld.addLink(new SpringLink({CFrame{1.0, 0.0, 0.0}, a}, {CFrame{0.0, 0.0, 0.0}, b}, 15.0, 0.5));\n\t}\n\t{\n\t\tExtendedPart* a = new ExtendedPart(boxShape(1.0, 1.0, 1.0), GlobalCFrame(3.0, 3.0, 0.0), {1.0, 1.0, 1.0}, \"SpringLinkMain3\");\n\t\tExtendedPart* b = new ExtendedPart(boxShape(2.0, 2.0, 2.0), GlobalCFrame(), {1.0, 0.5, 1.0}, \"SpringLinkPart3\");\n\n\t\tworld.addPart(a);\n\t\tworld.addPart(b);\n\n\t\tworld.addLink(new SpringLink({CFrame{1.0, 0.0, 0.0}, a}, {CFrame{0.0, 0.0, 0.0}, b}, 15.0, 0.5));\n\t}\n\n\t/*Vec3 angularVel(0.0, 0.0, -1.0);\n\t{\n\t\tExtendedPart* nativeFixedConstraintGroupMain = new ExtendedPart(boxShape(1.0, 1.0, 1.0), GlobalCFrame(Position(-3.0, 7.0, 2.0), Rotation::fromEulerAngles(0.0, 0.0, -0.5)), {1.0, 1.0, 1.0}, \"MainPart\");\n\t\tExtendedPart* f2 = new ExtendedPart(boxShape(0.9, 0.9, 0.9), GlobalCFrame(), {1.0, 1.0, 1.0}, \"f2\");\n\t\tExtendedPart* f3 = new ExtendedPart(boxShape(0.8, 0.8, 0.8), GlobalCFrame(), {1.0, 1.0, 1.0}, \"f3\");\n\t\tExtendedPart* f4 = new ExtendedPart(boxShape(0.7, 0.7, 0.7), GlobalCFrame(), {1.0, 1.0, 1.0}, \"f4\");\n\t\tExtendedPart* f5 = new ExtendedPart(boxShape(0.6, 0.6, 0.6), GlobalCFrame(), {1.0, 1.0, 1.0}, \"f5\");\n\n\t\tnativeFixedConstraintGroupMain->attach(f2, CFrame(1.2, 0.0, 0.0));\n\t\tf2->attach(f3, CFrame(1.2, 0.0, 0.0));\n\t\tf3->attach(f4, CFrame(1.2, 0.0, 0.0));\n\t\tf4->attach(f5, CFrame(1.2, 0.0, 0.0));\n\n\t\tworld.addPart(f2);\n\n\t\tf2->getMainPhysical()->motionOfCenterOfMass.rotation.angularVelocity = angularVel;\n\t}\n\n\t{\n\t\tExtendedPart* fixedConstraintGroupMain = new ExtendedPart(boxShape(1.0, 1.0, 1.0), GlobalCFrame(Position(-3.0, 7.0, -2.0), Rotation::fromEulerAngles(0.0, 0.0, -0.5)), {1.0, 1.0, 1.0}, \"MainPart\");\n\t\tExtendedPart* f2 = new ExtendedPart(boxShape(0.9, 0.9, 0.9), GlobalCFrame(), {1.0, 1.0, 1.0}, \"f2\");\n\t\tExtendedPart* f3 = new ExtendedPart(boxShape(0.8, 0.8, 0.8), GlobalCFrame(), {1.0, 1.0, 1.0}, \"f3\");\n\t\tExtendedPart* f4 = new ExtendedPart(boxShape(0.7, 0.7, 0.7), GlobalCFrame(), {1.0, 1.0, 1.0}, \"f4\");\n\t\tExtendedPart* f5 = new ExtendedPart(boxShape(0.6, 0.6, 0.6), GlobalCFrame(), {1.0, 1.0, 1.0}, \"f5\");\n\n\t\tfixedConstraintGroupMain->attach(f2, new FixedConstraint(), CFrame(1.2, 0.0, 0.0), CFrame(0, 0, 0));\n\t\tf2->attach(f3, new FixedConstraint(), CFrame(1.2, 0.0, 0.0), CFrame(0, 0, 0));\n\t\tf3->attach(f4, new FixedConstraint(), CFrame(1.2, 0.0, 0.0), CFrame(0, 0, 0));\n\t\tf4->attach(f5, new FixedConstraint(), CFrame(1.2, 0.0, 0.0), CFrame(0, 0, 0));\n\n\t\tworld.addPart(f2);\n\n\t\tf2->getMainPhysical()->motionOfCenterOfMass.rotation.angularVelocity = angularVel;\n\t}*/\n\n\t{\n\t\tExtendedPart* fixedConstraintGroupMain = new ExtendedPart(boxShape(1.0, 1.0, 1.0), GlobalCFrame(-3.0, 3.0, 7.0), {1.0, 1.0, 1.0}, \"MainPart\");\n\t\tExtendedPart* f2 = new ExtendedPart(boxShape(0.9, 0.9, 0.9), GlobalCFrame(), {1.0, 1.0, 1.0}, \"f2\");\n\t\tExtendedPart* f3 = new ExtendedPart(boxShape(0.8, 0.8, 0.8), GlobalCFrame(), {1.0, 1.0, 1.0}, \"f3\");\n\t\tExtendedPart* f4 = new ExtendedPart(boxShape(0.7, 0.7, 0.7), GlobalCFrame(), {1.0, 1.0, 1.0}, \"f4\");\n\t\tExtendedPart* f5 = new ExtendedPart(boxShape(0.6, 0.6, 0.6), GlobalCFrame(), {1.0, 1.0, 1.0}, \"f5\");\n\n\t\tf2->attach(f3, new FixedConstraint(), CFrame(1.2, 0.0, 0.0), CFrame(0, 0, 0));\n\t\tfixedConstraintGroupMain->attach(f2, new FixedConstraint(), CFrame(1.2, 0.0, 0.0), CFrame(0, 0, 0));\n\t\tf3->attach(f4, new FixedConstraint(), CFrame(1.2, 0.0, 0.0), CFrame(0, 0, 0));\n\t\tf4->attach(f5, new FixedConstraint(), CFrame(1.2, 0.0, 0.0), CFrame(0, 0, 0));\n\n\t\tworld.addPart(f2);\n\t}\n\n\n\t{\n\t\tdouble turnSpeed = 10.0;\n\n\t\tauto poweredCarFolder = screen.registry.create();\n\t\tscreen.registry.add<Comp::Name>(poweredCarFolder, \"Powered Car\");\n\n\t\tExtendedPart* poweredCarBody = new ExtendedPart(boxShape(1.0, 0.4, 2.0), GlobalCFrame(-6.0, 1.0, 0.0), basicProperties, \"Chassis\", poweredCarFolder);\n\t\tExtendedPart* FLWheel = new ExtendedPart(cylinderShape(0.5, 0.2), GlobalCFrame(), basicProperties, \"Front Left Wheel\", poweredCarFolder);\n\t\tExtendedPart* FRWheel = new ExtendedPart(cylinderShape(0.5, 0.2), GlobalCFrame(), basicProperties, \"Front Right Wheel\", poweredCarFolder);\n\t\tExtendedPart* BLWheel = new ExtendedPart(cylinderShape(0.5, 0.2), GlobalCFrame(), basicProperties, \"Back Left Wheel\", poweredCarFolder);\n\t\tExtendedPart* BRWheel = new ExtendedPart(cylinderShape(0.5, 0.2), GlobalCFrame(), basicProperties, \"Back Right Wheel\", poweredCarFolder);\n\n\t\tpoweredCarBody->attach(FLWheel, new ConstantSpeedMotorConstraint(turnSpeed), CFrame(Vec3(0.55, 0.0, 1.0), Rotation::Predefined::Y_90), CFrame(Vec3(0.0, 0.0, 0.15), Rotation::Predefined::Y_180));\n\t\tpoweredCarBody->attach(BLWheel, new ConstantSpeedMotorConstraint(turnSpeed), CFrame(Vec3(0.55, 0.0, -1.0), Rotation::Predefined::Y_90), CFrame(Vec3(0.0, 0.0, 0.15), Rotation::Predefined::Y_180));\n\t\tpoweredCarBody->attach(FRWheel, new ConstantSpeedMotorConstraint(-turnSpeed), CFrame(Vec3(-0.55, 0.0, 1.0), Rotation::Predefined::Y_270), CFrame(Vec3(0.0, 0.0, 0.15), Rotation::Predefined::Y_180));\n\t\tpoweredCarBody->attach(BRWheel, new ConstantSpeedMotorConstraint(-turnSpeed), CFrame(Vec3(-0.55, 0.0, -1.0), Rotation::Predefined::Y_270), CFrame(Vec3(0.0, 0.0, 0.15), Rotation::Predefined::Y_180));\n\n\t\tworld.addPart(poweredCarBody);\n\n\t\t//poweredCarBody->getMainPhysical()->motionOfCenterOfMass.angularVelocity = Vec3(0.0, 1.0, 0.0);\n\t}\n\n\t{\n\t\tExtendedPart* mainBlock = new ExtendedPart(boxShape(1.0, 1.0, 1.0), GlobalCFrame(0.0, 5.0, 5.0), basicProperties, \"Main Block\");\n\t\tExtendedPart* attachedBlock = new ExtendedPart(boxShape(1.0, 1.0, 1.0), GlobalCFrame(), basicProperties, \"Attached Block\");\n\n\t\tmainBlock->attach(attachedBlock, new ConstantSpeedMotorConstraint(1.0), CFrame(Vec3(0.0, 0.0, 0.5)), CFrame(Vec3(1.0, 0.0, -0.5)));\n\n\t\tworld.addPart(mainBlock);\n\t}\n\n\t// needed for conservation of angular momentum\n\t{\n\t\tExtendedPart* mainBlock = new ExtendedPart(boxShape(1.0, 1.0, 1.0), GlobalCFrame(0.0, 5.0, -5.0), basicProperties, \"Main Block\");\n\t\tExtendedPart* attachedBlock = new ExtendedPart(boxShape(1.0, 1.0, 1.0), GlobalCFrame(), basicProperties, \"Attached Block\");\n\n\t\tmainBlock->attach(attachedBlock, new MotorConstraintTemplate<SineWaveController>(0.0, 6.283, 1.0), CFrame(Vec3(0.0, 0.0, 0.5)), CFrame(Vec3(0.0, 0.0, -0.5)));\n\n\t\tworld.addPart(mainBlock);\n\t}\n\n\t{\n\t\tExtendedPart* mainBlock = new ExtendedPart(boxShape(1.0, 1.0, 1.0), GlobalCFrame(0.0, 5.0, 10.0), basicProperties, \"Main Block\");\n\t\tExtendedPart* attachedBlock = new ExtendedPart(boxShape(1.0, 1.0, 1.0), GlobalCFrame(), basicProperties, \"Attached Block\");\n\t\tExtendedPart* anotherAttachedBlock = new ExtendedPart(boxShape(1.0, 1.0, 1.0), GlobalCFrame(), basicProperties, \"Another Attached Block\");\n\t\tExtendedPart* attachedCylinder = new ExtendedPart(cylinderShape(0.5, 1.0), GlobalCFrame(), basicProperties, \"Rotating Attached Block\");\n\t\tExtendedPart* attachedBall = new ExtendedPart(sphereShape(0.5), GlobalCFrame(), basicProperties, \"Attached Ball\");\n\n\t\tmainBlock->attach(attachedBlock, new SinusoidalPistonConstraint(1.0, 3.0, 1.0), CFrame(0.5, 0.0, 0.0, Rotation::Predefined::Y_90), CFrame(-0.5, 0.0, 0.0, Rotation::Predefined::Y_90));\n\t\tattachedBlock->attach(anotherAttachedBlock, new SinusoidalPistonConstraint(1.0, 2.0, 0.7), CFrame(0.0, 0.5, 0.0, Rotation::Predefined::X_270), CFrame(0.0, -0.5, 0.0, Rotation::Predefined::X_270));\n\n\t\tattachedBlock->attach(attachedCylinder, new ConstantSpeedMotorConstraint(3.0), CFrame(0.0, 0.0, 0.55), CFrame(0.0, 0.0, -0.55));\n\n\t\tattachedCylinder->attach(attachedBall, new SinusoidalPistonConstraint(0.0, 2.0, 0.7), CFrame(0.0, 0.5, 0.0, Rotation::Predefined::X_270), CFrame(0.0, -0.5, 0.0, Rotation::Predefined::X_270));\n\n\t\tworld.addPart(mainBlock);\n\n\t\tmainBlock->getMainPhysical()->motionOfCenterOfMass.rotation.rotation[0] = Vec3(0, 2, 0);\n\t}\n\n\t{\n\t\t//WorldBuilder::buildTrebuchet(GlobalCFrame(0, 2, -20), 1.0, 2.0, 0.6, 0.2, 2.4, 0.15, 0);\n\t}\n\n\t{\n\t\tExtendedPart* box1 = new ExtendedPart(boxShape(2.0, 1.0, 1.0), GlobalCFrame(-10.0, 5.0, -10.0), basicProperties, \"Box1\");\n\t\tExtendedPart* box2 = new ExtendedPart(boxShape(2.0, 1.0, 1.0), GlobalCFrame(-11.1, 5.0, -8.1, Rotation::rotY(3.1415 * 2 / 3)), basicProperties, \"Box2\");\n\t\tExtendedPart* box3 = new ExtendedPart(boxShape(2.0, 1.0, 1.0), GlobalCFrame(-8.9, 5.0, -8.1, Rotation::rotY(-3.1415 * 2 / 3)), basicProperties, \"Box3\");\n\n\t\tworld.addPart(box1);\n\t\tworld.addPart(box2);\n\t\tworld.addPart(box3);\n\n\t\tConstraintGroup group;\n\n\t\tgroup.add(box1, box3, new HingeConstraint(Vec3(1.5, 0.0, 0.0), Vec3(0.0, 1.0, 0.0), Vec3(-1.5, 0.0, 0.0), Vec3(0.0, 1.0, 0.0)));\n\t\tgroup.add(box2, box1, new HingeConstraint(Vec3(1.5, 0.0, 0.0), Vec3(0.0, 1.0, 0.0), Vec3(-1.5, 0.0, 0.0), Vec3(0.0, 1.0, 0.0)));\n\t\t//group.add(box3->parent, box2->parent, new HingeConstraint(Vec3(1.5, 0.0, 0.0), Vec3(0.0, 1.0, 0.0), Vec3(-1.5, 0.0, 0.0), Vec3(0.0, 1.0, 0.0)));\n\n\t\tworld.constraints.push_back(std::move(group));\n\t}\n\n\t{\n\t\tExtendedPart* box1 = new ExtendedPart(boxShape(2.0, 1.0, 1.0), GlobalCFrame(-10.0, 5.0, 10.0), basicProperties, \"Box1\");\n\t\tExtendedPart* box2 = new ExtendedPart(boxShape(2.0, 1.0, 1.0), GlobalCFrame(-11.1, 5.0, 11.9, Rotation::rotY(3.1415 * 2 / 3)), basicProperties, \"Box2\");\n\t\tExtendedPart* box3 = new ExtendedPart(boxShape(2.0, 1.0, 1.0), GlobalCFrame(-8.9, 5.0, 11.9, Rotation::rotY(-3.1415 * 2 / 3)), basicProperties, \"Box3\");\n\n\t\tworld.addPart(box1);\n\t\tworld.addPart(box2);\n\t\tworld.addPart(box3);\n\n\t\tConstraintGroup group;\n\n\t\tgroup.add(box1, box3, new BallConstraint(Vec3(1.0, 0.0, 0.7), Vec3(-1.0, 0.0, 0.7)));\n\t\tgroup.add(box2, box1, new BallConstraint(Vec3(1.0, 0.0, 0.7), Vec3(-1.0, 0.0, 0.7)));\n\t\tgroup.add(box3, box2, new BallConstraint(Vec3(1.0, 0.0, 0.7), Vec3(-1.0, 0.0, 0.7)));\n\n\t\tworld.constraints.push_back(std::move(group));\n\t}\n\n\tShape torusShape = polyhedronShape(ShapeLibrary::createTorus(1.0f, 0.6f, 80, 80));\n\tGraphics::MeshRegistry::registerShapeClass(torusShape.baseShape.get(), Graphics::ExtendedTriangleMesh::generateSmoothNormalsShape(torusShape.baseShape->asPolyhedron()));\n\tworld.addPart(new ExtendedPart(torusShape, Position(-10.0, 3.0, 0.0), basicProperties, \"Torus\"));\n\n\n\tVec2f toyPoints[]{{0.2f, 0.2f},{0.3f, 0.4f},{0.2f, 0.6f},{0.3f, 0.8f},{0.4f,0.7f},{0.5f,0.4f},{0.6f,0.2f},{0.75f,0.1f},{0.9f,0.015f}};\n\tShape toyShape = polyhedronShape(ShapeLibrary::createRevolvedShape(0.0f, toyPoints, 9, 1.0f, 10));\n\tworld.addPart(new ExtendedPart(toyShape, Position(-10.0, 3.0, 3.0), basicProperties, \"ToyPoints\"));\n\n\tVec2f arrowPoints[]{{0.3f,0.1f},{0.3f,0.04f},{1.0f,0.04f}};\n\tShape arrorShape = polyhedronShape(ShapeLibrary::createRevolvedShape(0.0f, arrowPoints, 3, 1.0f, 40));\n\tworld.addPart(new ExtendedPart(arrorShape, Position(-7.0, 3.0, 0.0), basicProperties, \"ArrowPoints\"));\n}\n\nvoid buildDebugWorld(Screen& screen, PlayerWorld& world) {\n\tbuildFloorWorld(screen, world);\n\n\tauto parent = EntityBuilder(screen.registry).name(\"Spheres\").get();\n\tint s = 10;\n\tfor (int x = 0; x < s; x++) {\n\t\tfor (int y = 0; y < s; y++) {\n\t\t\tfor (int z = 0; z < s; z++) {\n\t\t\t\tExtendedPart* part = new ExtendedPart(sphereShape(0.45), Position(x, 2 + y, z), PartProperties(), \"Sphere\", parent);\n\t\t\t\tauto mat = screen.registry.add<Graphics::Comp::Material>(part->entity, Graphics::Colors::RED);\n\t\t\t\tmat->metalness = 1.0f * x / s;\n\t\t\t\tmat->roughness = 1.0f * y / s;\n\t\t\t\tmat->ao = 1.0f * z / s;\n\t\t\t\tworld.addTerrainPart(part);\n\t\t\t}\n\t\t}\n\t}\n\t\n}\n\nvoid buildFloorWorld(Screen& screen, PlayerWorld& world) {\n\tWorldBuilder::buildFloorAndWalls(50.0, 50.0, 1.0);\n\n\tComp::Light::Attenuation attenuation = { 1, 1, 1 };\n\tauto lights = EntityBuilder(screen.registry).name(\"Lights\").get();\n\tauto sphereData = Graphics::MeshRegistry::getMesh(&SphereClass::instance);\n\tEntityBuilder(screen.registry).parent(lights).transform(Position(10, 5, -10), 0.2).light(Graphics::Color(1, 0.84f, 0.69f), 300, attenuation).hitbox(sphereShape(1.0)).mesh(sphereData);\n\tEntityBuilder(screen.registry).parent(lights).transform(Position(10, 5, 10), 0.2).light(Graphics::Color(1, 0.84f, 0.69f), 300, attenuation).hitbox(sphereShape(1.0)).mesh(sphereData);\n\tEntityBuilder(screen.registry).parent(lights).transform(Position(-10, 5, -10), 0.2).light(Graphics::Color(1, 0.84f, 0.69f), 200, attenuation).hitbox(sphereShape(1.0)).mesh(sphereData);\n\tEntityBuilder(screen.registry).parent(lights).transform(Position(-10, 5, 10), 0.2).light(Graphics::Color(1, 0.84f, 0.69f), 500, attenuation).hitbox(sphereShape(1.0)).mesh(sphereData);\n}\n\nvoid buildBallWorld(Screen& screen, PlayerWorld& world) {\n\tbuildFloorWorld(screen, world);\n\n\tEngine::MeshResource* ball = ResourceManager::add<Engine::MeshResource>(\"ball\", \"../res/models/ball.obj\");\n\tGraphics::Comp::Mesh mesh = Graphics::MeshRegistry::registerShape(*ball->getShape());\n\tGraphics::TextureResource* ballAlbedo = ResourceManager::add<Graphics::TextureResource>(\"ball albedo\", \"../res/textures/ball/ball_color.png\");\n\tGraphics::TextureResource* ballNormal = ResourceManager::add<Graphics::TextureResource>(\"ball normal\", \"../res/textures/ball/ball_normal.png\");\n\tGraphics::TextureResource* ballMetal = ResourceManager::add<Graphics::TextureResource>(\"ball metal\", \"../res/textures/ball/ball_metal.png\");\n\tGraphics::TextureResource* ballGloss = ResourceManager::add<Graphics::TextureResource>(\"ball gloss\", \"../res/textures/ball/ball_gloss.png\");\n\tGraphics::TextureResource* ballAO = ResourceManager::add<Graphics::TextureResource>(\"ball ao\", \"../res/textures/ball/ball_ao.png\");\n\n\tauto entity = EntityBuilder(screen.registry).transform(Position(0, 8, 0)).mesh(mesh).hitbox(boxShape(10, 10, 10)).get();\n\tauto material = screen.registry.add<Graphics::Comp::Material>(entity);\n\tmaterial->set(Graphics::Comp::Material::Map_Albedo, SRef<Graphics::Texture>(dynamic_cast<Graphics::Texture*>(ballAlbedo)));\n\tmaterial->set(Graphics::Comp::Material::Map_Normal, SRef<Graphics::Texture>(dynamic_cast<Graphics::Texture*>(ballNormal)));\n\tmaterial->set(Graphics::Comp::Material::Map_Metalness, SRef<Graphics::Texture>(dynamic_cast<Graphics::Texture*>(ballMetal)));\n\tmaterial->set(Graphics::Comp::Material::Map_Roughness, SRef<Graphics::Texture>(dynamic_cast<Graphics::Texture*>(ballGloss)));\n\tmaterial->set(Graphics::Comp::Material::Map_AO, SRef<Graphics::Texture>(dynamic_cast<Graphics::Texture*>(ballAO)));\n}\n\nvoid buildBoxWorld(Screen& screen, PlayerWorld& world) {\n\tbuildFloorWorld(screen, world);\n\n\tEngine::MeshResource* ball = ResourceManager::add<Engine::MeshResource>(\"ball\", \"../res/models/box_t.obj\");\n\tGraphics::ExtendedTriangleMesh shape = *ball->getShape();\n\tconst Vec3f* normals = shape.normals.get();\n\tGraphics::Comp::Mesh mesh = Graphics::MeshRegistry::registerShape(shape);\n\tGraphics::TextureResource* boxAlbedo = ResourceManager::add<Graphics::TextureResource>(\"box albedo\", \"../res/textures/box/MetalPlates006_1K_Color.jpg\");\n\tGraphics::TextureResource* boxNormal = ResourceManager::add<Graphics::TextureResource>(\"box normal\", \"../res/textures/box/MetalPlates006_1K_NormalGL.jpg\");\n\tGraphics::TextureResource* boxMetalness = ResourceManager::add<Graphics::TextureResource>(\"box metal\", \"../res/textures/box/MetalPlates006_1K_Metalness.jpg\");\n\tGraphics::TextureResource* boxRougness = ResourceManager::add<Graphics::TextureResource>(\"box roughness\", \"../res/textures/box/MetalPlates006_1K_Roughness.jpg\");\n\n\tauto entity = EntityBuilder(screen.registry).transform(Position(0, 8, 0)).mesh(mesh).hitbox(boxShape(10, 10, 10)).get();\n\tauto material = screen.registry.add<Graphics::Comp::Material>(entity);\n\tmaterial->set(Graphics::Comp::Material::Map_Albedo, SRef<Graphics::Texture>(dynamic_cast<Graphics::Texture*>(boxAlbedo)));\n\t//material->set(Graphics::Comp::Material::Map_Normal, SRef<Graphics::Texture>(dynamic_cast<Graphics::Texture*>(boxNormal)));\n\tmaterial->set(Graphics::Comp::Material::Map_Metalness, SRef<Graphics::Texture>(dynamic_cast<Graphics::Texture*>(boxMetalness)));\n\tmaterial->set(Graphics::Comp::Material::Map_Roughness, SRef<Graphics::Texture>(dynamic_cast<Graphics::Texture*>(boxRougness)));\n}\n\n};\n"
  },
  {
    "path": "application/builtinWorlds.h",
    "content": "#pragma once\n\n#include \"worlds.h\"\n#include \"view/screen.h\"\n\nnamespace P3D::Application {\nvoid buildBenchmarkWorld(PlayerWorld& world);\nvoid buildShowcaseWorld(Screen& screen, PlayerWorld& world);\nvoid buildDebugWorld(Screen& screen, PlayerWorld& world);\nvoid buildBallWorld(Screen& screen, PlayerWorld& world);\nvoid buildFloorWorld(Screen& screen, PlayerWorld& world);\nvoid buildBoxWorld(Screen& screen, PlayerWorld& world);\n};\n"
  },
  {
    "path": "application/core.cpp",
    "content": "#include \"core.h\""
  },
  {
    "path": "application/core.h",
    "content": "#pragma once\n\n#include <unordered_map>\n#include <functional>\n#include <algorithm>\n#include <utility>\n#include <string>\n#include <vector>\n#include <cmath>\n#include <map>\n\n#include <Physics3D/math/linalg/vec.h>\n#include <Physics3D/math/linalg/mat.h>\n#include <Physics3D/math/linalg/trigonometry.h>\n#include <Physics3D/math/fix.h>\n#include <Physics3D/math/position.h>\n\n#include \"../util/log.h\"\n#include <Physics3D/datastructures/smartPointers.h>\n\n#define irepeat(x, n) for (int x = 0; x < n; x++)\n#define frepeat(x, n) for (float x = 0.0f; x < n; x+=1.0f)\n#define isrepeat(x, n, s) for (int x = 0; x < n; x+=s)\n#define fsrepeat(x, n, s) for (float x = 0.0f; x < n; x+=s)\n\n#ifdef _MSC_VER\n\t#define P3D_DEBUGBREAK __debugbreak()\n#else\n#include <csignal>\n\t#define P3D_DEBUGBREAK raise(SIGTRAP)\n#endif\n"
  },
  {
    "path": "application/debugData.natvis",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?> \n<AutoVisualizer xmlns=\"http://schemas.microsoft.com/vstudio/debugger/natvis/2010\">\n  <Type Name=\"Fix&lt;*&gt;\">\n    <DisplayString>{double(value) / (1ULL &lt;&lt; $T1),g}</DisplayString>\n  </Type>\n  <Type Name=\"Part\">\n    <DisplayString>parent={(void*) parent} mainPhys={(void*) parent->mainPhysical}</DisplayString>\n  </Type>\n  <Type Name=\"TreeNode\">\n    <DisplayString Condition=\"nodeCount != 0x7FFFFFFF\">TrunkNode Size={nodeCount} isGroupHead={isGroupHead}</DisplayString>\n    <DisplayString Condition=\"nodeCount == 0x7FFFFFFF\">LeafNode {object} isGroupHead={isGroupHead}</DisplayString>\n    <Expand>\n      <Item Name=\"bounds\" ExcludeView=\"simple\">bounds</Item>\n      <ArrayItems Condition=\"nodeCount != 0x7FFFFFFF\">\n        <Size>nodeCount</Size>\n        <ValuePointer>subTrees</ValuePointer>\n      </ArrayItems>\n      <Item Name=\"object\" ExcludeView=\"simple\" Condition=\"nodeCount == 0x7FFFFFFF\">object</Item>\n    </Expand>\n  </Type>\n  <Type Name=\"TreeStackElement\">\n    <DisplayString Condition=\"node->nodeCount != 0x7FFFFFFF\">index={index}/{node->nodeCount} bounds={node->bounds} isGroupHead={node->isGroupHead}</DisplayString>\n    <DisplayString Condition=\"node->nodeCount == 0x7FFFFFFF\">leafNode bounds={node->bounds}</DisplayString>\n  </Type>\n  <Type Name=\"NodeStack\">\n    <DisplayString>Size={top - stack + 1} Top={top->node->bounds}</DisplayString>\n    <Expand>\n      <ArrayItems Condition=\"top >= stack\">\n        <Size>top - stack + 1</Size>\n        <ValuePointer>stack</ValuePointer>\n      </ArrayItems>\n    </Expand>\n  </Type>\n  <Type Name=\"P3D::TreeNodeRef\">\n    <DisplayString Condition=\"ptr == 0xADADADADADADADAD\">Invalid</DisplayString>\n    <DisplayString Condition=\"(ptr &amp; 0b111) == 0\">LeafNode {(void*) ptr}</DisplayString>\n    <DisplayString Condition=\"(ptr &amp; 0b111) != 0 &amp;&amp; (ptr &amp; 0b1000) == 0\">TreeTrunk {{Size: {(ptr &amp; 0b111) + 1}}}</DisplayString>\n    <DisplayString Condition=\"(ptr &amp; 0b111) != 0 &amp;&amp; (ptr &amp; 0b1000) == 0b1000\">Grouphead {{Size: {(ptr &amp; 0b111) + 1}}}</DisplayString>\n    <Expand>\n      <ArrayItems Condition=\"(ptr &amp; 0b111) != 0\">\n        <Size>(ptr &amp; 0b111) + 1</Size>\n        <ValuePointer>((TreeTrunk*) (ptr &amp; 0xFFFFFFFFFFFFFFF0))->subNodes</ValuePointer>\n      </ArrayItems>\n      <Item Name=\"TreeTrunk\" ExcludeView=\"simple\" Condition=\"(ptr &amp; 0b111) != 0\">(TreeTrunk*) (ptr &amp; 0xFFFFFFFFFFFFFFF0)</Item>\n    </Expand>\n  </Type>\n  <Type Name=\"P3D::BoundsTreePrototype\">\n    <DisplayString>BoundsTree {{baseTrunkSize: {baseTrunkSize}}}</DisplayString>\n    <Expand>\n      <ArrayItems>\n        <Size>baseTrunkSize</Size>\n        <ValuePointer>baseTrunk.subNodes</ValuePointer>\n      </ArrayItems>\n      <Item Name=\"TreeTrunk\" ExcludeView=\"simple\">baseTrunk</Item>\n    </Expand>\n  </Type>\n</AutoVisualizer>"
  },
  {
    "path": "application/ecs/components.h",
    "content": "#pragma once\n\n#include <string>\n#include <variant>\n#include <functional>\n\n#include <Physics3D/geometry/builtinShapeClasses.h>\n#include <Physics3D/threading/upgradeableMutex.h>\n#include <Physics3D/geometry/shapeCreation.h>\n#include \"Physics3D/softlinks/elasticLink.h\"\n#include \"Physics3D/softlinks/magneticLink.h\"\n#include \"Physics3D/softlinks/springLink.h\"\n#include \"../application/extendedPart.h\"\n#include \"../worlds.h\"\n#include \"Physics3D/misc/toString.h\"\n#include \"Physics3D/softlinks/alignmentLink.h\"\n\nnamespace P3D::Application {\n\n\tnamespace Comp {\n\n\t\tstruct Hitbox : RC {\n\t\t\tstd::variant<Shape, ExtendedPart*> hitbox;\n\n\t\t\tHitbox() : hitbox(boxShape(2.0, 2.0, 2.0)) {}\n\t\t\tHitbox(ExtendedPart* part) : hitbox(part) {}\n\t\t\tHitbox(const Shape& shape) : hitbox(shape) {}\n\n\t\t\tShape getShape() {\n\t\t\t\tif (std::holds_alternative<Shape>(this->hitbox)) {\n\t\t\t\t\treturn std::get<Shape>(hitbox);\n\t\t\t\t} else {\n\t\t\t\t\treturn std::get<ExtendedPart*>(this->hitbox)->hitbox;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tbool isPartAttached() {\n\t\t\t\treturn std::holds_alternative<ExtendedPart*>(this->hitbox);\n\t\t\t}\n\n\t\t\tExtendedPart* getPart() {\n\t\t\t\treturn std::get<ExtendedPart*>(this->hitbox);\n\t\t\t}\n\n\t\t\tDiagonalMat3 getScale() {\n\t\t\t\treturn this->getShape().scale;\n\t\t\t}\n\n\t\t\tvoid setScale(const DiagonalMat3& scale) {\n\t\t\t\tif (std::holds_alternative<ExtendedPart*>(this->hitbox)) {\n\t\t\t\t\tstd::get<ExtendedPart*>(this->hitbox)->setScale(scale);\n\t\t\t\t} else {\n\t\t\t\t\tstd::get<Shape>(this->hitbox).scale = scale;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tstruct Transform : RC {\n\t\t\tstruct ScaledCFrame {\n\t\t\t\tGlobalCFrame cframe;\n\t\t\t\tDiagonalMat3 scale;\n\n\t\t\t\tScaledCFrame()\n\t\t\t\t\t: cframe(GlobalCFrame())\n\t\t\t\t\t, scale(DiagonalMat3::IDENTITY()) {}\n\n\t\t\t\tScaledCFrame(const Position& position)\n\t\t\t\t\t: cframe(position)\n\t\t\t\t\t, scale(DiagonalMat3::IDENTITY()) {}\n\n\t\t\t\tScaledCFrame(const Position& position, double scale)\n\t\t\t\t\t: cframe(position)\n\t\t\t\t\t, scale(DiagonalMat3::DIAGONAL(scale)) {}\n\n\t\t\t\tScaledCFrame(const GlobalCFrame& cframe)\n\t\t\t\t\t: cframe(cframe)\n\t\t\t\t\t, scale(DiagonalMat3::IDENTITY()) {}\n\n\t\t\t\tScaledCFrame(const GlobalCFrame& cframe, double scale)\n\t\t\t\t\t: cframe(cframe)\n\t\t\t\t\t, scale(DiagonalMat3::DIAGONAL(scale)) {}\n\n\t\t\t\tScaledCFrame(const GlobalCFrame& cframe, const DiagonalMat3& scale)\n\t\t\t\t\t: cframe(cframe)\n\t\t\t\t\t, scale(scale) {}\n\n\t\t\t\tvoid translate(const Vec3& translation) {\n\t\t\t\t\tthis->cframe.translate(translation);\n\t\t\t\t}\n\n\t\t\t\tvoid rotate(const Rotation& rotation) {\n\t\t\t\t\tthis->cframe.rotate(rotation);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tstd::variant<ExtendedPart*, ScaledCFrame> root;\n\t\t\tstd::variant<CFrame, CFrame*> offset;\n\n\t\t\tstd::function<void()> onChange;\n\n\t\t\tTransform()\n\t\t\t\t: root(ScaledCFrame())\n\t\t\t\t, offset(nullptr) {}\n\n\t\t\tTransform(ExtendedPart* root)\n\t\t\t\t: root(root)\n\t\t\t\t, offset(nullptr) {}\n\n\t\t\tTransform(ExtendedPart* root, CFrame* offset)\n\t\t\t\t: root(root)\n\t\t\t\t, offset(offset) {}\n\n\t\t\tTransform(ExtendedPart* root, const CFrame& offset)\n\t\t\t\t: root(root)\n\t\t\t\t, offset(offset) {}\n\n\t\t\tTransform(const Position& position)\n\t\t\t\t: root(ScaledCFrame(position))\n\t\t\t\t, offset(nullptr) {}\n\n\t\t\tTransform(const Position& position, double scale)\n\t\t\t\t: root(ScaledCFrame(position, scale))\n\t\t\t\t, offset(nullptr) {}\n\n\t\t\tTransform(const GlobalCFrame& cframe)\n\t\t\t\t: root(ScaledCFrame(cframe))\n\t\t\t\t, offset(nullptr) {}\n\n\t\t\tTransform(const GlobalCFrame& cframe, double scale)\n\t\t\t\t: root(ScaledCFrame(cframe, scale))\n\t\t\t\t, offset(nullptr) {}\n\n\t\t\tTransform(const GlobalCFrame& cframe, const DiagonalMat3& scale)\n\t\t\t\t: root(ScaledCFrame(cframe, scale))\n\t\t\t\t, offset(nullptr) {}\n\n\t\t\tbool isRootPart() {\n\t\t\t\treturn std::holds_alternative<ExtendedPart*>(this->root);\n\t\t\t}\n\n\t\t\tbool isRootCFrame() {\n\t\t\t\treturn std::holds_alternative<ScaledCFrame>(this->root);\n\t\t\t}\n\n\t\t\tbool hasOffset() {\n\t\t\t\treturn std::holds_alternative<CFrame>(this->offset) || std::holds_alternative<CFrame*>(this->offset) && std::get<CFrame*>(this->offset) != nullptr;\n\t\t\t}\n\n\t\t\tbool isOffsetStoredLocal() {\n\t\t\t\tif (!hasOffset())\n\t\t\t\t\treturn false;\n\n\t\t\t\treturn std::holds_alternative<CFrame>(this->offset);\n\t\t\t}\n\n\t\t\tbool isOffsetStoredRemote() {\n\t\t\t\tif (!hasOffset())\n\t\t\t\t\treturn false;\n\n\t\t\t\treturn std::holds_alternative<CFrame*>(this->offset);\n\t\t\t}\n\n\t\t\tvoid addCallback(const std::function<void()>& onChange) {\n\t\t\t\tthis->onChange = onChange;\n\t\t\t}\n\n\t\t\tvoid setRoot(ExtendedPart* root) {\n\t\t\t\tthis->root = root;\n\t\t\t}\n\n\t\t\tvoid setRoot(const ScaledCFrame& root) {\n\t\t\t\tthis->root = root;\n\t\t\t}\n\n\t\t\tvoid setOffset(CFrame* offset) {\n\t\t\t\tthis->offset = offset;\n\t\t\t}\n\n\t\t\tvoid setOffset(const CFrame& offset) {\n\t\t\t\tthis->offset = offset;\n\t\t\t}\n\n\t\t\ttemplate <typename Function>\n\t\t\tvoid modify(UpgradeableMutex& mutex, const Function& function) {\n\t\t\t\tif (isRootPart() || isOffsetStoredRemote()) {\n\t\t\t\t\tmutex.lock();\n\t\t\t\t\tfunction();\n\t\t\t\t\tmutex.unlock();\n\t\t\t\t} else\n\t\t\t\t\tfunction();\n\n\t\t\t\tif (onChange != nullptr)\n\t\t\t\t\tonChange();\n\t\t\t}\n\n\t\t\tvoid translate(const Vec3& translation) {\n\t\t\t\tif (hasOffset()) {\n\t\t\t\t\tVec3 relativeTranslation = getRootCFrame().relativeToLocal(translation);\n\n\t\t\t\t\tif (isOffsetStoredLocal()) {\n\t\t\t\t\t\tstd::get<CFrame>(this->offset).translate(relativeTranslation);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstd::get<CFrame*>(this->offset)->translate(relativeTranslation);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (isRootPart()) {\n\t\t\t\t\t\tstd::get<ExtendedPart*>(this->root)->translate(translation);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstd::get<ScaledCFrame>(this->root).translate(translation);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (onChange != nullptr)\n\t\t\t\t\tonChange();\n\t\t\t}\n\n\t\t\tvoid rotate(const Vec3& normal, double angle) {\n\t\t\t\tif (hasOffset()) {\n\t\t\t\t\tVec3 relativeNormal = getRootCFrame().relativeToLocal(normal);\n\t\t\t\t\tRotation relativeRotation = Rotation::fromRotationVector(relativeNormal * angle);\n\n\t\t\t\t\tif (isOffsetStoredLocal()) {\n\t\t\t\t\t\tstd::get<CFrame>(this->offset).rotate(relativeRotation);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstd::get<CFrame*>(this->offset)->rotate(relativeRotation);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tRotation rotation = Rotation::fromRotationVector(normal * angle);\n\n\t\t\t\t\tif (isRootPart()) {\n\t\t\t\t\t\tExtendedPart* part = std::get<ExtendedPart*>(this->root);\n\t\t\t\t\t\tpart->setCFrame(part->getCFrame().rotated(rotation));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstd::get<ScaledCFrame>(this->root).rotate(rotation);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (onChange != nullptr)\n\t\t\t\t\tonChange();\n\t\t\t}\n\n\t\t\tvoid rotate(const Rotation& rotation) {\n\t\t\t\tif (hasOffset()) {\n\t\t\t\t\tRotation rootRotation = getRootCFrame().getRotation();\n\t\t\t\t\tRotation relativeRotation = ~rootRotation * rotation * rootRotation;\n\n\t\t\t\t\tif (isOffsetStoredLocal()) {\n\t\t\t\t\t\tstd::get<CFrame>(this->offset).rotate(relativeRotation);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstd::get<CFrame*>(this->offset)->rotate(relativeRotation);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (isRootPart()) {\n\t\t\t\t\t\tExtendedPart* part = std::get<ExtendedPart*>(this->root);\n\t\t\t\t\t\tpart->setCFrame(part->getCFrame().rotated(rotation));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstd::get<ScaledCFrame>(this->root).rotate(rotation);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (onChange != nullptr)\n\t\t\t\t\tonChange();\n\t\t\t}\n\n\t\t\tvoid scale(double scaleX, double scaleY, double scaleZ) {\n\t\t\t\tif (isRootPart()) {\n\t\t\t\t\tstd::get<ExtendedPart*>(this->root)->scale(scaleX, scaleY, scaleZ);\n\t\t\t\t} else {\n\t\t\t\t\tstd::get<ScaledCFrame>(this->root).scale *= DiagonalMat3({ scaleX, scaleY, scaleZ });\n\t\t\t\t}\n\n\t\t\t\tif (onChange != nullptr)\n\t\t\t\t\tonChange();\n\t\t\t}\n\n\t\t\tGlobalCFrame getRootCFrame() {\n\t\t\t\tif (isRootPart()) {\n\t\t\t\t\treturn std::get<ExtendedPart*>(this->root)->getCFrame();\n\t\t\t\t} else {\n\t\t\t\t\treturn std::get<ScaledCFrame>(this->root).cframe;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tCFrame getOffsetCFrame() {\n\t\t\t\tif (hasOffset()) {\n\t\t\t\t\tif (isOffsetStoredLocal())\n\t\t\t\t\t\treturn std::get<CFrame>(this->offset);\n\t\t\t\t\telse\n\t\t\t\t\t\treturn *std::get<CFrame*>(this->offset);\n\t\t\t\t} else {\n\t\t\t\t\treturn CFrame();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tGlobalCFrame getCFrame() {\n\t\t\t\tGlobalCFrame rootCFrame = getRootCFrame();\n\t\t\t\tCFrame offsetCFrame = getOffsetCFrame();\n\n\t\t\t\treturn rootCFrame.localToGlobal(offsetCFrame);\n\t\t\t}\n\n\t\t\tvoid setCFrame(const GlobalCFrame& cframe) {\n\t\t\t\tif (hasOffset()) {\n\t\t\t\t\tCFrame relativeCFrame = getRootCFrame().globalToLocal(cframe);\n\t\t\t\t\tif (isOffsetStoredLocal()) {\n\t\t\t\t\t\tstd::get<CFrame>(this->offset) = relativeCFrame;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t*std::get<CFrame*>(this->offset) = relativeCFrame;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (isRootPart()) {\n\t\t\t\t\t\tstd::get<ExtendedPart*>(this->root)->setCFrame(cframe);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstd::get<ScaledCFrame>(this->root).cframe = cframe;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (onChange != nullptr)\n\t\t\t\t\tonChange();\n\t\t\t}\n\n\t\t\tPosition getPosition() {\n\t\t\t\treturn getCFrame().getPosition();\n\t\t\t}\n\n\t\t\tvoid setPosition(const Position& position) {\n\t\t\t\tGlobalCFrame cframe = getCFrame();\n\t\t\t\tcframe.position = position;\n\n\t\t\t\tsetCFrame(cframe);\n\t\t\t}\n\n\t\t\tRotation getRotation() {\n\t\t\t\treturn getCFrame().getRotation();\n\t\t\t}\n\n\t\t\tvoid setRotation(const Rotation& rotation) {\n\t\t\t\tGlobalCFrame cframe = getCFrame();\n\t\t\t\tcframe.rotation = rotation;\n\n\t\t\t\tsetCFrame(cframe);\n\t\t\t}\n\n\t\t\tDiagonalMat3 getScale() {\n\t\t\t\tif (isRootPart()) {\n\t\t\t\t\treturn std::get<ExtendedPart*>(this->root)->hitbox.scale;\n\t\t\t\t} else {\n\t\t\t\t\treturn std::get<ScaledCFrame>(this->root).scale;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvoid setScale(const DiagonalMat3& scale) {\n\t\t\t\tif (isRootPart()) {\n\t\t\t\t\tstd::get<ExtendedPart*>(this->root)->setScale(scale);\n\t\t\t\t} else {\n\t\t\t\t\tstd::get<ScaledCFrame>(this->root).scale = scale;\n\t\t\t\t}\n\n\t\t\t\tif (onChange != nullptr)\n\t\t\t\t\tonChange();\n\t\t\t}\n\n\t\t\tdouble getWidth() {\n\t\t\t\tif (isRootPart()) {\n\t\t\t\t\treturn std::get<ExtendedPart*>(this->root)->hitbox.getWidth();\n\t\t\t\t} else {\n\t\t\t\t\treturn std::get<ScaledCFrame>(this->root).scale[0] * 2;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvoid setWidth(double width) {\n\t\t\t\tif (isRootPart()) {\n\t\t\t\t\tstd::get<ExtendedPart*>(this->root)->hitbox.setWidth(width);\n\t\t\t\t} else {\n\t\t\t\t\tstd::get<ScaledCFrame>(this->root).scale[0] = width / 2;\n\t\t\t\t}\n\n\t\t\t\tif (onChange != nullptr)\n\t\t\t\t\tonChange();\n\t\t\t}\n\n\t\t\tdouble getHeight() {\n\t\t\t\tif (isRootPart()) {\n\t\t\t\t\treturn std::get<ExtendedPart*>(this->root)->hitbox.getHeight();\n\t\t\t\t} else {\n\t\t\t\t\treturn std::get<ScaledCFrame>(this->root).scale[1] * 2;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvoid setHeight(double height) {\n\t\t\t\tif (isRootPart()) {\n\t\t\t\t\tstd::get<ExtendedPart*>(this->root)->hitbox.setHeight(height);\n\t\t\t\t} else {\n\t\t\t\t\tstd::get<ScaledCFrame>(this->root).scale[1] = height / 2;\n\t\t\t\t}\n\n\t\t\t\tif (onChange != nullptr)\n\t\t\t\t\tonChange();\n\t\t\t}\n\n\t\t\tdouble getDepth() {\n\t\t\t\tif (isRootPart()) {\n\t\t\t\t\treturn std::get<ExtendedPart*>(this->root)->hitbox.getDepth();\n\t\t\t\t} else {\n\t\t\t\t\treturn std::get<ScaledCFrame>(this->root).scale[2] * 2;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvoid setDepth(double depth) {\n\t\t\t\tif (isRootPart()) {\n\t\t\t\t\tstd::get<ExtendedPart*>(this->root)->hitbox.setDepth(depth);\n\t\t\t\t} else {\n\t\t\t\t\tstd::get<ScaledCFrame>(this->root).scale[2] = depth / 2;\n\t\t\t\t}\n\n\t\t\t\tif (onChange != nullptr)\n\t\t\t\t\tonChange();\n\t\t\t}\n\n\t\t\tdouble getMaxRadius() {\n\t\t\t\tif (isRootPart()) {\n\t\t\t\t\treturn std::get<ExtendedPart*>(this->root)->hitbox.getMaxRadius();\n\t\t\t\t} else {\n\t\t\t\t\treturn length(Vec3 { getWidth(), getHeight(), getDepth() });\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tMat4f getModelMatrix(bool scaled = true) {\n\t\t\t\tif (scaled)\n\t\t\t\t\treturn getCFrame().asMat4WithPreScale(getScale());\n\t\t\t\telse\n\t\t\t\t\treturn getCFrame().asMat4();\n\t\t\t}\n\t\t};\n\n\t\t// The name of an entity\n\t\tstruct Name : RC {\n\t\t\tstd::string name;\n\n\t\t\tName(const std::string& name) : name(name) {}\n\n\t\t\tvoid setName(const std::string& name) {\n\t\t\t\tthis->name = name;\n\t\t\t}\n\t\t};\n\n\t\t// The collider of the entity, as it is being physicsed in the engine \n\t\tstruct Collider : RC {\n\t\t\tExtendedPart* part;\n\n\t\t\tCollider(ExtendedPart* part) : part(part) {}\n\n\t\t\tExtendedPart* operator->() const {\n\t\t\t\treturn part;\n\t\t\t}\n\t\t};\n\n\t\tstruct Light : public RC {\n\t\t\tstruct Attenuation {\n\t\t\t\tfloat constant;\n\t\t\t\tfloat linear;\n\t\t\t\tfloat exponent;\n\t\t\t};\n\n\t\t\tGraphics::Color color;\n\t\t\tfloat intensity;\n\t\t\tAttenuation attenuation;\n\n\t\t\tLight(const Graphics::Color& color, float intensity, const Attenuation& attenuation)\n\t\t\t\t: color(color)\n\t\t\t\t, intensity(intensity)\n\t\t\t\t, attenuation(attenuation) {}\n\t\t};\n\n\t\tstruct Attachment : public RC {\n\t\t\tPart* from;\n\t\t\tPart* to;\n\n\t\t\tCFrame* attachment;\n\t\t\tbool isAttachmentToMainPart = false;\n\n\t\t\tAttachment(Part* from, Part* to) : from(from), to(to) {\n\t\t\t\tthis->isAttachmentToMainPart = to->isMainPart();\n\t\t\t\tthis->attachment = &getChildPart()->getAttachToMainPart();\n\t\t\t}\n\n\t\t\tvoid setAttachment(const CFrame& cframe) {\n\t\t\t\tto->getPhysical()->rigidBody.setAttachFor(getChildPart(), cframe);\n\t\t\t}\n\n\t\t\tExtendedPart* getMainPart() {\n\t\t\t\treturn reinterpret_cast<ExtendedPart*>(isAttachmentToMainPart ? to : from);\n\t\t\t}\n\n\t\t\tExtendedPart* getChildPart() {\n\t\t\t\treturn reinterpret_cast<ExtendedPart*>(isAttachmentToMainPart ? from : to);\n\t\t\t}\n\t\t};\n\n\t\tstruct SoftLink : public RC {\n\t\t\tP3D::SoftLink* link;\n\n\t\t\tSoftLink(P3D::SoftLink* link) : link(link) {}\n\n\t\t\tvoid setPositionA(const Vec3& position) {\n\t\t\t\tlink->attachedPartA.attachment.position = position;\n\t\t\t}\n\n\t\t\tvoid setPositionB(const Vec3& position) {\n\t\t\t\tlink->attachedPartB.attachment.position = position;\n\t\t\t}\n\n\t\t\tVec3 getPositionA() const {\n\t\t\t\treturn link->attachedPartA.attachment.position;\n\t\t\t}\n\n\t\t\tVec3 getPositionB() const {\n\t\t\t\treturn link->attachedPartB.attachment.position;\n\t\t\t}\n\t\t};\n\n\t\tstruct MagneticLink : public SoftLink {\n\t\t\tMagneticLink(P3D::MagneticLink* link) : SoftLink(link) {}\n\t\t};\n\n\t\tstruct SpringLink : public SoftLink {\n\t\t\tSpringLink(P3D::SpringLink* link) : SoftLink(link) {}\n\t\t};\n\n\t\tstruct ElasticLink : public SoftLink {\n\t\t\tElasticLink(P3D::ElasticLink* link) : SoftLink(link) {}\n\t\t};\n\n\t\tstruct AlignmentLink : public SoftLink {\n\t\t\tAlignmentLink(P3D::AlignmentLink* link) : SoftLink(link) {}\n\t\t};\n\n\t\tstruct HardConstraint : public RC {\n\t\t\tHardPhysicalConnection* hardConstraint;\n\n\t\t\tHardConstraint(HardPhysicalConnection* hardConstraint) : hardConstraint(hardConstraint) {}\n\n\t\t\tCFrame* getChildAttachment() {\n\t\t\t\treturn &hardConstraint->attachOnChild;\n\t\t\t}\n\n\t\t\tCFrame* getParentAttachment() {\n\t\t\t\treturn &hardConstraint->attachOnParent;\n\t\t\t}\n\t\t};\n\n\t\tstruct FixedConstraint : public HardConstraint {\n\t\t\tFixedConstraint(HardPhysicalConnection* connection) : HardConstraint(connection) {}\n\t\t};\n\t}\n\n};\n"
  },
  {
    "path": "application/ecs/entityBuilder.h",
    "content": "#pragma once\n\n#include <sstream>\n\n#include \"../engine/ecs/registry.h\"\n#include \"components.h\"\n\nnamespace P3D::Application {\n\nclass EntityBuilder {\nprivate:\n\tEngine::Registry64& registry;\n\tEngine::Registry64::entity_type entity;\n\t\npublic:\n\texplicit EntityBuilder(Engine::Registry64& registry) : registry(registry), entity(registry.create()) {}\n\tEntityBuilder(Engine::Registry64& registry, const Engine::Registry64::entity_type& entity) : registry(registry), entity(entity) {}\n\n\t[[nodiscard]] Engine::Registry64::entity_type get() const {\n\t\treturn entity;\n\t}\n\t\n\tEntityBuilder& parent(const Engine::Registry64::entity_type& entity) {\n\t\tthis->registry.setParent(this->entity, entity);\n\n\t\treturn *this;\n\t}\n\n\ttemplate<typename... Args>\n\tEntityBuilder& transform(Args&&... args) {\n\t\tthis->registry.add<Comp::Transform>(this->entity, std::forward<Args>(args)...);\n\t\t\n\t\treturn *this;\n\t}\n\n\ttemplate<typename... Args>\n\tEntityBuilder& name(Args&&... args) {\n\t\tthis->registry.add<Comp::Name>(this->entity, std::forward<Args>(args)...);\n\n\t\treturn *this;\n\t}\n\n\ttemplate<typename... Args>\n\tEntityBuilder& light(Args&&... args) {\n\t\tthis->registry.add<Comp::Light>(this->entity, std::forward<Args>(args)...);\n\n\t\treturn *this;\n\t}\n\n\ttemplate<typename... Args>\n\tEntityBuilder& collider(Args&&... args) {\n\t\tthis->registry.add<Comp::Collider>(this->entity, std::forward<Args>(args)...);\n\n\t\treturn *this;\n\t}\n\n\ttemplate<typename... Args>\n\tEntityBuilder& mesh(Args&&... args) {\n\t\tthis->registry.add<Graphics::Comp::Mesh>(this->entity, std::forward<Args>(args)...);\n\n\t\treturn *this;\n\t}\n\n\ttemplate<typename... Args>\n\tEntityBuilder& material(Args&&... args) {\n\t\tthis->registry.add<Graphics::Comp::Material>(this->entity, std::forward<Args>(args)...);\n\n\t\treturn *this;\n\t}\n\n\ttemplate<typename... Args>\n\tEntityBuilder& hitbox(Args&&... args) {\n\t\tthis->registry.add<Comp::Hitbox>(this->entity, std::forward<Args>(args)...);\n\n\t\treturn *this;\n\t}\n\t\t\n\ttemplate<typename... Args>\n\tEntityBuilder& attachment(Args&&... args) {\n\t\tthis->registry.add<Comp::Attachment>(this->entity, std::forward<Args>(args)...);\n\n\t\treturn *this;\n\t}\n\n\ttemplate<typename... Args>\n\tEntityBuilder& magneticLink(Args&&... args) {\n\t\tthis->registry.add<Comp::MagneticLink>(this->entity, std::forward<Args>(args)...);\n\n\t\treturn *this;\n\t}\n\n\ttemplate<typename... Args>\n\tEntityBuilder& elasticLink(Args&&... args) {\n\t\tthis->registry.add<Comp::ElasticLink>(this->entity, std::forward<Args>(args)...);\n\n\t\treturn *this;\n\t}\n\n\ttemplate<typename... Args>\n\tEntityBuilder& springLink(Args&&... args) {\n\t\tthis->registry.add<Comp::SpringLink>(this->entity, std::forward<Args>(args)...);\n\n\t\treturn *this;\n\t}\n\n\ttemplate<typename... Args>\n\tEntityBuilder& alignmentLink(Args&&... args) {\n\t\tthis->registry.add<Comp::AlignmentLink>(this->entity, std::forward<Args>(args)...);\n\n\t\treturn *this;\n\t}\n\n\ttemplate<typename... Args>\n\tEntityBuilder& fixedConstraint(Args&&... args) {\n\t\tthis->registry.add<Comp::FixedConstraint>(this->entity, std::forward<Args>(args)...);\n\n\t\treturn *this;\n\t}\n};\n\n}"
  },
  {
    "path": "application/eventHandler.cpp",
    "content": "#include \"core.h\"\n\n#include \"eventHandler.h\"\n\n#include \"view/screen.h\"\n#include \"extendedPart.h\"\n\nnamespace P3D::Application {\n\nvoid* EventHandler::getPtr() const {\n\treturn pointer;\n}\n\nvoid EventHandler::setPtr(void* ptr) {\n\tpointer = ptr;\n}\n\nvoid EventHandler::setCameraMoveCallback(CameraMoveHandler handler) {\n\tcameraMoveHandler = handler;\n}\n\nvoid EventHandler::setWindowResizeCallback(WindowResizeHandler handler) {\n\twindowResizeHandler = handler;\n}\n\nvoid EventHandler::setPartRayIntersectCallback(PartRayIntersectHandler handler) {\n\tpartRayIntersectHandler = handler;\n}\n\nvoid EventHandler::setPartDragCallback(PartDragHandler handler) {\n\tpartDragHandler = handler;\n}\n\nvoid EventHandler::setPartClickCallback(PartClickHandler handler) {\n\tpartClickHandler = handler;\n}\n\nvoid EventHandler::setPartTouchCallback(PartTouchHandler handler) {\n\tpartTouchHandler = handler;\n}\n\nvoid EventHandler::setPartReleaseCallback(PartReleaseHandler handler) {\n\tpartReleaseHandler = handler;\n}\n\n};"
  },
  {
    "path": "application/eventHandler.h",
    "content": "#pragma once\n\nnamespace P3D::Application {\n\nclass Screen;\nstruct Camera;\nstruct ExtendedPart;\n\ntypedef void (*CameraMoveHandler) (Screen&, Camera*, Vec3);\ntypedef void (*WindowResizeHandler) (Screen&, Vec2i);\ntypedef void (*PartRayIntersectHandler) (Screen&, ExtendedPart*, Position);\ntypedef void (*PartDragHandler) (Screen&, ExtendedPart*, Vec3);\ntypedef void (*PartClickHandler) (Screen&, ExtendedPart*, Vec3);\ntypedef void (*PartTouchHandler) (ExtendedPart*, ExtendedPart*, Vec3);\ntypedef void (*PartReleaseHandler) (ExtendedPart*, ExtendedPart*);\n\nclass EventHandler {\nprivate:\n\tvoid* pointer = nullptr;\n\npublic:\n\tCameraMoveHandler cameraMoveHandler = [] (Screen&, Camera*, Vec3) {};\n\tWindowResizeHandler windowResizeHandler = [] (Screen&, Vec2i) {};\n\tPartRayIntersectHandler partRayIntersectHandler = [] (Screen&, ExtendedPart*, Position) {};\n\tPartDragHandler partDragHandler = [] (Screen&, ExtendedPart*, Vec3) {};\n\tPartClickHandler partClickHandler = [] (Screen&, ExtendedPart*, Vec3) {};\n\tPartTouchHandler partTouchHandler = [] (ExtendedPart*, ExtendedPart*, Vec3) {};\n\tPartReleaseHandler partReleaseHandler = [] (ExtendedPart*, ExtendedPart*) {};\n\n\tvoid* getPtr() const;\n\tvoid setPtr(void* ptr);\n\tvoid setCameraMoveCallback(CameraMoveHandler handler);\n\tvoid setWindowResizeCallback(WindowResizeHandler handler);\n\tvoid setPartRayIntersectCallback(PartRayIntersectHandler handler);\n\tvoid setPartDragCallback(PartDragHandler handler);\n\tvoid setPartClickCallback(PartClickHandler handler);\n\tvoid setPartTouchCallback(PartTouchHandler handler);\n\tvoid setPartReleaseCallback(PartReleaseHandler handler);\n};\n\n}"
  },
  {
    "path": "application/extendedPart.cpp",
    "content": "#include \"core.h\"\n\n#include \"application.h\"\n#include \"extendedPart.h\"\n#include \"ecs/components.h\"\n#include \"view/screen.h\"\n#include \"../engine/ecs/registry.h\"\n#include <Physics3D/misc/serialization/serialization.h>\n#include \"../graphics/meshRegistry.h\"\n\nnamespace P3D::Application {\n\nExtendedPart::ExtendedPart(Part&& part, const Graphics::Comp::Mesh& mesh, const std::string& name, const Entity& parent)\n\t: Part(std::move(part)) {\n\tif (this->entity == Engine::Registry64::null_entity)\n\t\tthis->entity = screen.registry.create();\n\n\tif (parent != Engine::Registry64::null_entity)\n\t\tscreen.registry.setParent(this->entity, parent);\n\n\tscreen.registry.add<Graphics::Comp::Mesh>(this->entity, mesh);\n\tscreen.registry.add<Comp::Hitbox>(this->entity, this);\n\tscreen.registry.add<Comp::Transform>(this->entity, this);\n\tif (!name.empty())\n\t\tscreen.registry.add<Comp::Name>(this->entity, name);\n}\n\nExtendedPart::ExtendedPart(const Shape& hitbox,\n                           const GlobalCFrame& position,\n                           const PartProperties& properties,\n                           const Graphics::Comp::Mesh& mesh,\n                           const std::string& name,\n                           const Entity& parent)\n\t: Part(hitbox, position, properties) {\n\tif (this->entity == Engine::Registry64::null_entity)\n\t\tthis->entity = screen.registry.create();\n\n\tif (parent != Engine::Registry64::null_entity)\n\t\tscreen.registry.setParent(this->entity, parent);\n\n\tscreen.registry.add<Graphics::Comp::Mesh>(this->entity, mesh);\n\tscreen.registry.add<Comp::Hitbox>(this->entity, this);\n\tscreen.registry.add<Comp::Transform>(this->entity, this);\n\tif (!name.empty())\n\t\tscreen.registry.add<Comp::Name>(this->entity, name);\n}\n\nExtendedPart::ExtendedPart(Part&& part, const std::string& name, const Entity& parent)\n\t: Part(std::move(part)) {\n\tif (this->entity == Engine::Registry64::null_entity)\n\t\tthis->entity = screen.registry.create();\n\n\tif (parent != Engine::Registry64::null_entity)\n\t\tscreen.registry.setParent(this->entity, parent);\n\n\tscreen.registry.add<Graphics::Comp::Mesh>(this->entity, Graphics::MeshRegistry::getMesh(part.hitbox.baseShape.get()));\n\tscreen.registry.add<Comp::Hitbox>(this->entity, this);\n\tscreen.registry.add<Comp::Transform>(this->entity, this);\n\tif (!name.empty())\n\t\tscreen.registry.add<Comp::Name>(this->entity, name);\n}\n\nExtendedPart::ExtendedPart(const Shape& hitbox,\n                           const GlobalCFrame& position,\n                           const PartProperties& properties,\n                           const std::string& name,\n                           const Entity& parent)\n\t: Part(hitbox, position, properties) {\n\tif (this->entity == Engine::Registry64::null_entity)\n\t\tthis->entity = screen.registry.create();\n\n\tif (parent != Engine::Registry64::null_entity)\n\t\tscreen.registry.setParent(this->entity, parent);\n\n\tscreen.registry.add<Graphics::Comp::Mesh>(this->entity, Graphics::MeshRegistry::getMesh(hitbox.baseShape.get()));\n\tscreen.registry.add<Comp::Hitbox>(this->entity, this);\n\tscreen.registry.add<Comp::Transform>(this->entity, this);\n\tif (!name.empty())\n\t\tscreen.registry.add<Comp::Name>(this->entity, name);\n}\n\nExtendedPart::ExtendedPart(const Shape& hitbox,\n                           ExtendedPart* attachTo,\n                           const CFrame& attach,\n                           const PartProperties& properties,\n                           const std::string& name,\n                           const Entity& parent)\n\t: Part(hitbox, *attachTo, attach, properties) {\n\tif (this->entity == Engine::Registry64::null_entity)\n\t\tthis->entity = screen.registry.create();\n\n\tif (parent != Engine::Registry64::null_entity)\n\t\tscreen.registry.setParent(this->entity, parent);\n\n\tscreen.registry.add<Graphics::Comp::Mesh>(this->entity, Graphics::MeshRegistry::getMesh(hitbox.baseShape.get()));\n\tscreen.registry.add<Comp::Hitbox>(this->entity, this);\n\tscreen.registry.add<Comp::Transform>(this->entity, this);\n\tif (!name.empty())\n\t\tscreen.registry.add<Comp::Name>(this->entity, name);\n}\n\nExtendedPart::~ExtendedPart() {\n\t// have to do the same as Part's destructor here, because if I don't then PlayerWorld tries to update a deleted entity\n\tthis->removeFromWorld();\n\tif (this->entity != Engine::Registry64::null_entity) \n\t\tscreen.registry.destroy(this->entity);\n}\n\nvoid ExtendedPart::setMaterial(const Graphics::Comp::Material& material) {\n\tscreen.registry.add<Graphics::Comp::Material>(this->entity, material);\n}\n\nvoid ExtendedPart::setName(const std::string& name) {\n\tscreen.registry.add<Comp::Name>(this->entity, name);\n}\n\nvoid ExtendedPart::setColor(const Graphics::Color& color) {\n\tscreen.registry.getOrAdd<Graphics::Comp::Material>(this->entity)->albedo = color;\n}\n\nGraphics::Color ExtendedPart::getColor() const {\n\treturn screen.registry.get<Graphics::Comp::Material>(this->entity)->albedo;\n}\n\n};\n"
  },
  {
    "path": "application/extendedPart.h",
    "content": "#pragma once\n\n#include \"../graphics/ecs/components.h\"\n#include \"../graphics/extendedTriangleMesh.h\"\n#include <Physics3D/part.h>\n#include \"../engine/ecs/registry.h\"\n\nnamespace P3D::Application {\n\nstruct ExtendedPart : public Part {\n\tusing Entity = Engine::Registry64::entity_type;\n\npublic:\n\tEntity entity = 0;\n\n\tExtendedPart() = default;\n\tExtendedPart(Part&& part, const std::string& name = \"\", const Entity& parent = 0);\n\tExtendedPart(Part&& part, const Graphics::Comp::Mesh& mesh, const std::string& name = \"\", const Entity& parent = 0);\n\tExtendedPart(const Shape& hitbox, const GlobalCFrame& position, const PartProperties& properties, const std::string& name = \"\", const Entity& parent = 0);\n\tExtendedPart(const Shape& hitbox, const GlobalCFrame& position, const PartProperties& properties, const Graphics::Comp::Mesh& mesh, const std::string& name = \"\", const Entity& parent = 0);\n\tExtendedPart(const Shape& hitbox, ExtendedPart* attachTo, const CFrame& attach, const PartProperties& properties, const std::string& name = \"\", const Entity& parent = 0);\n\n\t~ExtendedPart();\n\n\tvoid setMaterial(const Graphics::Comp::Material& material);\n\tvoid setName(const std::string& name);\n\n\tvoid setColor(const Graphics::Color& color);\n\tGraphics::Color getColor() const;\n};\n\n};"
  },
  {
    "path": "application/input/playerController.cpp",
    "content": "#include \"core.h\"\n\n#include \"playerController.h\"\n\n\n#include <Physics3D/world.h>\n\n#include \"application.h\"\n#include \"view/screen.h\"\n#include \"standardInputHandler.h\"\n#include \"engine/options/keyboardOptions.h\"\n#include \"../extendedPart.h\"\n\n#define RUN_SPEED 5\n#define JUMP_SPEED 6\n#define AIR_RUN_SPEED_FACTOR 2\n\n\nnamespace P3D::Application {\nvoid PlayerController::apply(WorldPrototype* world) {\n\t// Player movement\n\tif(!screen.camera.flying) {\n\t\tusing namespace Engine;\n\t\tExtendedPart* player = screen.camera.attachment;\n\t\tPhysical* playerPhys = player->getPhysical();\n\n\t\tVec3f playerX = screen.camera.cframe.rotation * Vec3(1, 0, 0);\n\t\tVec3f playerZ = screen.camera.cframe.rotation * Vec3(0, 0, 1);\n\n\t\tVec3 up(0, 1, 0);\n\t\tVec3 forward = normalize(playerZ % up % up);\n\t\tVec3 right = -normalize(playerX % up % up);\n\n\t\tVec3 total(0, 0, 0);\n\t\tif(handler->getKey(KeyboardOptions::Move::forward))\n\t\t\ttotal += forward;\n\t\tif(handler->getKey(KeyboardOptions::Move::backward))\n\t\t\ttotal -= forward;\n\t\tif(handler->getKey(KeyboardOptions::Move::right))\n\t\t\ttotal += right;\n\t\tif(handler->getKey(KeyboardOptions::Move::left))\n\t\t\ttotal -= right;\n\n\t\tVec3 runVector = (lengthSquared(total) >= 0.00005) ? normalize(total) * RUN_SPEED : Vec3(0, 0, 0);\n\t\tVec3 desiredSpeed = runVector;\n\t\tVec3 actualSpeed = playerPhys->getMotion().getVelocity();\n\t\tVec3 speedToGain = desiredSpeed - actualSpeed;\n\t\tspeedToGain.y = 0;\n\n\t\tplayerPhys->mainPhysical->applyForceAtCenterOfMass(speedToGain * player->getMass() * AIR_RUN_SPEED_FACTOR);\n\n\t\tif(handler->getKey(KeyboardOptions::Move::jump))\n\t\t\trunVector += Vec3(0, JUMP_SPEED, 0);\n\n\t\tplayer->properties.conveyorEffect = runVector;\n\t}\n}\n};\n\n\n"
  },
  {
    "path": "application/input/playerController.h",
    "content": "#pragma once\n\n#include <Physics3D/externalforces/externalForce.h>\n\nnamespace P3D::Application {\n\nclass PlayerController : public ExternalForce {\n\tvirtual void apply(WorldPrototype* world) override;\n};\n\n};\n"
  },
  {
    "path": "application/input/standardInputHandler.cpp",
    "content": "#include \"core.h\"\n\n#include \"standardInputHandler.h\"\n\n#include <Physics3D/misc/toString.h>\n#include <Physics3D/world.h>\n#include <Physics3D/layer.h>\n\n\n#include \"../engine/input/keyboard.h\"\n\n#include \"../application/worldBuilder.h\"\n#include \"../engine/options/keyboardOptions.h\"\n#include \"../graphics/renderer.h\"\n#include \"../application.h\"\n#include \"../graphics/gui/gui.h\"\n#include \"../graphics/debug/visualDebug.h\"\n#include \"../graphics/buffers/frameBuffer.h\"\n#include \"../graphics/glfwUtils.h\"\n#include \"../worlds.h\"\n#include \"../view/screen.h\"\n#include \"ecs/components.h\"\n#include \"../view/camera.h\"\n#include <random>\n\n#include \"layer/pickerLayer.h\"\n#include \"../picker/tools/translationTool.h\"\n\nnamespace P3D::Application {\n\n#define KEY_BIND(name) \\\n\tif (key == name)\n\n#define KEY_RANGE(first, second) \\\n\tif (key > first && key < second)\n\t\nStandardInputHandler::StandardInputHandler(GLFWwindow* window, Screen& screen) : InputHandler(window), screen(screen) {}\n\nvoid StandardInputHandler::onEvent(Engine::Event& event) {\n\tusing namespace Engine;\n\n\tApplication::onEvent(event);\n\n\tEventDispatcher dispatcher(event);\n\n\tif (dispatcher.dispatch<KeyPressEvent>(EVENT_BIND(StandardInputHandler::onKeyPress)))\n\t\treturn;\n\n\tif (dispatcher.dispatch<DoubleKeyPressEvent>(EVENT_BIND(StandardInputHandler::onDoubleKeyPress)))\n\t\treturn;\n\n\tif (dispatcher.dispatch<WindowResizeEvent>(EVENT_BIND(StandardInputHandler::onWindowResize)))\n\t\treturn;\n\n}\n\nbool StandardInputHandler::onWindowResize(Engine::WindowResizeEvent& event) {\n\tVec2i dimension = Vec2i(event.getWidth(), event.getHeight());\n\n\tGraphics::Renderer::viewport(Vec2i(), dimension);\n\n\t(*screen.eventHandler.windowResizeHandler) (screen, dimension);\n\n\treturn true;\n}\n\nbool StandardInputHandler::onFrameBufferResize(Engine::FrameBufferResizeEvent& event) {\n\tVec2i dimension = Vec2i(event.getWidth(), event.getHeight());\n\n\tGraphics::Renderer::viewport(Vec2i(), dimension);\n\t\n\tfloat aspect = float(dimension.x) / float(dimension.y);\n\tscreen.camera.onUpdate(aspect);\n\tscreen.dimension = dimension;\n\tscreen.screenFrameBuffer->resize(screen.dimension);\n\n\tGraphics::GUI::windowInfo.aspect = aspect;\n\tGraphics::GUI::windowInfo.dimension = dimension;\n\n\t(*screen.eventHandler.windowResizeHandler) (screen, dimension);\n\n\treturn true;\n}\n\nbool StandardInputHandler::onKeyPressOrRepeat(Engine::KeyPressEvent& event) {\n\tusing namespace Engine;\n\n\tKey key = event.getKey();\n\n\tKEY_BIND(KeyboardOptions::Tick::Speed::up) {\n\t\tsetSpeed(getSpeed() * 1.5);\n\t\tLog::info(\"TPS is now: %f\", getSpeed());\n\t}\n\t\n\tKEY_BIND(KeyboardOptions::Tick::Speed::down) {\n\t\tsetSpeed(getSpeed() / 1.5);\n\t\tLog::info(\"TPS is now: %f\", getSpeed());\n\t}\n\n\tKEY_BIND(KeyboardOptions::Tick::run) {\n\t\tif (isPaused()) runTick();\n\t}\n\n\tKEY_BIND(Keyboard::KEY_O) {\n\t\tstd::unique_lock<UpgradeableMutex> worldLock(*screen.worldMutex);\n\t\tPosition pos(0.0 + (rand() % 100) * 0.001, 1.0 + (rand() % 100) * 0.001, 0.0 + (rand() % 100) * 0.001);\n\t\tWorldBuilder::createDominoAt(GlobalCFrame(pos, Rotation::fromEulerAngles(0.2, 0.3, 0.7)));\n\n\t\tLog::info(\"Created domino! There are %d objects in the world! \", screen.world->getPartCount());\n\t}\n\n\treturn true;\n}\n\nbool StandardInputHandler::onKeyPress(Engine::KeyPressEvent& event) {\n\tusing namespace Graphics::VisualDebug;\n\tusing namespace Engine;\n\n\tKey key = event.getKey();\n\n\tKEY_BIND(KeyboardOptions::Tick::pause) {\n\t\ttogglePause();\n\t}\n\n\tKEY_BIND(KeyboardOptions::Part::remove) {\n\t\tif (screen.selectedPart != nullptr) {\n\t\t\tstd::unique_lock<UpgradeableMutex> worldLock(*screen.worldMutex);\n\t\t\tdelete screen.selectedPart;\n\t\t\tTranslationTool::magnet.selectedPart = nullptr;\n\t\t\tscreen.selectedPart = nullptr;\n\t\t}\n\t}\n\n\tKEY_BIND(KeyboardOptions::Debug::pies) {\n\t\trenderPiesEnabled = !renderPiesEnabled;\n\t}\n\t\n\tKEY_BIND(KeyboardOptions::Part::makeMainPart) {\n\t\tLog::info(\"Made %s the main part of it's physical\", screen.registry.getOr<Comp::Name>(screen.selectedPart->entity, \"\").name.c_str());\n\t\tscreen.selectedPart->makeMainPart();\n\t}\n\t\n\tKEY_BIND(KeyboardOptions::Part::makeMainPhysical) {\n\t\tif (screen.selectedPart) {\n\t\t\tPhysical* selectedPartPhysical = screen.selectedPart->getPhysical();\n\t\t\tif (selectedPartPhysical != nullptr) {\n\t\t\t\tif (!selectedPartPhysical->isMainPhysical()) {\n\t\t\t\t\tLog::info(\"Made %s the main physical\", screen.registry.getOr<Comp::Name>(screen.selectedPart->entity, \"\").name.c_str());\n\t\t\t\t\t((ConnectedPhysical*) selectedPartPhysical)->makeMainPhysical();\n\t\t\t\t} else {\n\t\t\t\t\tLog::warn(\"This physical is already the main physical!\");\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tLog::warn(\"This part has no physical!\");\n\t\t\t}\n\t\t}\n\t}\n\t\n\tKEY_BIND(KeyboardOptions::World::valid) {\n\t\tLog::debug(\"Checking World::isValid()\");\n\t\tstd::shared_lock<UpgradeableMutex> worldReadLock(*screen.worldMutex);\n\t\tif(screen.world->isValid()) {\n\t\t\tLog::info(\"World is valid!\");\n\t\t} else {\n\t\t\tLog::info(\"World is not valid!\");\n\t\t}\n\t}\n\t\n\tKEY_BIND(KeyboardOptions::Edit::rotate) {\n\t\tPickerLayer::toolManagers[0].selectTool(\"Rotate\");\n\t}\n\t\n\tKEY_BIND(KeyboardOptions::Edit::translate) {\n\t\tPickerLayer::toolManagers[0].selectTool(\"Translate\");\n\t}\n\t\n\tKEY_BIND(KeyboardOptions::Edit::scale) {\n\t\tPickerLayer::toolManagers[0].selectTool(\"Scale\");\n\t}\n\n\tKEY_BIND(KeyboardOptions::Edit::select) {\n\t\tPickerLayer::toolManagers[0].selectTool(\"Select\");\n\t}\n\n\tKEY_BIND(KeyboardOptions::Edit::region) {\n\t\tPickerLayer::toolManagers[0].selectTool(\"Select region\");\n\t}\n\t\n\tKEY_BIND(KeyboardOptions::Debug::spheres) {\n\t\tcolissionSpheresMode = static_cast<SphereColissionRenderMode>((static_cast<int>(colissionSpheresMode) + 1) % 3);\n\t}\n\t\n\tKEY_BIND(KeyboardOptions::Debug::tree) {\n\t\tcolTreeRenderMode++;\n\t\tint worldLayerCount = getMaxLayerID(world.layers); // must be a signed int, because size_t comparison makes the comparison unsigned\n\t\tif(colTreeRenderMode >= worldLayerCount) {\n\t\t\tcolTreeRenderMode = -2;\n\t\t}\n\t}\n\t\n\tKEY_BIND(KeyboardOptions::Application::close) {\n\t\tGraphics::GLFW::closeWindow();\n\t} else if (key == Keyboard::KEY_F11) {\n\t\tGraphics::GLFW::swapFullScreen();\n\t}\n\n\tKEY_RANGE(Keyboard::KEY_F1, Keyboard::KEY_F9) {\n\t\ttoggleVectorType(static_cast<Debug::VectorType>(key.getCode() - Keyboard::KEY_F1.getCode()));\n\t}\n\n\tKEY_RANGE(Keyboard::KEY_NUMBER_1, Keyboard::KEY_NUMBER_3) {\n\t\ttogglePointType(static_cast<Debug::PointType>(key.getCode() - Keyboard::KEY_NUMBER_1.getCode()));\n\t}\n\n\treturn onKeyPressOrRepeat(event);\n};\n\nbool StandardInputHandler::onDoubleKeyPress(Engine::DoubleKeyPressEvent& event) {\n\tusing namespace Engine;\n\n\tKey key = event.getKey();\n\n\tKEY_BIND(KeyboardOptions::Move::fly) {\n\t\ttoggleFlying();\n\t}\n\n\treturn true;\n}\n\n};"
  },
  {
    "path": "application/input/standardInputHandler.h",
    "content": "#pragma once\n\n#include \"../engine/input/inputHandler.h\"\n#include \"../engine/event/keyEvent.h\"\n#include \"../engine/event/windowEvent.h\"\n\nnamespace P3D::Application {\n\nclass Screen;\n\nclass StandardInputHandler : public Engine::InputHandler {\npublic:\n\tScreen& screen;\n\n\tStandardInputHandler(GLFWwindow* window, Screen& screen);\n\n\tvoid onEvent(Engine::Event& event) override;\n\n\tbool onFrameBufferResize(Engine::FrameBufferResizeEvent& event);\n\tbool onWindowResize(Engine::WindowResizeEvent& event);\n\tbool onKeyPress(Engine::KeyPressEvent& event);\n\tbool onKeyPressOrRepeat(Engine::KeyPressEvent& event);\n\tbool onDoubleKeyPress(Engine::DoubleKeyPressEvent& event);\n};\n\n};"
  },
  {
    "path": "application/io/saveDialog.cpp",
    "content": "#include \"core.h\"\n\n#include \"saveDialog.h\"\n\n#include <iostream>\n#include <stddef.h>\n#include <string.h>\n\nnamespace P3D::Application {\n#ifdef _WIN32\n#include <Windows.h>\n\nbool saveWorldDialog(char* worldFilePath) {\n\t//glfwGetWin32Window(window);\n\n\tOPENFILENAME ofn;\n\tstrcpy(worldFilePath, \"new.world\");\n\n\tZeroMemory(&ofn, sizeof(ofn));\n\n\tofn.lStructSize = sizeof(ofn);\n\t//ofn.hwndOwner = hwnd;\n\tofn.lpstrFilter = \"World Files (*.world)\\0*.world\\0All Files (*.*)\\0*.*\\0\";\n\tofn.lpstrFile = worldFilePath;\n\tofn.nMaxFile = MAX_PATH;\n\tofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;\n\tofn.lpstrDefExt = \"world\";\n\n\treturn GetSaveFileName(&ofn); // saves the filename to input parameter worldFilePath, returns true if user confirmed\n}\nbool openWorldDialog(char* worldFilePath) {\n\t//glfwGetWin32Window(window);\n\n\tOPENFILENAME ofn;\n\tstrcpy(worldFilePath, \"\");\n\n\tZeroMemory(&ofn, sizeof(ofn));\n\n\tofn.lStructSize = sizeof(ofn);\n\t//ofn.hwndOwner = hwnd;\n\tofn.lpstrFilter = \"World Files (*.world)\\0*.world\\0All Files (*.*)\\0*.*\\0\";\n\tofn.lpstrFile = worldFilePath;\n\tofn.nMaxFile = MAX_PATH;\n\tofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;\n\tofn.lpstrDefExt = \"world\";\n\n\treturn GetOpenFileName(&ofn); // saves the filename to input parameter worldFilePath, returns true if user confirmed\n}\n#else\nstatic void stripFinalNewlines(char* fileName) {\n\tstd::size_t lastChar = strlen(fileName) - 1;\n\twhile(isspace(fileName[lastChar])){\n\t\tfileName[lastChar] = '\\0';\n\t\tlastChar--;\n\t}\n}\nbool saveWorldDialog(char* worldFilePath) {\n\tFILE* fileDialog = popen(\"zenity --file-selection --save --confirm-overwrite --file-filter=*.world  2>/dev/null\", \"r\");\n\tif(fileDialog != NULL) {\n\t\tif(!fgets(worldFilePath, MAX_PATH_LENGTH, fileDialog)) throw \"fgets error!\";\n\t\tif(pclose(fileDialog) == 0) { // OK save file\n\t\t\tstripFinalNewlines(worldFilePath);\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t} else {\n\t\tstd::cout << \"Save *.world to> \";\n\t\tstd::string fileName;\n\t\tstd::cin >> fileName;\n\n\t\tif(fileName.empty()) return false;\n\t\tstrcpy(worldFilePath, fileName.c_str());\n\t\treturn true;\n\t}\n}\nbool openWorldDialog(char* worldFilePath) {\n\tFILE* fileDialog = popen(\"zenity --file-selection --file-filter=*.world  2>/dev/null\", \"r\");\n\tif(fileDialog != NULL) {\n\t\tif(!fgets(worldFilePath, MAX_PATH_LENGTH, fileDialog)) throw \"fgets error!\";\n\t\tif(pclose(fileDialog) == 0) { // OK save file\n\t\t\tstripFinalNewlines(worldFilePath);\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t} else {\n\t\tstd::cout << \"Input world to open> \";\n\t\tstd::string fileName;\n\t\tstd::cin >> fileName;\n\n\t\tif(fileName.empty()) return false;\n\t\tstrcpy(worldFilePath, fileName.c_str());\n\t\treturn true;\n\t}\n}\n#endif\n};\n"
  },
  {
    "path": "application/io/saveDialog.h",
    "content": "#pragma once\n\nnamespace P3D::Application {\n\nconstexpr size_t MAX_PATH_LENGTH = 1024;\n// returns true if user selected save\nbool saveWorldDialog(char* worldFilePath);\n// returns true if user selected open\nbool openWorldDialog(char* worldFilePath);\n};"
  },
  {
    "path": "application/io/serialization.cpp",
    "content": "#include \"core.h\"\n\n#include \"serialization.h\"\n\n#include \"../util/fileUtils.h\"\n\n#include \"extendedPart.h\"\n#include \"application.h\"\n#include \"view/screen.h\"\n#include \"ecs/components.h\"\n#include \"../engine/ecs/registry.h\"\n#include <Physics3D/world.h>\n#include \"../worlds.h\"\n\n#include <Physics3D/externalforces/directionalGravity.h>\n#include <Physics3D/misc/toString.h>\n#include <Physics3D/misc/serialization/serialization.h>\n\n#include <fstream>\n#include <sstream>\n\nnamespace P3D::Application {\n\nFixedSharedObjectSerializerDeserializer<Graphics::Texture*> textureSerializer{nullptr};\n\nvoid WorldImportExport::registerTexture(Graphics::Texture* texture) {\n\ttextureSerializer.registerObject(texture);\n}\n\nstatic void serializeMaterial(const Graphics::Comp::Material& material, std::ostream& ostream) {\n\ttextureSerializer.serialize(material.get(Graphics::Comp::Material::Map_Albedo).get(), ostream);\n\ttextureSerializer.serialize(material.get(Graphics::Comp::Material::Map_Normal).get(), ostream);\n\ttextureSerializer.serialize(material.get(Graphics::Comp::Material::Map_Metalness).get(), ostream);\n\ttextureSerializer.serialize(material.get(Graphics::Comp::Material::Map_Roughness).get(), ostream);\n\ttextureSerializer.serialize(material.get(Graphics::Comp::Material::Map_AO).get(), ostream);\n\ttextureSerializer.serialize(material.get(Graphics::Comp::Material::Map_Gloss).get(), ostream);\n\ttextureSerializer.serialize(material.get(Graphics::Comp::Material::Map_Specular).get(), ostream);\n\ttextureSerializer.serialize(material.get(Graphics::Comp::Material::Map_Displacement).get(), ostream);\n\tserializeBasicTypes<Graphics::Color>(material.albedo, ostream);\n\tserializeBasicTypes<float>(material.metalness, ostream);\n\tserializeBasicTypes<float>(material.roughness, ostream);\n\tserializeBasicTypes<float>(material.ao, ostream);\n}\n\nstatic Graphics::Comp::Material deserializeMaterial(std::istream& istream) {\n\tSRef<Graphics::Texture> albedoMap(textureSerializer.deserialize(istream));\n\tSRef<Graphics::Texture> normalMap(textureSerializer.deserialize(istream));\n\tSRef<Graphics::Texture> metalnessMap(textureSerializer.deserialize(istream));\n\tSRef<Graphics::Texture> roughnessMap(textureSerializer.deserialize(istream));\n\tSRef<Graphics::Texture> aoMap(textureSerializer.deserialize(istream));\n\tSRef<Graphics::Texture> glossMap(textureSerializer.deserialize(istream));\n\tSRef<Graphics::Texture> specularMap(textureSerializer.deserialize(istream));\n\tSRef<Graphics::Texture> displacementrMap(textureSerializer.deserialize(istream));\n\tGraphics::Color albedo = deserializeBasicTypes<Graphics::Color>(istream);\n\tfloat metalness = deserializeBasicTypes<float>(istream);\n\tfloat roughness = deserializeBasicTypes<float>(istream);\n\tfloat ao = deserializeBasicTypes<float>(istream);\n\n\tGraphics::Comp::Material material = Graphics::Comp::Material(albedo, metalness, roughness, ao);\n\tmaterial.set(Graphics::Comp::Material::Map_Albedo, albedoMap);\n\tmaterial.set(Graphics::Comp::Material::Map_Normal, normalMap);\n\tmaterial.set(Graphics::Comp::Material::Map_Metalness, metalnessMap);\n\tmaterial.set(Graphics::Comp::Material::Map_Roughness, roughnessMap);\n\tmaterial.set(Graphics::Comp::Material::Map_AO, aoMap);\n\tmaterial.set(Graphics::Comp::Material::Map_Gloss, glossMap);\n\tmaterial.set(Graphics::Comp::Material::Map_Specular, specularMap);\n\tmaterial.set(Graphics::Comp::Material::Map_Displacement, displacementrMap);\n\n\treturn material;\n}\n\nclass Serializer : public SerializationSession<ExtendedPart> {\npublic:\n\tusing SerializationSession<ExtendedPart>::SerializationSession;\n\tvirtual void serializePartExternalData(const ExtendedPart& part, std::ostream& ostream) override {\n\t\t// TODO integrate components into serialization\n\t\tserializeMaterial(screen.registry.getOr<Graphics::Comp::Material>(part.entity), ostream);\n\t\tserializeString(screen.registry.getOr<Comp::Name>(part.entity, \"\").name, ostream);\n\t}\n};\n\nclass Deserializer : public DeSerializationSession<ExtendedPart> {\npublic:\n\tusing DeSerializationSession<ExtendedPart>::DeSerializationSession;\n\tvirtual ExtendedPart* deserializeExtendedPart(Part&& partPhysicalData, std::istream& istream) override {\n\t\tGraphics::Comp::Material material = deserializeMaterial(istream);\n\t\tExtendedPart* result = new ExtendedPart(std::move(partPhysicalData), deserializeString(istream));\n\n\t\tresult->setMaterial(material);\n\n\t\treturn result;\n\t}\n};\n\nstatic void openWriteFile(std::ofstream& fstream, const char* fileName) {\n\tstd::string fullPath = Util::getFullPath(fileName);\n\tLog::info(\"Writing to file %s\", fullPath.c_str());\n\tfstream.open(fullPath, std::ios::binary);\n\tif(!fstream.is_open()) {\n\t\tthrow \"File not opened!\";\n\t}\n}\n\nstatic void openReadFile(std::ifstream& fstream, const char* fileName) {\n\tstd::string fullPath = Util::getFullPath(fileName);\n\tLog::info(\"Reading file %s\", fullPath.c_str());\n\tfstream.open(fullPath, std::ios::binary);\n\tif(!fstream.is_open()) {\n\t\tthrow \"File not opened!\";\n\t}\n}\n\nvoid WorldImportExport::saveLooseParts(const char* fileName, size_t numberOfParts, const ExtendedPart* const parts[]) {\n\tstd::ofstream file;\n\topenWriteFile(file, fileName);\n\n\tSerializer serializer;\n\tserializer.serializeParts(parts, numberOfParts, file);\n\n\tfile.close();\n}\nvoid WorldImportExport::loadLoosePartsIntoWorld(const char* fileName, PlayerWorld& world) {\n\tstd::ifstream file;\n\topenReadFile(file, fileName);\n\n\tDeserializer d;\n\tstd::vector<ExtendedPart*> result = d.deserializeParts(file);\n\tfile.close();\n\n\tfor(ExtendedPart* p : result) {\n\t\tworld.addPart(p);\n\t}\n}\n\nvoid WorldImportExport::loadNativePartsIntoWorld(const char* fileName, PlayerWorld& world) {\n\tstd::ifstream file;\n\topenReadFile(file, fileName);\n\n\tDeSerializationSessionPrototype d;\n\tstd::vector<Part*> result = d.deserializeParts(file);\n\tfile.close();\n\n\tfor(Part* p : result) {\n\t\tLog::debug(\"Part cframe: %s\", str(p->getCFrame()).c_str());\n\t\tworld.addPart(new ExtendedPart(std::move(*p)));\n\t}\n}\n\nvoid WorldImportExport::saveWorld(const char* fileName, const PlayerWorld& world) {\n\tstd::ofstream file;\n\topenWriteFile(file, fileName);\n\n\tSerializer serializer;\n\tserializer.serializeWorld(world, file);\n\n\tfile.close();\n}\nvoid WorldImportExport::loadWorld(const char* fileName, PlayerWorld& world) {\n\tstd::ifstream file;\n\topenReadFile(file, fileName);\n\n\tif(!file.is_open()) {\n\t\tthrow std::runtime_error(\"Could not open file!\");\n\t}\n\n\tDeserializer deserializer;\n\tdeserializer.deserializeWorld(world, file);\n\n\tassert(world.isValid());\n\n\tfile.close();\n}\n};\n"
  },
  {
    "path": "application/io/serialization.h",
    "content": "#pragma once\n\n#include <string>\n#include \"extendedPart.h\"\n\n#include \"../worlds.h\"\n#include \"../extendedPart.h\"\n\nnamespace P3D::Application {\n\nnamespace WorldImportExport {\n\nvoid registerTexture(Graphics::Texture* texture);\n\nvoid saveWorld(const char* fileName, const PlayerWorld& world);\nvoid saveLooseParts(const char* fileName, size_t numberOfParts, const ExtendedPart* const parts[]);\n\n\nvoid loadWorld(const char* fileName, PlayerWorld& world);\nvoid loadLoosePartsIntoWorld(const char* fileName, PlayerWorld& world);\nvoid loadNativePartsIntoWorld(const char* fileName, PlayerWorld& world);\n\n};\n\n};"
  },
  {
    "path": "application/layer/cameraLayer.cpp",
    "content": "#include \"core.h\"\n\n#include \"cameraLayer.h\"\n\n#include \"../view/screen.h\"\n#include \"../application/input/standardInputHandler.h\"\n#include \"../engine/options/keyboardOptions.h\"\n\nnamespace P3D::Application {\n\nvoid CameraLayer::onInit(Engine::Registry64& registry) {\n\tScreen* screen = static_cast<Screen*>(this->ptr);\n\n\t// Camera init\n\tscreen->camera.setPosition(Position(1.0, 2.0, 3.0));\n\tscreen->camera.setRotation(Vec3(0, 3.1415, 0.0));\n\tscreen->camera.onUpdate(1.0f, screen->camera.aspect, 0.01f, 10000.0f);\n}\n\nvoid CameraLayer::onUpdate(Engine::Registry64& registry) {\n\tusing namespace Engine;\n\tScreen* screen = static_cast<Screen*>(this->ptr);\n\n\tstd::chrono::time_point<std::chrono::steady_clock> curUpdate = std::chrono::steady_clock::now();\n\tstd::chrono::nanoseconds deltaTnanos = curUpdate - this->lastUpdate;\n\tthis->lastUpdate = curUpdate;\n\n\tdouble speedAdjustment = deltaTnanos.count() * 0.000000001 * 60.0;\n\n\t// IO events\n\tif (handler->anyKey) {\n\t\tbool leftDragging = handler->leftDragging;\n\t\tif (handler->getKey(KeyboardOptions::Move::forward))\n\t\t\tscreen->camera.move(*screen, 0, 0, -1 * speedAdjustment, leftDragging);\n\t\tif (handler->getKey(KeyboardOptions::Move::backward))\n\t\t\tscreen->camera.move(*screen, 0, 0, 1 * speedAdjustment, leftDragging);\n\t\tif (handler->getKey(KeyboardOptions::Move::right))\n\t\t\tscreen->camera.move(*screen, 1 * speedAdjustment, 0, 0, leftDragging);\n\t\tif (handler->getKey(KeyboardOptions::Move::left))\n\t\t\tscreen->camera.move(*screen, -1 * speedAdjustment, 0, 0, leftDragging);\n\t\tif (handler->getKey(KeyboardOptions::Move::ascend))\n\t\t\tif (screen->camera.flying)\n\t\t\t\tscreen->camera.move(*screen, 0, 1 * speedAdjustment, 0, leftDragging);\n\t\tif (handler->getKey(KeyboardOptions::Move::descend))\n\t\t\tif (screen->camera.flying)\n\t\t\t\tscreen->camera.move(*screen, 0, -1 * speedAdjustment, 0, leftDragging);\n\t\tif (handler->getKey(KeyboardOptions::Rotate::left))\n\t\t\tscreen->camera.rotate(*screen, 0, 1 * speedAdjustment, 0, leftDragging);\n\t\tif (handler->getKey(KeyboardOptions::Rotate::right))\n\t\t\tscreen->camera.rotate(*screen, 0, -1 * speedAdjustment, 0, leftDragging);\n\t\tif (handler->getKey(KeyboardOptions::Rotate::up))\n\t\t\tscreen->camera.rotate(*screen, 1 * speedAdjustment, 0, 0, leftDragging);\n\t\tif (handler->getKey(KeyboardOptions::Rotate::down))\n\t\t\tscreen->camera.rotate(*screen, -1 * speedAdjustment, 0, 0, leftDragging);\n\t}\n\n\tscreen->camera.onUpdate();\n}\n\nvoid CameraLayer::onEvent(Engine::Registry64& registry, Engine::Event& event) {\n\tScreen* screen = static_cast<Screen*>(this->ptr);\n\tscreen->camera.onEvent(event);\n}\n\nvoid CameraLayer::onRender(Engine::Registry64& registry) {\n\tScreen* screen = static_cast<Screen*>(this->ptr);\n\n}\n\nvoid CameraLayer::onClose(Engine::Registry64& registry) {\n\n}\n};\n"
  },
  {
    "path": "application/layer/cameraLayer.h",
    "content": "#pragma once\n\n#include \"../engine/layer/layer.h\"\n#include <chrono>\n\nnamespace P3D::Application {\n\nclass Screen;\n\nclass CameraLayer : public Engine::Layer {\nprivate:\n\tstd::chrono::time_point<std::chrono::steady_clock> lastUpdate = std::chrono::steady_clock::now();\n\npublic:\n\tinline CameraLayer() : Layer() {};\n\tinline CameraLayer(Screen* screen, char flags = None) : Layer(\"CameraLayer\", screen, flags) {};\n\n\tvirtual void onInit(Engine::Registry64& registry) override;\n\tvirtual void onUpdate(Engine::Registry64& registry) override;\n\tvirtual void onEvent(Engine::Registry64& registry, Engine::Event& event) override;\n\tvirtual void onRender(Engine::Registry64& registry) override;\n\tvirtual void onClose(Engine::Registry64& registry) override;\n};\n\n};"
  },
  {
    "path": "application/layer/constraintLayer.cpp",
    "content": "#include \"core.h\"\n#include \"constraintLayer.h\"\n\n#include \"worlds.h\"\n#include \"../view/screen.h\"\n#include \"../shader/shaders.h\"\n#include \"../graphics/renderer.h\"\n#include \"../graphics/meshRegistry.h\"\n#include <Physics3D/constraints/ballConstraint.h>\n#include <Physics3D/constraints/hingeConstraint.h>\n#include <Physics3D/constraints/barConstraint.h>\n#include <Physics3D/hardconstraints/sinusoidalPistonConstraint.h>\n#include <Physics3D/hardconstraints/motorConstraint.h>\n#include <Physics3D/misc/toString.h>\n#include <Physics3D/geometry/shapeLibrary.h>\n#include <Physics3D/physical.h>\n#include <Physics3D/threading/upgradeableMutex.h>\n\n#include <typeindex>\n\nnamespace P3D::Application {\n\nvoid ConstraintLayer::onInit(Engine::Registry64& registry) {\n\n}\n\nvoid ConstraintLayer::onUpdate(Engine::Registry64& registry) {\n\n}\n\nstatic void renderObject(const Graphics::Comp::Mesh& shape, const GlobalCFrame& cframe, const DiagonalMat3f& scale, const Graphics::Comp::Material& material) {\n\tShaders::basicShader->updateMaterial(material);\n\tShaders::basicShader->updateTexture(false);\n\tShaders::basicShader->updateModel(cframe, scale);\n\tMeshRegistry::get(shape)->render();\n}\n\nstatic void renderConstraintLineBetween(Position p1, Position p2) {\n\tVec3 delta = p2 - p1;\n\n\tif (lengthSquared(delta) < 0.0001) \n\t\treturn;\n\n\tPosition center = p1 + delta/2;\n\n\tRotation rot = Rotation::faceY(delta);\n\n\trenderObject(MeshRegistry::box, GlobalCFrame(center, rot), DiagonalMat3f{0.2f, float(length(delta) / 2), 0.2f}, Graphics::Comp::Material(Color(1.0f, 0.0f, 0.0f, 1.0f)));\n\trenderObject(MeshRegistry::box, GlobalCFrame(p1, rot), DiagonalMat3f{0.25f, 0.25f, 0.25f}, Graphics::Comp::Material(Color(0.0f, 1.0f, 0.0f, 1.0f)));\n\trenderObject(MeshRegistry::box, GlobalCFrame(p2, rot), DiagonalMat3f{0.25f, 0.25f, 0.25f}, Graphics::Comp::Material(Color(0.0f, 1.0f, 0.0f, 1.0f)));\n}\n\nstatic Color constraintBarColor = Colors::RGB_R;\nconstexpr static float constraintBarThickness = 0.02f;\nconstexpr static float innerBallThickness = 0.06f;\nconstexpr static float outerBallThickness = 0.07f;\nstatic Graphics::Comp::Material innerConstraintColor = Graphics::Comp::Material(Color(0.0f, 0.0f, 1.0f, 1.0f));\nstatic Graphics::Comp::Material outerConstraintColor = Graphics::Comp::Material(Color(0.0f, 0.0f, 1.0f, 0.7f));\n\n\nstatic void renderBar(GlobalCFrame cframe, Vec3 delta, float thickness, Color color) {\n\tif (lengthSquared(delta) < 0.0001) \n\t\treturn;\n\n\tRotation rotation = Rotation::faceZ(delta);\n\n\trenderObject(MeshRegistry::box, cframe.localToGlobal(CFrame(delta/2, rotation)), DiagonalMat3f{thickness, thickness, float(length(delta) / 2)}, Graphics::Comp::Material(color));\n}\n\nstatic void renderPiston(const SinusoidalPistonConstraint* piston, const GlobalCFrame& start, const GlobalCFrame& end, int segments, float minThickness, float maxThickness) {\n\tVec3 delta = start.globalToLocal(end).getPosition();\n\tVec3 step = delta / segments;\n\n\tif (lengthSquared(delta) < 0.0001)\n\t\treturn;\n\n\tRotation rot = Rotation::faceZ(delta);\n\n\tfor (int i = 0; i < segments; i++) {\n\t\tVec3 center = step * (i + 0.5);\n\n\t\tfloat thickness = i / (segments - 1.0f) * (maxThickness - minThickness) + minThickness;\n\n\t\tGraphics::Comp::Material mat = (i%2 == 0) ? Graphics::Comp::Material(Color(1.0f, 0.8f, 0.1f, 1.0f)) : Graphics::Comp::Material(Color(0.9f, 0.9f, 0.9f, 1.0f));\n\n\t\trenderObject(MeshRegistry::cylinder, start.localToGlobal(CFrame(center, rot)), DiagonalMat3f{thickness, thickness, float(length(step) / 2)}, mat);\n\t}\n\n\trenderObject(MeshRegistry::sphere, start, DiagonalMat3f::IDENTITY() * minThickness * 1.2f, Graphics::Comp::Material(Color(0.0f, 1.0f, 0.0f, 1.0f)));\n\trenderObject(MeshRegistry::sphere, end, DiagonalMat3f::IDENTITY() * maxThickness * 1.2f, Graphics::Comp::Material(Color(0.0f, 1.0f, 0.0f, 1.0f)));\n}\n\nstatic void renderMotor(const ConstantSpeedMotorConstraint* motor, const GlobalCFrame& start, const GlobalCFrame& end) {\n\trenderObject(MeshRegistry::hexagon, start.localToGlobal(CFrame(Vec3(0, 0, 0.05))), DiagonalMat3f{0.2f, 0.2f, 0.1f}, Graphics::Comp::Material(Color(1.0f, 1.0f, 0.0f, 1.0f)));\n\trenderObject(MeshRegistry::hexagon, end.localToGlobal(CFrame(Vec3(0, 0, -0.05))), DiagonalMat3f{0.2f, 0.2f, 0.1f}, Graphics::Comp::Material(Color(0.7f, 0.7f, 0.0f, 1.0f)));\n}\n\nstatic void renderBallConstraint(const GlobalCFrame& cframeA, const GlobalCFrame& cframeB, const BallConstraint* bc) {\n\trenderBar(cframeA, bc->attachA, constraintBarThickness, constraintBarColor);\n\trenderBar(cframeB, bc->attachB, constraintBarThickness, constraintBarColor);\n\n\trenderObject(MeshRegistry::sphere, cframeA.localToGlobal(CFrame(bc->attachA)), DiagonalMat3f::IDENTITY() * innerBallThickness, innerConstraintColor);\n\trenderObject(MeshRegistry::sphere, cframeB.localToGlobal(CFrame(bc->attachB)), DiagonalMat3f::IDENTITY() * outerBallThickness, outerConstraintColor);\n}\n\nstatic void renderHingeConstraint(const GlobalCFrame& cframeA, const GlobalCFrame& cframeB, const HingeConstraint* hc) {\n\trenderBar(cframeA, hc->attachA, constraintBarThickness, constraintBarColor);\n\trenderBar(cframeB, hc->attachB, constraintBarThickness, constraintBarColor);\n\n\tCFrame atA(hc->attachA, Rotation::faceZ(hc->axisA));\n\tCFrame atB(hc->attachB, Rotation::faceZ(hc->axisB));\n\trenderObject(MeshRegistry::cylinder, cframeA.localToGlobal(atA), DiagonalMat3f::IDENTITY() * innerBallThickness, innerConstraintColor);\n\trenderObject(MeshRegistry::cylinder, cframeB.localToGlobal(atB), DiagonalMat3f::IDENTITY() * outerBallThickness, outerConstraintColor);\n}\n\nstatic void renderBarConstraint(const GlobalCFrame& cframeA, const GlobalCFrame& cframeB, const BarConstraint* bc) {\n\trenderBar(cframeA, bc->attachA, constraintBarThickness, constraintBarColor);\n\trenderBar(cframeB, bc->attachB, constraintBarThickness, constraintBarColor);\n\tPosition globalA = cframeA.localToGlobal(bc->attachA);\n\tPosition globalB = cframeB.localToGlobal(bc->attachB);\n\n\tPosition barCenter = avg(globalA, globalB);\n\tVec3 bar;\n\tif(globalA != globalB) {\n\t\tbar = withLength(Vec3(globalB - globalA), bc->barLength);\n\t} else {\n\t\tbar = Vec3(bc->barLength, 0, 0);\n\t}\n\n\trenderBar(barCenter - bar/2, bar, constraintBarThickness, constraintBarColor);\n\n\trenderObject(MeshRegistry::sphere, cframeA.localToGlobal(CFrame(bc->attachA)), DiagonalMat3f::IDENTITY() * innerBallThickness, innerConstraintColor);\n\trenderObject(MeshRegistry::sphere, cframeB.localToGlobal(CFrame(bc->attachB)), DiagonalMat3f::IDENTITY() * outerBallThickness, outerConstraintColor);\n\n\trenderObject(MeshRegistry::sphere, barCenter - bar / 2, DiagonalMat3f::IDENTITY() * innerBallThickness, innerConstraintColor);\n\trenderObject(MeshRegistry::sphere, barCenter + bar / 2, DiagonalMat3f::IDENTITY() * outerBallThickness, outerConstraintColor);\n}\n\nstatic void renderHardConstraint( const ConnectedPhysical& conPhys) {\n\tGlobalCFrame cframeOfConPhys = conPhys.getCFrame();\n\tGlobalCFrame cframeOfParent = conPhys.parent->getCFrame();\n\n\n\trenderBar(cframeOfConPhys, conPhys.connectionToParent.attachOnChild.position, constraintBarThickness, constraintBarColor);\n\trenderBar(cframeOfParent, conPhys.connectionToParent.attachOnParent.position, constraintBarThickness, constraintBarColor);\n\n\tconst HardConstraint* constraint = conPhys.connectionToParent.constraintWithParent.get();\n\n\tGlobalCFrame startOfConstraint = cframeOfConPhys.localToGlobal(conPhys.connectionToParent.attachOnChild);\n\tGlobalCFrame endOfConstraint = cframeOfParent.localToGlobal(conPhys.connectionToParent.attachOnParent);\n\tconst auto& info(typeid(*constraint));\n\tif (info == typeid(SinusoidalPistonConstraint)) {\n\t\trenderPiston(dynamic_cast<const SinusoidalPistonConstraint*>(constraint), startOfConstraint, endOfConstraint, 3, 0.1f, 0.12f);\n\t} else if (info == typeid(ConstantSpeedMotorConstraint)) {\n\t\trenderMotor(dynamic_cast<const ConstantSpeedMotorConstraint*>(constraint), startOfConstraint, endOfConstraint);\n\t}\n}\n\nstatic void recurseRenderHardConstraints(const Physical& physical) {\n\tfor(const ConnectedPhysical& conPhys : physical.childPhysicals) {\n\t\trenderHardConstraint(conPhys);\n\t\trecurseRenderHardConstraints(conPhys);\n\t}\n}\n\nstatic void renderConstraint(const PhysicalConstraint& constraint) {\n\tconst auto& info(typeid(*constraint.constraint));\n\tGlobalCFrame cfA = constraint.physA->getCFrame();\n\tGlobalCFrame cfB = constraint.physB->getCFrame();\n\tif(info == typeid(BallConstraint)) {\n\t\trenderBallConstraint(cfA, cfB, dynamic_cast<const BallConstraint*>(constraint.constraint));\n\t} else if(info == typeid(HingeConstraint)) {\n\t\trenderHingeConstraint(cfA, cfB, dynamic_cast<const HingeConstraint*>(constraint.constraint));\n\t} else if(info == typeid(BarConstraint)) {\n\t\trenderBarConstraint(cfA, cfB, dynamic_cast<const BarConstraint*>(constraint.constraint));\n\t}\n}\n\nstatic void renderSpringLink(const GlobalCFrame& start) {\n\trenderObject(MeshRegistry::sphere, start.localToGlobal(CFrame(Vec3(0, 0, 0.05))), DiagonalMat3f{ 0.2f, 0.2f, 0.1f }, Graphics::Comp::Material(Color(1.0f, 1.0f, 0.0f, 1.0f)));\n\t\n}\n\n/*static void renderSoftLinkConstraint(const ConstraintLayer* cl, const SoftLink* link) {\n\trenderConstraintLineBetween(link->getGlobalPositionOfAttach2(), link->getGlobalPositionOfAttach1());\n}*/\n\nvoid ConstraintLayer::onRender(Engine::Registry64& registry) {\n\tusing namespace Graphics;\n\tusing namespace Renderer;\n\n\tScreen* screen = static_cast<Screen*>(this->ptr);\n\t\n\tbeginScene();\n\tenableBlending();\n\n\tShaders::basicShader->updateProjection(screen->camera.viewMatrix, screen->camera.projectionMatrix, screen->camera.cframe.position);\n\tShaders::maskShader->updateProjection(screen->camera.viewMatrix, screen->camera.projectionMatrix, screen->camera.cframe.position);\n\n\t{\n\t\tstd::shared_lock<UpgradeableMutex> worldReadLock(*screen->worldMutex);\n\t\tfor(MotorizedPhysical* phys : screen->world->physicals) {\n\t\t\trecurseRenderHardConstraints(*phys);\n\t\t}\n\n\t\tfor(const ConstraintGroup& g : screen->world->constraints) {\n\t\t\tfor(const PhysicalConstraint& constraint : g.constraints) {\n\t\t\t\trenderConstraint(constraint);\n\t\t\t}\n\t\t}\n\n\t\t/*for (const SoftLink* springLink : screen->world->springLinks) {\n\t\t\trenderSoftLinkConstraint(this, springLink);\n\t\t}*/\n\t}\n\n\tendScene();\n}\n\nvoid ConstraintLayer::onEvent(Engine::Registry64& registry, Engine::Event& event) {\n\n}\n\nvoid ConstraintLayer::onClose(Engine::Registry64& registry) {\n\n}\n\n};"
  },
  {
    "path": "application/layer/constraintLayer.h",
    "content": "#pragma once\n\n#include \"../engine/layer/layer.h\"\n\nnamespace P3D::Application {\n\nclass Screen;\n\nclass ConstraintLayer : public Engine::Layer {\npublic:\n\tConstraintLayer() = default;\n\tConstraintLayer(Screen* screen, char flags = None) : Layer(\"Constraint layer\", screen, flags) {}\n\n\tvirtual ~ConstraintLayer() = default;\n\n\tvoid onInit(Engine::Registry64& registry) override;\n\tvoid onUpdate(Engine::Registry64& registry) override;\n\tvoid onRender(Engine::Registry64& registry) override;\n\tvoid onEvent(Engine::Registry64& registry, Engine::Event& event) override;\n\tvoid onClose(Engine::Registry64& registry) override;\n};\n};\n"
  },
  {
    "path": "application/layer/debugLayer.cpp",
    "content": "#include \"core.h\"\n\n#include \"debugLayer.h\"\n\n#include \"../graphics/renderer.h\"\n#include \"../graphics/ecs/components.h\"\n#include \"../graphics/mesh/arrayMesh.h\"\n#include \"../graphics/mesh/pointMesh.h\"\n#include \"../graphics/mesh/vectorMesh.h\"\n#include \"../graphics/mesh/indexedMesh.h\"\n#include \"../graphics/debug/visualDebug.h\"\n\n#include <Physics3D/threading/upgradeableMutex.h>\n#include <Physics3D/boundstree/boundsTree.h>\n#include <Physics3D/geometry/polyhedron.h>\n#include <Physics3D/math/bounds.h>\n#include <Physics3D/physical.h>\n#include <Physics3D/layer.h>\n\n#include \"worlds.h\"\n#include \"view/screen.h\"\n#include \"graphics/meshRegistry.h\"\n#include \"shader/shaders.h\"\n\nnamespace P3D::Application {\n\nVec4f colors[] {\n\tColors::BLUE,\n\tColors::GREEN,\n\tColors::YELLOW,\n\tColors::ORANGE,\n\tColors::RED,\n\tColors::PURPLE\n};\n\nvoid renderSphere(double radius, const Position& position, const Color& color) {\n\tShaders::basicShader->updateMaterial(Graphics::Comp::Material(color));\n\tShaders::basicShader->updateModel(join(Mat3f::IDENTITY() * static_cast<float>(radius), castPositionToVec3f(position), Vec3f(0.0f,0.0f,0.0f),1.0f));\n\n\tGraphics::MeshRegistry::get(Graphics::MeshRegistry::sphere)->render();\n}\n\nvoid renderBox(const GlobalCFrame& cframe, double width, double height, double depth, const Color& color) {\n\tShaders::basicShader->updateMaterial(Graphics::Comp::Material(color));\n\tShaders::basicShader->updateModel(Mat4f(cframe.asMat4WithPreScale(DiagonalMat3{width, height, depth})));\n\n\tGraphics::MeshRegistry::get(Graphics::MeshRegistry::box)->render();\n}\n\nvoid renderBounds(const Bounds& bounds, const Color& color) {\n\tVec3Fix diagonal = bounds.getDiagonal();\n\tPosition position = bounds.getCenter();\n\trenderBox(GlobalCFrame(position), static_cast<double>(diagonal.x), static_cast<double>(diagonal.y), static_cast<double>(diagonal.z), color);\n}\n\nstatic Color getCyclingColor(int depth) {\n\tColor color = colors[depth % 6];\n\tcolor.a = 0.3f;\n\treturn color;\n}\n\nstatic void renderBoundsForDepth(const Bounds& bounds, int depth) {\n\trenderBounds(bounds.expanded((10 - depth) * 0.002), getCyclingColor(depth));\n}\n\nstatic void recursiveRenderColTree(const P3D::TreeTrunk& curTrunk, int curTrunkSize, int depth) {\n\tfor(int i = 0; i < curTrunkSize; i++) {\n\t\tconst TreeNodeRef& subNode = curTrunk.subNodes[i];\n\n\t\tif(subNode.isTrunkNode()) {\n\t\t\trecursiveRenderColTree(subNode.asTrunk(), subNode.getTrunkSize(), depth + 1);\n\t\t}\n\n\t\trenderBoundsForDepth(curTrunk.getBoundsOfSubNode(i), depth);\n\t}\n}\n\nstatic bool recursiveColTreeForOneObject(const TreeTrunk& curTrunk, int curTrunkSize, const Part* part, const Bounds& bounds, int depth) {\n\tfor(int i = 0; i < curTrunkSize; i++) {\n\t\tconst TreeNodeRef& subNode = curTrunk.subNodes[i];\n\n\t\tif(subNode.isTrunkNode()) {\n\t\t\tif(recursiveColTreeForOneObject(subNode.asTrunk(), subNode.getTrunkSize(), part, bounds, depth + 1)) {\n\t\t\t\trenderBoundsForDepth(curTrunk.getBoundsOfSubNode(i), depth);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} else {\n\t\t\tif(subNode.asObject() == part) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n}\n\nstatic void renderTree(const BoundsTree<Part>& tree) {\n\tauto baseTrunk = tree.getPrototype().getBaseTrunk();\n\trecursiveRenderColTree(baseTrunk.first, baseTrunk.second, 0);\n}\nstatic void renderTreeForOneObject(const BoundsTree<Part>& tree, const Part& part) {\n\tauto baseTrunk = tree.getPrototype().getBaseTrunk();\n\trecursiveColTreeForOneObject(baseTrunk.first, baseTrunk.second, &part, part.getBounds(), 0);\n}\n\n\n\nvoid DebugLayer::onInit(Engine::Registry64& registry) {\n\n\t// Origin init\n\toriginMesh = new ArrayMesh(nullptr, 1, 3, Renderer::POINT);\n\n\t// Vector init\n\tvectorMesh = new VectorMesh(nullptr, 0);\n\n\t// Point init\n\tpointMesh = new PointMesh(nullptr, 0);\n\n}\n\nvoid DebugLayer::onUpdate(Engine::Registry64& registry) {\n\n}\n\nvoid DebugLayer::onEvent(Engine::Registry64& registry, Engine::Event& event) {\n\n}\n\nvoid DebugLayer::onRender(Engine::Registry64& registry) {\n\tusing namespace Graphics;\n\tusing namespace Renderer;\n\tusing namespace VisualDebug;\n\tusing namespace AppDebug;\n\tScreen* screen = static_cast<Screen*>(this->ptr);\n\n\tbeginScene();\n\tenableBlending();\n\n\tgraphicsMeasure.mark(GraphicsProcess::VECTORS);\n\n\n\t// Initialize vector log buffer\n\tAddableBuffer<ColoredVector>& vecLog = getVectorBuffer();\n\tAddableBuffer<ColoredPoint>& pointLog = getPointBuffer();\n\n\t{\n\t\tstd::shared_lock<UpgradeableMutex> worldReadLock(*screen->worldMutex);\n\t\tfor(const MotorizedPhysical* physical : screen->world->physicals) {\n\t\t\tPosition com = physical->getCenterOfMass();\n\t\t\tpointLog.add(ColoredPoint(com, Debug::CENTER_OF_MASS));\n\t\t}\n\n\t\tScreen* screen = static_cast<Screen*>(this->ptr);\n\t\tif(screen->selectedPart != nullptr) {\n\t\t\tconst GlobalCFrame& selectedCFrame = screen->selectedPart->getCFrame();\n\t\t\tMotion partMotion = screen->selectedPart->getMotion();\n\t\t\tPolyhedron asPoly = screen->selectedPart->hitbox.asPolyhedron();\n\t\t\tfor(const Vec3f& corner : asPoly.iterVertices()) {\n\t\t\t\tvecLog.add(ColoredVector(selectedCFrame.localToGlobal(corner), partMotion.getVelocityOfPoint(selectedCFrame.localToRelative(corner)), Debug::VELOCITY));\n\t\t\t}\n\n\t\t\tif(colissionSpheresMode == SphereColissionRenderMode::SELECTED) {\n\t\t\t\tPhysical& selectedPhys = *screen->selectedPart->getPhysical();\n\n\t\t\t\tfor(Part& part : selectedPhys.rigidBody) {\n\t\t\t\t\tColor yellow = Colors::YELLOW;\n\t\t\t\t\tyellow.a = 0.5;\n\t\t\t\t\tBoundingBox localBounds = screen->selectedPart->getLocalBounds();\n\t\t\t\t\trenderBox(screen->selectedPart->getCFrame().localToGlobal(CFrame(localBounds.getCenter())), localBounds.getWidth(), localBounds.getHeight(), localBounds.getDepth(), yellow);\n\n\t\t\t\t\tColor green = Colors::GREEN;\n\t\t\t\t\tgreen.a = 0.5;\n\t\t\t\t\trenderSphere(part.maxRadius, part.getPosition(), green);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif(colissionSpheresMode == SphereColissionRenderMode::ALL) {\n\t\t\tfor(MotorizedPhysical* phys : screen->world->physicals) {\n\t\t\t\tfor(Part& part : phys->rigidBody) {\n\t\t\t\t\tColor yellow = Colors::YELLOW;\n\t\t\t\t\tyellow.a = 0.5;\n\t\t\t\t\tBoundingBox localBounds = part.getLocalBounds();\n\t\t\t\t\trenderBox(part.getCFrame().localToGlobal(CFrame(localBounds.getCenter())), localBounds.getWidth(), localBounds.getHeight(), localBounds.getDepth(), yellow);\n\n\t\t\t\t\tColor green = Colors::GREEN;\n\t\t\t\t\tgreen.a = 0.5;\n\t\t\t\t\trenderSphere(part.maxRadius, part.getPosition(), green);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif(colTreeRenderMode == -2) {\n\t\t\tif(screen->selectedPart != nullptr) {\n\t\t\t\trenderTreeForOneObject(screen->selectedPart->layer->tree, *screen->selectedPart);\n\t\t\t}\n\t\t} else if(colTreeRenderMode >= 0) {\n\t\t\trenderTree(getLayerByID(screen->world->layers, colTreeRenderMode)->tree);\n\t\t}\n\t\tworldReadLock.unlock(); // unlock_shared\n\t}\n\n\tdisableDepthTest();\n\n\t// Update debug meshes\n\tgraphicsMeasure.mark(GraphicsProcess::VECTORS);\n\tupdateVectorMesh(vectorMesh, vecLog.data, vecLog.size);\n\tupdatePointMesh(pointMesh, pointLog.data, pointLog.size);\n\n\t// Render vector mesh\n\tgraphicsMeasure.mark(GraphicsProcess::VECTORS);\n\tShaders::vectorShader->updateProjection(screen->camera.viewMatrix, screen->camera.projectionMatrix, screen->camera.cframe.position);\n\tvectorMesh->render();\n\n\t// Render point mesh\n\tgraphicsMeasure.mark(GraphicsProcess::VECTORS);\n\tShaders::pointShader->updateProjection(screen->camera.viewMatrix, screen->camera.projectionMatrix, screen->camera.cframe.position);\n\tpointMesh->render();\n\n\t// Render origin mesh\n\tgraphicsMeasure.mark(GraphicsProcess::ORIGIN);\n\tShaders::originShader->updateProjection(screen->camera.viewMatrix, screen->camera.getViewRotation(), screen->camera.projectionMatrix, screen->camera.orthoMatrix, screen->camera.cframe.position);\n\toriginMesh->render();\n\n\tendScene();\n}\n\nvoid DebugLayer::onClose(Engine::Registry64& registry) {\n\n}\n\n};"
  },
  {
    "path": "application/layer/debugLayer.h",
    "content": "#pragma once\n\n#include \"../engine/layer/layer.h\"\n\nnamespace P3D::Graphics {\nclass ArrayMesh;\nclass PointMesh;\nclass VectorMesh;\n};\n\nclass Screen;\n\nnamespace P3D::Application {\n\nclass DebugLayer : public Engine::Layer {\nprivate:\n\tGraphics::VectorMesh* vectorMesh = nullptr;\n\tGraphics::PointMesh* pointMesh = nullptr;\n\tGraphics::ArrayMesh* originMesh = nullptr;\n\npublic:\n\tinline DebugLayer() : Layer() {};\n\tinline DebugLayer(Screen* screen, char flags = NoUpdate | NoEvents) : Layer(\"Debug layer\", screen, flags) {};\n\n\tvirtual void onInit(Engine::Registry64& registry) override;\n\tvirtual void onUpdate(Engine::Registry64& registry) override;\n\tvirtual void onEvent(Engine::Registry64& registry, Engine::Event& event) override;\n\tvirtual void onRender(Engine::Registry64& registry) override;\n\tvirtual void onClose(Engine::Registry64& registry) override;\n};\n\n};"
  },
  {
    "path": "application/layer/debugOverlay.cpp",
    "content": "#include \"core.h\"\n#include \"debugOverlay.h\"\n\n#include \"view/screen.h\"\n#include \"shader/shaders.h\"\n\n#include \"../util/resource/resourceManager.h\"\n\n#include \"../graphics/renderer.h\"\n#include \"../graphics/debug/profilerUI.h\"\n#include \"../graphics/debug/visualDebug.h\"\n#include \"../graphics/resource/fontResource.h\"\n#include \"../graphics/path/path.h\"\n#include \"../graphics/gui/gui.h\"\n\n#include <Physics3D/misc/physicsProfiler.h>\n#include <Physics3D/misc/toString.h>\n#include <Physics3D/world.h>\n#include <Physics3D/layer.h>\n#include <Physics3D/threading/upgradeableMutex.h>\n\n#include \"worlds.h\"\n\nnamespace P3D::Application {\n\nGraphics::BarChartClassInfo iterChartClasses[] {\n\t{ \"GJK Collide\"   , Vec3f(0.2f, 0.2f, 1.0f) },\n\t{ \"GJK No Collide\", Vec3f(1.0f, 0.5f, 0.0f) },\n\t{ \"EPA\"           , Vec3f(1.0f, 1.0f, 0.0f) }\n};\n\nGraphics::BarChart iterationChart(\"Iteration Statistics\", \"\", GJKCollidesIterationStatistics.labels, iterChartClasses, Vec2f(-1.0f + 0.1f, -0.3f), Vec2f(0.8f, 0.6f), 3, 17);\nGraphics::SlidingChart fpsSlidingChart(\"Fps Fps\", Vec2f(-0.3f, 0.2f), Vec2f(0.7f, 0.4f));\n\nvoid DebugOverlay::onInit(Engine::Registry64& registry) {\n\tusing namespace Graphics;\n\tfpsSlidingChart.add(SlidingChartDataSetInfo(\"Fps 1\", 100, Colors::ORANGE, 2.0));\n\tfpsSlidingChart.add(SlidingChartDataSetInfo(\"Fps 2\", 50, Colors::BLUE, 1.0));\n}\n\nvoid DebugOverlay::onUpdate(Engine::Registry64& registry) {\n\tusing namespace Graphics::VisualDebug;\n\tfieldIndex = 0;\n}\n\nvoid DebugOverlay::onEvent(Engine::Registry64& registry, Engine::Event& event) {\n\n}\n\nvoid DebugOverlay::onRender(Engine::Registry64& registry) {\n\tusing namespace Graphics;\n\tusing namespace VisualDebug;\n\tusing namespace Renderer;\n\n\tScreen* screen = static_cast<Screen*>(this->ptr);\n\n\tGraphics::Shaders::guiShader->bind();\n\tGraphics::Shaders::guiShader->setUniform(\"projectionMatrix\", screen->camera.orthoMatrix);\n\n\tbeginScene();\n\n\tenableBlending();\n\tdisableDepthTest();\n\tdisableCulling();\n\n\tPath::bind(GUI::batch);\n\tResourceManager::get<FontResource>(\"font\")->getAtlas()->bind();\n\tShaders::fontShader->updateProjection(screen->camera.orthoMatrix);\n\tGraphics::Shaders::guiShader->setUniform(\"projectionMatrix\", screen->camera.orthoMatrix);\n\tgraphicsMeasure.mark(GraphicsProcess::PROFILER);\n\n\tsize_t objectCount = screen->world->getPartCount();\n\taddDebugField(screen->dimension, GUI::font, \"Screen\", str(screen->dimension) + \", [\" + std::to_string(screen->camera.aspect) + \":1]\", \"\");\n\taddDebugField(screen->dimension, GUI::font, \"Position\", str(screen->camera.cframe.position), \"\");\n\taddDebugField(screen->dimension, GUI::font, \"Objects\", objectCount, \"\");\n\t//addDebugField(screen->dimension, GUI::font, \"Intersections\", getTheoreticalNumberOfIntersections(objectCount), \"\");\n\taddDebugField(screen->dimension, GUI::font, \"AVG Collide GJK Iterations\", gjkCollideIterStats.avg(), \"\");\n\taddDebugField(screen->dimension, GUI::font, \"AVG No Collide GJK Iterations\", gjkNoCollideIterStats.avg(), \"\");\n\taddDebugField(screen->dimension, GUI::font, \"TPS\", physicsMeasure.getAvgTPS(), \"\");\n\taddDebugField(screen->dimension, GUI::font, \"FPS\", Graphics::graphicsMeasure.getAvgTPS(), \"\");\n\t/*addDebugField(screen->dimension, GUI::font, \"World Kinetic Energy\", screen->world->getTotalKineticEnergy(), \"\");\n\taddDebugField(screen->dimension, GUI::font, \"World Potential Energy\", screen->world->getTotalPotentialEnergy(), \"\");\n\taddDebugField(screen->dimension, GUI::font, \"World Energy\", screen->world->getTotalEnergy(), \"\");*/\n\taddDebugField(screen->dimension, GUI::font, \"World Age\", screen->world->age, \" ticks\");\n\n\tif (renderPiesEnabled) {\n\t\tfloat leftSide = float(screen->dimension.x) / float(screen->dimension.y);\n\t\tPieChart graphicsPie = toPieChart(Graphics::graphicsMeasure, \"Graphics\", Vec2f(-leftSide + 1.5f, -0.7f), 0.2f);\n\t\tPieChart physicsPie = toPieChart(physicsMeasure, \"Physics\", Vec2f(-leftSide + 0.3f, -0.7f), 0.2f);\n\t\tPieChart intersectionPie = toPieChart(intersectionStatistics, \"Intersections\", Vec2f(-leftSide + 2.7f, -0.7f), 0.2f);\n\n\t\tphysicsPie.renderText(GUI::font);\n\t\tgraphicsPie.renderText(GUI::font);\n\t\tintersectionPie.renderText(GUI::font);\n\n\t\tphysicsPie.renderPie();\n\t\tgraphicsPie.renderPie();\n\t\tintersectionPie.renderPie();\n\n\t\tParallelArray<long long, 17> gjkColIter = GJKCollidesIterationStatistics.history.avg();\n\t\tParallelArray<long long, 17> gjkNoColIter = GJKNoCollidesIterationStatistics.history.avg();\n\t\tParallelArray<long long, 17> epaIter = EPAIterationStatistics.history.avg();\n\n\t\tfor (size_t i = 0; i < GJKCollidesIterationStatistics.size(); i++) {\n\t\t\titerationChart.data(0, i) = WeightValue { (float) gjkColIter[i], std::to_string(gjkColIter[i]) };\n\t\t\titerationChart.data(1, i) = WeightValue { (float) gjkNoColIter[i], std::to_string(gjkNoColIter[i]) };\n\t\t\titerationChart.data(2, i) = WeightValue { (float) epaIter[i], std::to_string(epaIter[i]) };\n\t\t}\n\n\t\titerationChart.position = Vec2f(-leftSide + 0.1f, -0.3f);\n\t\titerationChart.render();\n\n\t\t{\n\t\t\tgraphicsMeasure.mark(GraphicsProcess::WAIT_FOR_LOCK);\n\t\t\tstd::shared_lock<UpgradeableMutex> worldReadLock(*screen->worldMutex);\n\n\t\t\tScreen* screen = static_cast<Screen*>(this->ptr);\n\n\t\t\tgraphicsMeasure.mark(GraphicsProcess::PROFILER);\n\t\t\t\n\t\t\tsize_t layerCount = getMaxLayerID(screen->world->layers);\n\t\t\tVec2i d = screen->dimension;\n\t\t\tfloat availableSpace = float(d.x) / float(d.y);\n\t\t\tfloat widthPerTree = availableSpace / layerCount;\n\t\t\tint i = 0;\n\t\t\tfor(const ColissionLayer& clayer : screen->world->layers) {\n\t\t\t\tfor(const WorldLayer& layer : clayer.subLayers) {\n\t\t\t\t\tfloat xPos = widthPerTree / 2 + widthPerTree * i;\n\n\t\t\t\t\trenderTreeStructure(layer.tree, pieColors[i], Vec2f(xPos, 0.95f), widthPerTree * 0.7f);\n\t\t\t\t\ti++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/*fpsSlidingChart.add(\"Fps 1\", Graphics::graphicsMeasure.getAvgTPS());\n\t\tfpsSlidingChart.add(\"Fps 2\", physicsMeasure.getAvgTPS());\n\t\tfpsSlidingChart.render();*/\n\n\t\tPath::batch->pushCommand(0); // if this is not here then the trees won't render properly if fpsSlidingChart.render is commented for some reason\n\t}\n\t\n\tGUI::batch->submit();\n\n\tendScene();\n}\n\nvoid DebugOverlay::onClose(Engine::Registry64& registry) {\n\n}\n\n};"
  },
  {
    "path": "application/layer/debugOverlay.h",
    "content": "#pragma once\n\n#include \"../engine/layer/layer.h\"\n\nnamespace P3D::Application {\n\nclass Screen;\n\nclass DebugOverlay : public Engine::Layer {\npublic:\n\tinline DebugOverlay() : Layer() {};\n\tinline DebugOverlay(Screen* screen, char flags = NoEvents) : Layer(\"Debug overlay\", screen, flags) {};\n\n\tvirtual void onInit(Engine::Registry64& registry) override;\n\tvirtual void onUpdate(Engine::Registry64& registry) override;\n\tvirtual void onEvent(Engine::Registry64& registry, Engine::Event& event) override;\n\tvirtual void onRender(Engine::Registry64& registry) override;\n\tvirtual void onClose(Engine::Registry64& registry) override;\n};\n\n};"
  },
  {
    "path": "application/layer/guiLayer.cpp",
    "content": "#include \"core.h\"\n\n#include \"guiLayer.h\"\n\n#include \"view/screen.h\"\n#include \"view/frames.h\"\n#include \"input/standardInputHandler.h\"\n#include \"../engine/event/mouseEvent.h\"\n#include \"../graphics/renderer.h\"\n#include \"../graphics/shader/shaders.h\"\n#include \"../graphics/gui/gui.h\"\n#include \"../graphics/buffers/frameBuffer.h\"\n\nnamespace P3D::Application {\n\nbool onMouseMove(const Engine::MouseMoveEvent& event) {\n\tusing namespace Graphics;\n\n\treturn false;\n}\n\nbool onMousePress(const Engine::MousePressEvent& event) {\n\tusing namespace Graphics;\n\n\treturn false;\n}\n\nbool onMouseRelease(const Engine::MouseReleaseEvent& event) {\n\tusing namespace Graphics;\n\n\treturn false;\n}\n\nbool onMouseDrag(const Engine::MouseDragEvent& event) {\n\tusing namespace Graphics;\n\t\n\treturn false;\n}\n\nbool onWindowResize(const Engine::WindowResizeEvent& event) {\n\tusing namespace Graphics;\n\tfloat aspect = ((float) event.getWidth()) / ((float) event.getHeight());\n\tVec2i dimension = Vec2i(event.getWidth(), event.getHeight());\n\treturn GUI::onWindowResize({ dimension, aspect });\n}\n\nvoid GuiLayer::onInit(Engine::Registry64& registry) {\n\tusing namespace Graphics;\n\n\tScreen* screen = static_cast<Screen*>(this->ptr);\n\n\t// GUI init\n\tGUI::onInit({ screen->dimension, screen->camera.aspect });\n\tShaders::guiShader->init(screen->camera.orthoMatrix);\n}\n\nvoid GuiLayer::onUpdate(Engine::Registry64& registry) {\n\tusing namespace Graphics;\n\n\tScreen* screen = static_cast<Screen*>(this->ptr);\n\n\t// Update GUI\n\tGUI::onUpdate(screen->camera.orthoMatrix);\n}\n\nvoid GuiLayer::onEvent(Engine::Registry64& registry, Engine::Event& event) {\n\tusing namespace Engine;\n\n\tEventDispatcher dispatcher(event);\n\tdispatcher.dispatch<MouseMoveEvent>(onMouseMove);\n\tdispatcher.dispatch<MousePressEvent>(onMousePress);\n\tdispatcher.dispatch<MouseReleaseEvent>(onMouseRelease);\n\tdispatcher.dispatch<MouseDragEvent>(onMouseDrag);\n\tdispatcher.dispatch<WindowResizeEvent>(onWindowResize);\n}\n\nvoid GuiLayer::onRender(Engine::Registry64& registry) {\n\tusing namespace Graphics;\n\tusing namespace Renderer;\n\tScreen* screen = static_cast<Screen*>(this->ptr);\n\t\n\tbindFramebuffer(screen->screenFrameBuffer->getID());\n\tbeginScene();\n\n\tFrames::onRender(registry);\n\n\tendScene();\n}\n\nvoid GuiLayer::onClose(Engine::Registry64& registry) {\n\tusing namespace Graphics;\n\tGUI::onClose();\n}\n\n};"
  },
  {
    "path": "application/layer/guiLayer.h",
    "content": "#pragma once\n\n#include \"../engine/layer/layer.h\"\n\nnamespace P3D::Application {\n\t\nclass Screen;\n\nclass GuiLayer : public Engine::Layer {\npublic:\n\tGuiLayer() : Layer() {}\n\tGuiLayer(Screen* screen, char flags = None) : Layer(\"Gui\", screen, flags) {}\n\n\tvoid onInit(Engine::Registry64& registry) override;\n\tvoid onUpdate(Engine::Registry64& registry) override;\n\tvoid onEvent(Engine::Registry64& registry, Engine::Event& event) override;\n\tvoid onRender(Engine::Registry64& registry) override;\n\tvoid onClose(Engine::Registry64& registry) override;\n};\n\n};"
  },
  {
    "path": "application/layer/imguiLayer.cpp",
    "content": "#include \"core.h\"\n\n#include \"imguiLayer.h\"\n\n#include <imgui/imgui.h>\n#include <imgui/imgui_impl_opengl3.h>\n#include <imgui/imgui_impl_glfw.h>\n\n#include \"../view/screen.h\"\n#include \"../graphics/glfwUtils.h\"\n#include \"../graphics/texture.h\"\n#include \"../graphics/buffers/frameBuffer.h\"\n#include \"../graphics/renderer.h\"\n#include \"../util/resource/resourceManager.h\"\n#include \"../engine/event/windowEvent.h\"\n#include \"../application/input/standardInputHandler.h\"\n#include \"../graphics/gui/gui.h\"\n#include <Physics3D/misc/toString.h>\n#include \"../graphics/gui/imgui/imguiStyle.h\"\n\nnamespace P3D::Application {\n\nvoid ImGuiLayer::onInit(Engine::Registry64& registry) {\n\tIMGUI_CHECKVERSION();\n\t\n\tImGui::CreateContext();\n\tImGuiIO& io = ImGui::GetIO(); (void) io;\n\tio.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;       // Enable Keyboard Controls\n\tio.ConfigFlags |= ImGuiConfigFlags_DockingEnable;           // Enable Docking\n\n\tGraphics::setupImGuiStyle();\n\tGLFWwindow* window = Graphics::GLFW::getCurrentContext();\n\n\tImGui_ImplGlfw_InitForOpenGL(window, true);\n\tImGui_ImplOpenGL3_Init(\"#version 330\");\n\tio.IniFilename = \"../res/imgui.ini\";\n}\n\nvoid ImGuiLayer::onUpdate(Engine::Registry64& registry) {\n\n}\n\nvoid ImGuiLayer::onEvent(Engine::Registry64& registry, Engine::Event& event) {\n\tif (!sceneHovered) {\n\t\tevent.handled = event.inCategory(Engine::EventCategoryMouse) && ImGui::GetIO().WantCaptureMouse;\n\t}\n}\n\nvoid ImGuiLayer::onRender(Engine::Registry64& registry) {\n\tScreen* screen = static_cast<Screen*>(this->ptr);\n\n\tImGui::Begin(\"Scene\", (bool*)0, ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoScrollbar /*| ImGuiWindowFlags_NoInputs*/);\n\tsceneHovered = ImGui::IsWindowHovered();\n\tImVec2 pos = ImGui::GetWindowPos();\n\tImVec2 min = ImGui::GetWindowContentRegionMin();\n\tImVec2 max = ImGui::GetWindowContentRegionMax();\n\t\n\tImVec2 size = ImVec2(max.x - min.x, max.y - min.y);\n\tmin = ImVec2(min.x + pos.x, min.y + pos.y);\n\tmax = ImVec2(max.x + pos.x, max.y + pos.y);\n\thandler->viewport = Vec4(min.x, min.y, size.x, size.y);\n\n\tSRef<Graphics::Texture> texture = screen->screenFrameBuffer->texture;\n\tImGui::Image((void*) (std::intptr_t) texture->getID(), size, ImVec2(0, 1), ImVec2(1, 0));\n\tImGui::End();\n\n\tGraphics::renderImGuiStyleEditor();\n\n\tif (Graphics::GUI::windowInfo.dimension.x != size.x || Graphics::GUI::windowInfo.dimension.y != size.y) {\n\t\tEngine::FrameBufferResizeEvent event(static_cast<unsigned>(size.x), static_cast<unsigned>(size.y));\n\t\thandler->onFrameBufferResize(event);\n\t}\n}\n\nvoid ImGuiLayer::onClose(Engine::Registry64& registry) {\n\tImGui_ImplOpenGL3_Shutdown();\n\tImGui_ImplGlfw_Shutdown();\n\tImGui::DestroyContext();\n}\n\nvoid ImGuiLayer::begin() {\n\tImGui_ImplOpenGL3_NewFrame();\n\tImGui_ImplGlfw_NewFrame();\n\tImGui::NewFrame();\n\n\tstatic bool opt_fullscreen_persistant = true;\n\tbool opt_fullscreen = opt_fullscreen_persistant;\n\tImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_None;\n\tImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;\n\tif (opt_fullscreen) {\n\t\tImGuiViewport* viewport = ImGui::GetMainViewport();\n\t\tImGui::SetNextWindowPos(viewport->GetWorkPos());\n\t\tImGui::SetNextWindowSize(viewport->GetWorkSize());\n\t\tImGui::SetNextWindowViewport(viewport->ID);\n\t\tImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);\n\t\tImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);\n\t\twindow_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;\n\t\twindow_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;\n\t}\n\n\tif (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode)\n\t\twindow_flags |= ImGuiWindowFlags_NoBackground;\n\n\tImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));\n\tImGui::Begin(\"Physics3D\", (bool*) true, window_flags);\n\tImGui::PopStyleVar();\n\n\tif (opt_fullscreen)\n\t\tImGui::PopStyleVar(2);\n\n\tImGuiIO& io = ImGui::GetIO();\n\tif (io.ConfigFlags & ImGuiConfigFlags_DockingEnable) {\n\t\tImGuiID dockspace_id = ImGui::GetID(\"DockSpace\");\n\t\tImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);\n\t}\n\n\tif (ImGui::BeginMenuBar()) {\n\t\tif (ImGui::BeginMenu(\"File\")) {\n\t\t\tif (ImGui::MenuItem(\"Save world\", \"CTRL-S\")) {\n\t\t\t\tEngine::KeyPressEvent event(Engine::Keyboard::KEY_S, Engine::Modifier::CTRL);\n\t\t\t\thandler->onEvent(event);\n\t\t\t}\n\t\t\tif (ImGui::MenuItem(\"Load world\", \"CTRL-O\")) {\n\t\t\t\tEngine::KeyPressEvent event(Engine::Keyboard::KEY_O, Engine::Modifier::CTRL);\n\t\t\t\thandler->onEvent(event);\n\t\t\t}\n\t\t\tif (ImGui::MenuItem(\"Exit\", \"esc\")) {\n\t\t\t\tEngine::KeyPressEvent event(Engine::Keyboard::KEY_ESCAPE);\n\t\t\t\thandler->onEvent(event);\n\t\t\t}\n\n\t\t\tImGui::EndMenu();\n\t\t}\n\n\t\tif (ImGui::BeginMenu(\"Edit\")) {\n\t\t\tif (ImGui::MenuItem(\"Play / pause\", \"P\")) {\n\t\t\t\tEngine::KeyPressEvent event(Engine::Keyboard::KEY_P);\n\t\t\t\thandler->onEvent(event);\n\t\t\t}\n\t\t\tif (ImGui::MenuItem(\"Tick\", \"T\")) {\n\t\t\t\tEngine::KeyPressEvent event(Engine::Keyboard::KEY_T);\n\t\t\t\thandler->onEvent(event);\n\t\t\t}\n\t\t\tif (ImGui::MenuItem(\"New part\", \"O\")) {\n\t\t\t\tEngine::KeyPressEvent event(Engine::Keyboard::KEY_O);\n\t\t\t\thandler->onEvent(event);\n\t\t\t}\n\t\t\tif (ImGui::MenuItem(\"Delete part\", \"DELETE\")) {\n\t\t\t\tEngine::KeyPressEvent event(Engine::Keyboard::KEY_DELETE);\n\t\t\t\thandler->onEvent(event);\n\t\t\t}\n\n\t\t\tImGui::EndMenu();\n\t\t}\n\n\t\tif (ImGui::BeginMenu(\"Debug\")) {\n\t\t\tif (ImGui::MenuItem(\"Debug info\", \"F\")) {\n\t\t\t\tEngine::KeyPressEvent event(Engine::Keyboard::KEY_F);\n\t\t\t\thandler->onEvent(event);\n\t\t\t}\n\n\t\t\tImGui::EndMenu();\n\t\t}\n\n\t\t\n\t\tImGui::EndMenuBar();\n\t}\n}\n\nvoid ImGuiLayer::end() {\n\t// End the dockspace\n\tImGui::End();\n\n\t// End imgui\n\tImGuiIO& io = ImGui::GetIO();\n\tScreen* screen = static_cast<Screen*>(this->ptr);\n\tio.DisplaySize = ImVec2((float) screen->dimension.x, (float) screen->dimension.y);\n\tImGui::Render();\n\n\tGraphics::Renderer::bindFramebuffer(0);\n\tImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());\n\n\tif (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {\n\t\tGLFWwindow* backupContext = Graphics::GLFW::getCurrentContext();\n\t\tImGui::UpdatePlatformWindows();\n\t\tImGui::RenderPlatformWindowsDefault();\n\t\tGraphics::GLFW::setCurrentContext(backupContext);\n\t}\n}\n\n};\n"
  },
  {
    "path": "application/layer/imguiLayer.h",
    "content": "#pragma once\n\n#include \"../engine/layer/layer.h\"\n\nnamespace P3D::Application {\n\nclass Screen;\n\nclass ImGuiLayer : public Engine::Layer {\npublic:\n\tbool sceneHovered = false;\n\n\tinline ImGuiLayer() : Layer() {};\n\tinline ImGuiLayer(Screen* screen, char flags = None) : Layer(\"ImGui\", screen, flags) {};\n\n\tvirtual void onInit(Engine::Registry64& registry) override;\n\tvirtual void onUpdate(Engine::Registry64& registry) override;\n\tvirtual void onEvent(Engine::Registry64& registry, Engine::Event& event) override;\n\tvirtual void onRender(Engine::Registry64& registry) override;\n\tvirtual void onClose(Engine::Registry64& registry) override;\n\n\tvoid begin();\n\tvoid end();\n};\n\n};"
  },
  {
    "path": "application/layer/modelLayer.cpp",
    "content": "#include \"core.h\"\n\n#include \"modelLayer.h\"\n\n#include <GL/glew.h>\n\n#include \"view/screen.h\"\n#include \"shader/shaders.h\"\n#include \"extendedPart.h\"\n#include \"worlds.h\"\n\n#include \"../engine/ecs/registry.h\"\n#include \"ecs/components.h\"\n\n#include \"../graphics/meshRegistry.h\"\n#include \"../graphics/ecs/components.h\"\n#include \"../graphics/mesh/indexedMesh.h\"\n#include \"../graphics/debug/visualDebug.h\"\n\n#include \"../graphics/gui/color.h\"\n\n#include <Physics3D/math/linalg/vec.h>\n#include <Physics3D/boundstree/filters/visibilityFilter.h>\n\n#include \"skyboxLayer.h\"\n#include \"../util/resource/resourceManager.h\"\n#include \"../layer/shadowLayer.h\"\n\n#include \"../graphics/batch/instanceBatchManager.h\"\n#include \"picker/tools/selectionTool.h\"\n\nnamespace P3D::Application {\n\nenum class RelationToSelectedPart {\n\tNONE,\n\tSELF,\n\tDIRECT_ATTACH,\n\tMAINPART,\n\tPHYSICAL_ATTACH,\n\tMAINPHYSICAL_ATTACH\n};\n\nstatic RelationToSelectedPart getRelationToSelectedPart(const Part* selectedPart, const Part* testPart) {\n\tif (selectedPart == nullptr)\n\t\treturn RelationToSelectedPart::NONE;\n\n\tif (testPart == selectedPart)\n\t\treturn RelationToSelectedPart::SELF;\n\n\tPhysical* selectedPartPhysical = selectedPart->getPhysical();\n\tPhysical* testPartPhysical = testPart->getPhysical();\n\tif (selectedPartPhysical != nullptr && testPartPhysical != nullptr) {\n\t\tif (testPartPhysical == testPartPhysical) {\n\t\t\tif(testPart->isMainPart()) {\n\t\t\t\treturn RelationToSelectedPart::MAINPART;\n\t\t\t} else {\n\t\t\t\treturn RelationToSelectedPart::DIRECT_ATTACH;\n\t\t\t}\n\t\t} else if (testPartPhysical->mainPhysical == selectedPartPhysical->mainPhysical) {\n\t\t\tif(testPartPhysical->isMainPhysical()) {\n\t\t\t\treturn RelationToSelectedPart::MAINPHYSICAL_ATTACH;\n\t\t\t} else {\n\t\t\t\treturn RelationToSelectedPart::PHYSICAL_ATTACH;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn RelationToSelectedPart::NONE;\n}\n\nstatic Color getAmbientForPartForSelected(Screen* screen, Part* part) {\n\tswitch (getRelationToSelectedPart(screen->selectedPart, part)) {\n\t\tcase RelationToSelectedPart::NONE:\n\t\t\treturn Color(0.0f, 0, 0, 0);\n\t\tcase RelationToSelectedPart::SELF:\n\t\t\treturn Color(0.5f, 0, 0, 0);\n\t\tcase RelationToSelectedPart::DIRECT_ATTACH:\n\t\t\treturn Color(0, 0.25f, 0, 0);\n\t\tcase RelationToSelectedPart::MAINPART:\n\t\t\treturn Color(0, 1.0f, 0, 0);\n\t\tcase RelationToSelectedPart::PHYSICAL_ATTACH:\n\t\t\treturn Color(0, 0, 0.25f, 0);\n\t\tcase RelationToSelectedPart::MAINPHYSICAL_ATTACH:\n\t\t\treturn Color(0, 0, 1.0f, 0);\n\t}\n\n\treturn Color(0, 0, 0, 0);\n}\n\nstatic Color getAlbedoForPart(Screen* screen, ExtendedPart* part) {\n\tColor computedAmbient = getAmbientForPartForSelected(screen, part);\n\n\t// if (part->entity is intersected)\n\t//\tcomputedAmbient = Vec4f(computedAmbient) + Vec4f(-0.1f, -0.1f, -0.1f, 0);\n\n\treturn computedAmbient;\n}\n\nvoid ModelLayer::onInit(Engine::Registry64& registry) {\n\tusing namespace Graphics;\n\tScreen* screen = static_cast<Screen*>(this->ptr);\n\n\t// Dont know anymore\n\tShaders::basicShader->updateTexture(false);\n\n\t// Instance batch manager\n\tmanager = new InstanceBatchManager(Shaders::instanceShader, DEFAULT_UNIFORM_BUFFER_LAYOUT);\n}\n\nvoid ModelLayer::onUpdate(Engine::Registry64& registry) {\n\tauto view = registry.view<Comp::Light>();\n\n\tstd::size_t index = 0;\n\tfor (auto entity : view) {\n\t\tIRef<Comp::Light> light = view.get<Comp::Light>(entity);\n\n\t\tPosition position;\n\t\tIRef<Comp::Transform> transform = registry.get<Comp::Transform>(entity);\n\t\tif (transform.valid()) \n\t\t\tposition = transform->getCFrame().getPosition();\n\t\t\n\t\tShaders::basicShader->updateLight(index, position, *light);\n\t\tShaders::instanceShader->updateLight(index, position, *light);\n\t\t\n\t\tindex += 1;\n\t}\n\n\tShaders::basicShader->updateLightCount(index);\n\tShaders::instanceShader->updateLightCount(index);\n}\n\nvoid ModelLayer::onEvent(Engine::Registry64& registry, Engine::Event& event) {\n\n}\n\t\t\nvoid ModelLayer::onRender(Engine::Registry64& registry) {\n\tusing namespace Graphics;\n\tusing namespace Renderer;\n\tScreen* screen = static_cast<Screen*>(this->ptr);\n\n\tbeginScene();\n\n\t// Matrices\n\tgraphicsMeasure.mark(UPDATE);\n\tShaders::debugShader->updateProjection(screen->camera.viewMatrix, screen->camera.projectionMatrix, screen->camera.cframe.position);\n\tShaders::basicShader->updateProjection(screen->camera.viewMatrix, screen->camera.projectionMatrix, screen->camera.cframe.position);\n\tShaders::instanceShader->updateProjection(screen->camera.viewMatrix, screen->camera.projectionMatrix, screen->camera.cframe.position);\n\n\t// Shadow\n\tVec3f from = { -10, 10, -10 };\n\tVec3f to = { 0, 0, 0 };\n\tVec3f sunDirection = to - from;\n\tShadowLayer::lightView = lookAt(from, to);\n\tShadowLayer::lighSpaceMatrix = ShadowLayer::lightProjection * ShadowLayer::lightView;\n\tRenderer::activeTexture(32);\n\tRenderer::bindTexture2D(ShadowLayer::depthMap);\n\tShaders::instanceShader->setUniform(\"shadowMap\", 32);\n\tShaders::instanceShader->setUniform(\"lightMatrix\", ShadowLayer::lighSpaceMatrix);\n\tShaders::instanceShader->updateSunDirection(sunDirection);\n\n\t// Skybox\n\tShaders::instanceShader->setUniform(\"skyboxTexture\", 31);\n\tSkyboxLayer::skyboxTexture->bind(31);\n\n\tgraphicsMeasure.mark(PHYSICALS);\n\t\n\t// Filter on mesh ID and transparency\n\tstruct EntityInfo {\n\t\tEngine::Registry64::entity_type entity = 0;\n\t\tComp::Transform transform;\n\t\tGraphics::Comp::Material material;\n\t\tIRef<Graphics::Comp::Mesh> mesh;\n\t\tIRef<Comp::Collider> collider;\n\t};\n\t\n\tstd::map<double, EntityInfo> transparentEntities;\n\n\t{\n\t\tstd::shared_lock<UpgradeableMutex> worldReadLock(*screen->worldMutex);\n\t\tVisibilityFilter filter = VisibilityFilter::forWindow(screen->camera.cframe.position, screen->camera.getForwardDirection(), screen->camera.getUpDirection(), screen->camera.fov, screen->camera.aspect, screen->camera.zfar);\n\n\t\tauto view = registry.view<Graphics::Comp::Mesh>();\n\t\tfor (auto entity : view) {\n\t\t\tEntityInfo info;\n\t\t\tinfo.entity = entity;\n\t\t\t\n\t\t\tinfo.mesh = view.get<Graphics::Comp::Mesh>(entity);\n\t\t\tif (!info.mesh.valid())\n\t\t\t\tcontinue;\n\n\t\t\tif (info.mesh->id == -1)\n\t\t\t\tcontinue;\n\n\t\t\tif (!info.mesh->visible)\n\t\t\t\tcontinue;\n\t\t\t\n\t\t\tinfo.collider = registry.get<Comp::Collider>(entity);\n\t\t\tif (info.collider.valid())\n\t\t\t\tif (!filter(*info.collider->part))\n\t\t\t\t\tcontinue;\n\n\t\t\tinfo.transform = registry.getOr<Comp::Transform>(entity);\n\t\t\tinfo.material = registry.getOr<Graphics::Comp::Material>(entity);\n\t\t\t\n\t\t\tif (info.material.albedo.a < 1.0f) {\n\t\t\t\tdouble distance = lengthSquared(Vec3(screen->camera.cframe.position - info.transform.getPosition()));\n\t\t\t\ttransparentEntities.insert(std::make_pair(distance, info));\n\t\t\t} else {\n\t\t\t\tMat4f modelMatrix = info.transform.getModelMatrix();\n\n\t\t\t\tif (info.collider.valid())\n\t\t\t\t\tinfo.material.albedo += getAlbedoForPart(screen, info.collider->part);\n\t\t\t\t\n\t\t\t\tmanager->add(info.mesh->id, modelMatrix, info.material);\n\t\t\t}\n\t\t}\n\n\t\tShaders::instanceShader->bind();\n\t\tmanager->submit();\n\n\n\t\t// Render transparent meshes\n\t\tShaders::basicShader->bind();\n\t\tenableBlending();\n\t\tfor (auto iterator = transparentEntities.rbegin(); iterator != transparentEntities.rend(); ++iterator) {\n\t\t\tEntityInfo info = iterator->second;\n\n\t\t\tif (info.mesh->id == -1)\n\t\t\t\tcontinue;\n\n\t\t\tif (!info.mesh->visible)\n\t\t\t\tcontinue;\n\n\t\t\tif (info.collider.valid())\n\t\t\t\tinfo.material.albedo += getAlbedoForPart(screen, info.collider->part);\n\n\t\t\tShaders::basicShader->updateMaterial(info.material);\n\t\t\tShaders::basicShader->updateModel(info.transform.getModelMatrix());\n\t\t\tMeshRegistry::meshes[info.mesh->id]->render();\n\t\t}\n\n\t\tauto scf = SelectionTool::selection.getCFrame();\n\t\tauto shb = SelectionTool::selection.getHitbox();\n\t\tif (scf.has_value() && shb.has_value()) {\n\t\t\tGraphics::Comp::Mesh data = MeshRegistry::getMesh(shb->baseShape.get());\n\t\t\tShaders::debugShader->updateModel(scf.value().asMat4WithPreScale(shb->scale));\n\t\t\tMeshRegistry::meshes[data.id]->render();\n\t\t}\n\t\t\n\t\t// Hitbox drawing\n\t\tfor (auto entity : SelectionTool::selection) {\n\t\t\tIRef<Comp::Transform> transform = registry.get<Comp::Transform>(entity);\n\t\t\tif (transform.valid()) {\n\t\t\t\tIRef<Comp::Hitbox> hitbox = registry.get<Comp::Hitbox>(entity);\n\n\t\t\t\tif (hitbox.valid()) {\n\t\t\t\t\tShape shape = hitbox->getShape();\n\n\t\t\t\t\tif (!hitbox->isPartAttached())\n\t\t\t\t\t\tshape = shape.scaled(transform->getScale());\n\n\t\t\t\t\tGraphics::Comp::Mesh data = MeshRegistry::getMesh(shape.baseShape.get());\n\n\t\t\t\t\tShaders::debugShader->updateModel(transform->getCFrame().asMat4WithPreScale(shape.scale));\n\t\t\t\t\tMeshRegistry::meshes[data.id]->render();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tendScene();\n}\n\nvoid ModelLayer::onClose(Engine::Registry64& registry) {\n\n}\n\n};"
  },
  {
    "path": "application/layer/modelLayer.h",
    "content": "#pragma once\n\n#include \"../graphics/batch/instanceBatchManager.h\"\n#include \"../engine/layer/layer.h\"\n\nnamespace P3D::Application {\n\nclass Screen;\n\nclass ModelLayer final : public Engine::Layer {\npublic:\n\n\tGraphics::InstanceBatchManager* manager = nullptr;\n\t\npublic:\n\tModelLayer() : Layer() {}\n\tModelLayer(Screen* screen, char flags = None) : Layer(\"Model\", screen, flags) {}\n\n\tvirtual ~ModelLayer() = default;\n\t\n\tvoid onInit(Engine::Registry64& registry) override;\n\tvoid onUpdate(Engine::Registry64& registry) override;\n\tvoid onEvent(Engine::Registry64& registry, Engine::Event& event) override;\n\tvoid onRender(Engine::Registry64& registry) override;\n\tvoid onClose(Engine::Registry64& registry) override;\n};\n\n};"
  },
  {
    "path": "application/layer/pickerLayer.cpp",
    "content": "#include \"core.h\"\n\n#include \"pickerLayer.h\"\n\n#include \"../application.h\"\n#include \"../graphics/debug/visualDebug.h\"\n#include \"view/screen.h\"\n#include \"input/standardInputHandler.h\"\n\n#include \"../engine/tool/toolManager.h\"\n#include \"../graphics/renderer.h\"\n#include \"../picker/tools/selectionTool.h\"\n#include \"../picker/tools/regionSelectionTool.h\"\n#include \"../picker/tools/translationTool.h\"\n#include \"../picker/tools/rotationTool.h\"\n#include \"../picker/tools/scaleTool.h\"\n#include \"../picker/ray.h\"\n#include \"picker/tools/alignmentLinkTool.h\"\n#include \"picker/tools/attachmentTool.h\"\n#include \"picker/tools/elasticLinkTool.h\"\n#include \"picker/tools/fixedConstraintTool.h\"\n#include \"picker/tools/magneticLinkTool.h\"\n#include \"picker/tools/motorConstraintTool.h\"\n#include \"picker/tools/pathTool.h\"\n#include \"picker/tools/pistonConstraintTool.h\"\n#include \"picker/tools/springLinkTool.h\"\n#include \"picker/tools/toolSpacing.h\"\n\nnamespace P3D::Application {\n\nstd::vector<Engine::ToolManager> PickerLayer::toolManagers;\n\t\nvoid PickerLayer::onInit(Engine::Registry64& registry) {\n\tEngine::ToolManager toolManager;\n\ttoolManager.registerTool<SelectionTool>();\n\ttoolManager.registerTool<RegionSelectionTool>();\n\ttoolManager.registerTool<TranslationTool>();\n\ttoolManager.registerTool<RotationTool>();\n\ttoolManager.registerTool<ScaleTool>();\n\t\n\ttoolManager.registerTool<ToolSpacing>();\n\n\ttoolManager.registerTool<AttachmentTool>();\n\ttoolManager.registerTool<FixedConstraintTool>();\n\ttoolManager.registerTool<MotorConstraintTool>();\n\ttoolManager.registerTool<PistonConstraintTool>();\n\n\ttoolManager.registerTool<ToolSpacing>();\n\t\n\ttoolManager.registerTool<MagneticLinkTool>();\n\ttoolManager.registerTool<SpringLinkTool>();\n\ttoolManager.registerTool<ElasticLinkTool>();\n\ttoolManager.registerTool<AlignmentLinkTool>();\n\t\n\ttoolManager.registerTool<ToolSpacing>();\n\n\ttoolManager.registerTool<PathTool>();\n\n\ttoolManager.selectTool<TranslationTool>();\n\n\ttoolManagers.push_back(std::move(toolManager));\n}\n\nvoid PickerLayer::onUpdate(Engine::Registry64& registry) {\n\tScreen* screen = static_cast<Screen*>(this->ptr);\n\t\n\tGraphics::graphicsMeasure.mark(Graphics::GraphicsProcess::PICKER);\n\n\t// Update selection context\n\tSelectionTool::mouse = handler->mousePosition;\n\tSelectionTool::ray = getMouseRay(*screen, handler->mousePosition);\n\n\tif (!isPaused())\n\t\tSelectionTool::selection.recalculateSelection();\n\n\tfor (Engine::ToolManager& toolManager : toolManagers)\n\t\ttoolManager.onUpdate();\n}\n\nvoid PickerLayer::onEvent(Engine::Registry64& registry, Engine::Event& event) {\n\tfor (Engine::ToolManager& toolManager : toolManagers)\n\t\ttoolManager.onEvent(event);\n}\n\nvoid PickerLayer::onRender(Engine::Registry64& registry) {\n\tusing namespace Graphics;\n\tusing namespace Renderer;\n\tScreen* screen = static_cast<Screen*>(this->ptr);\n\n\tbeginScene();\n\n\tclearDepth();\n\tenableDepthTest();\n\n\tfor (Engine::ToolManager& toolManager : toolManagers)\n\t\ttoolManager.onRender();\n\n\tdisableDepthTest();\n\tendScene();\n}\n\nvoid PickerLayer::onClose(Engine::Registry64& registry) {\n\tfor (Engine::ToolManager& toolManager : toolManagers)\n\t\ttoolManager.onClose();\n}\n\n};\n\n/*\nvoid moveGrabbedEntityLateral(Screen& screen) {\n\tif (screen.world->selectedPart == nullptr)\n\t\treturn;\nif (!screen.selectedEntity)\nreturn;\n\nVec3 cameraDirection = screen.camera.cframe.rotation * Vec3(0, 0, 1);\n\ndouble distance = Vec3(screen.selectedPoint - screen.camera.cframe.position) * cameraDirection / (SelectionTool::ray.direction * cameraDirection);\nPosition planeIntersection = screen.camera.cframe.position + SelectionTool::ray.direction * distance;\n\nif (isPaused()) {\n\tVec3 translation = planeIntersection - screen.selectedPoint;\n\tscreen.selectedPoint += translation;\n\tRef<Comp::Transform> transform = screen.registry.get<Comp::Transform>(screen.selectedEntity);\n\tif (transform.valid())\n\t\ttransform->translate(translation);\n} else {\n\tscreen.world->selectedPart = screen.selectedPart;\n\tscreen.world->magnetPoint = planeIntersection;\n}\n}\n\nvoid moveGrabbedEntityTransversal(Screen& screen, double dz) {\n\tif (screen.world->selectedPart == nullptr)\n\t\treturn;\n\tif (!screen.selectedEntity)\n\t\treturn;\n\n\tVec3 cameraDirection = screen.camera.cframe.rotation * Vec3(0, 0, 1);\n\tVec3 cameraYDirection = normalize(Vec3(cameraDirection.x, 0, cameraDirection.z));\n\n\tdouble distance = Vec3(screen.selectedPoint - screen.camera.cframe.position) * cameraDirection / (SelectionTool::ray.direction * cameraDirection);\n\tPosition planeIntersection = screen.camera.cframe.position + SelectionTool::ray.direction * distance;\n\n\tVec3 translation = -cameraYDirection * dz;\n\tif (isPaused()) {\n\t\tscreen.selectedPoint += translation;\n\t\tRef<Comp::Transform> transform = screen.registry.get<Comp::Transform>(screen.selectedEntity);\n\t\tif (transform.valid())\n\t\t\ttransform->translate(translation);\n\t} else {\n\t\tscreen.world->selectedPart = screen.selectedPart;\n\t\tscreen.world->magnetPoint += translation;\n\t}\n}\n*/"
  },
  {
    "path": "application/layer/pickerLayer.h",
    "content": "#pragma once\n\n#include \"../engine/tool/toolManager.h\"\n#include \"../engine/layer/layer.h\"\n\nnamespace P3D::Application {\n\nclass Screen;\n\nclass PickerLayer : public Engine::Layer {\npublic:\n\tstatic std::vector<Engine::ToolManager> toolManagers;\n\n\tPickerLayer() : Layer() {}\n\tPickerLayer(Screen* screen, char flags = None) : Layer(\"Picker\", screen, flags) {}\n\n\tvoid onInit(Engine::Registry64& registry) override;\n\tvoid onUpdate(Engine::Registry64& registry) override;\n\tvoid onEvent(Engine::Registry64& registry, Engine::Event& event) override;\n\tvoid onRender(Engine::Registry64& registry) override;\n\tvoid onClose(Engine::Registry64& registry) override;\n};\n\n};"
  },
  {
    "path": "application/layer/postprocessLayer.cpp",
    "content": "#include \"core.h\"\n\n#include \"postprocessLayer.h\"\n\n#include \"../graphics/buffers/frameBuffer.h\"\n#include \"../graphics/mesh/primitive.h\"\n#include \"../graphics/renderer.h\"\n#include \"../graphics/texture.h\"\n\n#include \"../application/shader/shaders.h\"\n#include \"../view/screen.h\"\n\nnamespace P3D::Application {\n\nvoid PostprocessLayer::onInit(Engine::Registry64& registry) {\n\n}\n\nvoid PostprocessLayer::onUpdate(Engine::Registry64& registry) {\n\n}\n\nvoid PostprocessLayer::onEvent(Engine::Registry64& registry, Engine::Event& event) {\n\n}\n\nvoid PostprocessLayer::onRender(Engine::Registry64& registry) {\n\tusing namespace Graphics;\n\tusing namespace Graphics::Renderer;\n\tScreen* screen = static_cast<Screen*>(this->ptr);\n}\n\nvoid PostprocessLayer::onClose(Engine::Registry64& registry) {\n\n}\n\n};"
  },
  {
    "path": "application/layer/postprocessLayer.h",
    "content": "#pragma once\n\n#include \"../engine/layer/layer.h\"\n\nnamespace P3D::Application {\n\nclass Screen;\n\nclass PostprocessLayer : public Engine::Layer {\nprivate:\n\tEngine::Registry64::entity_type entity;\n\t\npublic:\n\tPostprocessLayer() : Layer() {}\n\tPostprocessLayer(Screen* screen, char flags = 0) : Layer(\"Postprocess\", screen, flags) {};\n\n\tvoid onInit(Engine::Registry64& registry) override;\n\tvoid onUpdate(Engine::Registry64& registry) override;\n\tvoid onEvent(Engine::Registry64& registry, Engine::Event& event) override;\n\tvoid onRender(Engine::Registry64& registry) override;\n\tvoid onClose(Engine::Registry64& registry) override;\n};\n\n};"
  },
  {
    "path": "application/layer/shadowLayer.cpp",
    "content": "#include \"core.h\"\n#include \"shadowLayer.h\"\n\n#include <GL/glew.h>\n\n#include <Physics3D/world.h>\n#include <Physics3D/worldIteration.h>\n#include <Physics3D/boundstree/filters/visibilityFilter.h>\n\n#include \"view/screen.h\"\n#include \"../graphics/gui/gui.h\"\n#include \"../graphics/renderer.h\"\n#include \"../graphics/shader/shader.h\"\n#include \"../graphics/mesh/indexedMesh.h\"\n#include \"../graphics/buffers/frameBuffer.h\"\n#include \"../util/resource/resourceManager.h\"\n#include \"../graphics/meshRegistry.h\"\n#include \"ecs/components.h\"\n#include \"worlds.h\"\n#include \"application.h\"\n#include \"shader/shaders.h\"\n\nnamespace P3D::Application {\n\nfloat near = 0.001f;\nfloat far = 100.0f;\n\nMat4f ShadowLayer::lightProjection = ortho(-25.0, 25.0, -25.0, 25.0, near, far);\nMat4f ShadowLayer::lightView = lookAt({ -15.0, 15.0, -15.0 }, { 0.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 });\nMat4f ShadowLayer::lighSpaceMatrix = lightProjection * lightView;\nunsigned int ShadowLayer::depthMap = 0;\n\nGLID depthMapFBO;\nGLID WIDTH = 2048;\nGLID HEIGHT = 2048;\n\nIndexedMesh* mesh = nullptr;\n\nvoid ShadowLayer::onInit(Engine::Registry64& registry) {\n\tglGenFramebuffers(1, &depthMapFBO);\n\n\tglGenTextures(1, &depthMap);\n\tglBindTexture(GL_TEXTURE_2D, depthMap);\n\tglTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT,\n\t\tWIDTH, HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);\n\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);\n\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);\n\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);\n\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);\n\tfloat borderColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };\n\tglTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);\n\n\tglBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);\n\tglFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthMap, 0);\n\tglDrawBuffer(GL_NONE);\n\tglReadBuffer(GL_NONE);\n\tglBindFramebuffer(GL_FRAMEBUFFER, 0/*screen->screenFrameBuffer->getID()*/);\n}\n\nvoid ShadowLayer::onUpdate(Engine::Registry64& registry) {\n\n}\n\nvoid ShadowLayer::onEvent(Engine::Registry64& registry, Engine::Event& event) {\n\tusing namespace Engine;\n\n}\n\nvoid ShadowLayer::renderScene(Engine::Registry64& registry) {\n\tstd::vector<ExtendedPart*> visibleParts;\n\tstd::shared_lock<UpgradeableMutex> worldReadLock(*screen.worldMutex);\n\n\tscreen.world->forEachPart([&visibleParts](ExtendedPart& part) {\n\t\tvisibleParts.push_back(&part);\n\t});\n\n\tfor (ExtendedPart* part : visibleParts) {\n\t\tIRef<Graphics::Comp::Mesh> mesh = registry.get<Graphics::Comp::Mesh>(part->entity);\n\n\t\tif (!mesh.valid())\n\t\t\tcontinue;\n\n\t\tif (mesh->id == -1)\n\t\t\tcontinue;\n\n\t\tif (!mesh->visible)\n\t\t\tcontinue;\n\n\t\tShaders::depthShader->updateModel(part->getCFrame().asMat4WithPreScale(part->hitbox.scale));\n\t\tGraphics::MeshRegistry::meshes[mesh->id]->render();\n\t}\n}\n\nvoid ShadowLayer::onRender(Engine::Registry64& registry) {\n\tusing namespace Graphics;\n\tusing namespace Renderer;\n\n\tScreen* screen = static_cast<Screen*>(this->ptr);\n\n\tShaders::depthShader->bind();\n\tShaders::depthShader->updateLight(lighSpaceMatrix);\n\tglViewport(0, 0, WIDTH, HEIGHT);\n\tglBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);\n\tglClear(GL_DEPTH_BUFFER_BIT);\n\tRenderer::disableCulling();\n\t//glCullFace(GL_FRONT_AND_BACK);\n\trenderScene(registry);\n\t//glCullFace(GL_BACK);\n\tRenderer::enableCulling();\n\tglBindFramebuffer(GL_FRAMEBUFFER, screen->screenFrameBuffer->getID());\n\tglViewport(0, 0, GUI::windowInfo.dimension.x, GUI::windowInfo.dimension.y);\n\n\t/*Shaders::depthBufferShader.bind();\n\tShaders::depthBufferShader.updatePlanes(near, far);\n\tShaders::depthBufferShader.updateDepthMap(0, depthMap);\n\tGraphics::renderQuad();*/\n}\n\nvoid ShadowLayer::onClose(Engine::Registry64& registry) {\n}\n\n};"
  },
  {
    "path": "application/layer/shadowLayer.h",
    "content": "#pragma once\n\n#include \"../engine/layer/layer.h\"\n\nnamespace P3D::Application {\n\nclass Screen;\n\nclass ShadowLayer : public Engine::Layer {\npublic:\n\tstatic unsigned int depthMap;\n\tstatic Mat4f lightProjection;\n\tstatic Mat4f lighSpaceMatrix;\n\tstatic Mat4f lightView;\n\n\tinline ShadowLayer() : Layer() {};\n\tinline ShadowLayer(Screen* screen, char flags = None) : Layer(\"ShadowLayer\", screen, flags) {};\n\n\tvoid renderScene(Engine::Registry64& registry);\n\n\tvirtual void onInit(Engine::Registry64& registry) override;\n\tvirtual void onUpdate(Engine::Registry64& registry) override;\n\tvirtual void onEvent(Engine::Registry64& registry, Engine::Event& event) override;\n\tvirtual void onRender(Engine::Registry64& registry) override;\n\tvirtual void onClose(Engine::Registry64& registry) override;\n};\n\n};"
  },
  {
    "path": "application/layer/skyboxLayer.cpp",
    "content": "#include \"core.h\"\n#include \"skyboxLayer.h\"\n\n#include <GLFW/glfw3.h>\n#include <sstream>\n#include \"shader/shaders.h\"\n#include \"view/screen.h\"\n#include \"../graphics/renderer.h\"\n#include \"../graphics/texture.h\"\n#include \"../graphics/debug/visualDebug.h\"\n#include \"../graphics/resource/textureResource.h\"\n#include \"../graphics/gui/guiUtils.h\"\n#include \"../util/resource/resourceManager.h\"\n#include \"../graphics/mesh/primitive.h\"\n#include \"graphics/meshRegistry.h\"\n\nnamespace P3D::Application {\n\nSkyboxCycle lightColorCycle;\nSkyboxCycle skyColorCycle;\nSkyboxCycle horizonColorCycle;\nSkyboxCycle mistColorCycle;\n\nColor lightColor;\nColor skyColor;\nColor mistColor;\nColor horizonColor;\nVec2f mist;\nfloat starBrightness;\n\nGraphics::CubeMap* SkyboxLayer::skyboxTexture = nullptr;\n\nfloat getScroll(const Screen* screen) {\n\treturn static_cast<float>(std::atan2(screen->camera.viewMatrix(1, 0), screen->camera.viewMatrix(0, 0)) / screen->camera.fov / 2.0);\n}\nbool useNewSky;\nbool pauze;\nfloat time;\n\nvoid updateMist(float time) {\n\tfloat mistFactor;\n\tif (time > 0.5F) \n\t\tmistFactor = 1.0f - GUI::smoothstep(0.7083333f, 0.875f, time);\n\telse \n\t\tmistFactor = GUI::smoothstep(0.20833333f, 0.375f, time);\n\t\n\tmist = Vec2f(15.0f + mistFactor * 20.0f, 75.0f + mistFactor * 50.0f);\n}\n\nvoid updateStars(float time) {\n\tif (time > 0.5F)\n\t\tstarBrightness = GUI::smoothstep(0.9166667f, 1.0f, time);\n\telse \n\t\tstarBrightness = 1.0f - GUI::smoothstep(0.125f, 0.20833333f, time);\n\n}\n\nvoid SkyboxLayer::onInit(Engine::Registry64& registry) {\n\tskyboxTexture = new CubeMap(\"../res/skybox/right.jpg\", \"../res/skybox/left.jpg\", \"../res/skybox/top.jpg\", \"../res/skybox/bottom.jpg\", \"../res/skybox/front.jpg\", \"../res/skybox/back.jpg\");\n\n\tResourceManager::add<TextureResource>(\"night\", \"../res/textures/night.png\");\n\tResourceManager::add<TextureResource>(\"uv\", \"../res/textures/uv.png\");\n\n\tlightColorCycle = SkyboxCycle(Color(0.42f, 0.45f, 0.90f), Color(1.0f, 0.95f, 0.95f), Color(1.0f, 0.45f, 0.56f), Color(1.0f, 0.87f, 0.6f), 3.0f, 8.0f, 18.0f);\n\tskyColorCycle = SkyboxCycle(Color(0.31f, 0.44f, 0.64f), Color(0.96f, 0.93f, 0.9f), Color(0.996f, 0.77f, 0.57f), Color(1.0f, 0.94f, 0.67f), 3.0f, 8.0f, 18.0f);\n\thorizonColorCycle = SkyboxCycle(Color(0.2f, 0.2f, 0.42f), Color(0.6f, 0.9f, 1.0f), Color(0.93f, 0.49f, 0.57f), Color(1.0f, 0.64f, 0.47f), 3.0f, 8.0f, 18.0f);\n\tmistColorCycle = SkyboxCycle(Color(0.29f, 0.41f, 0.61f), Color(0.96f, 0.9f, 0.77f), Color(1.0f, 0.68f, 0.85f), Color(1.0f, 0.87f, 0.82f), 3.0f, 8.0f, 18.0f);\n}\n\nvoid SkyboxLayer::onUpdate(Engine::Registry64& registry) {\n\tif (!pauze)\n\t\ttime = fmod((float) (glfwGetTime() / 30.0), 1.0f);\n\n\tlightColor = lightColorCycle.sample(time);\n\tskyColor = skyColorCycle.sample(time);\n\tmistColor = mistColorCycle.sample(time);\n\thorizonColor = horizonColorCycle.sample(time);\n\n\tupdateMist(time);\n\tupdateStars(time);\n}\n\nvoid SkyboxLayer::onEvent(Engine::Registry64& registry, Engine::Event& event) {\n\n}\n\nvoid SkyboxLayer::onRender(Engine::Registry64& registry) {\n\tusing namespace Graphics;\n\tusing namespace Graphics::Renderer;\n\tgraphicsMeasure.mark(GraphicsProcess::SKYBOX);\n\n\tScreen* screen = static_cast<Screen*>(this->ptr);\n\t\n\tbeginScene();\n\n\tif (useNewSky) {\n\t\tdisableCulling();\n\t\tdisableDepthMask();\n\t\tenableBlending();\n\t\tResourceManager::get<TextureResource>(\"night\")->bind();\n\n\t\tShaders::skyShader->setUniform(\"nightTexture\", 0);\n\t\tShaders::skyShader->updateProjection(screen->camera.viewMatrix, screen->camera.projectionMatrix, screen->camera.cframe.position);\n\t\tShaders::skyShader->setUniform(\"starBrightness\", starBrightness);\n\t\tShaders::skyShader->setUniform(\"skyColor\", Vec3f(skyColor));\n\t\tShaders::skyShader->setUniform(\"horizonColor\", Vec3f(horizonColor));\n\t\t\n\t\tfloat scroll = getScroll(screen);\n\t\tShaders::skyShader->setUniform(\"scroll\", scroll);\n\t\tShaders::skyShader->setUniform(\"time\", time);\n\t\tShaders::skyShader->setUniform(\"skyboxSize\", 550.0f);\n\t\tShaders::skyShader->setUniform(\"segmentCount\", 25.0f);\n\n\t\tGraphics::MeshRegistry::get(Graphics::MeshRegistry::sphere)->render();\n\t} else {\n\t\tdisableCulling();\n\t\tdisableDepthMask();\n\t\tenableBlending();\n\n\t\tShaders::skyboxShader->updateProjection(screen->camera.viewMatrix, screen->camera.projectionMatrix, screen->camera.cframe.position);\n\t\tskyboxTexture->bind();\n\n\t\tGraphics::MeshRegistry::get(Graphics::MeshRegistry::sphere)->render();\n\t}\n\n\tendScene();\n}\n\nvoid SkyboxLayer::onClose(Engine::Registry64& registry) {\n\tskyboxTexture->close();\n}\n\n};"
  },
  {
    "path": "application/layer/skyboxLayer.h",
    "content": "#pragma once\n\n#include \"../engine/layer/layer.h\"\n#include \"../util/valueCycle.h\"\n#include \"../graphics/gui/color.h\"\n\nnamespace P3D {\nnamespace Graphics {\n\tclass CubeMap;\n}\n}\n\nnamespace P3D::Application {\n\nstruct SkyboxCycle : public Util::ValueCycle<Graphics::Color, Util::linear> {\npublic:\n\tSkyboxCycle() {}\n\tSkyboxCycle(const Graphics::Color& night, const Graphics::Color& day, const Graphics::Color& dusk, const Graphics::Color& dawn, float midnightEnd, float middayStart, float middayEnd) {\n\t\tfloat _midnightEnd = midnightEnd / 24.0f;\n\t\tfloat _middayStart = middayStart / 24.0f;\n\t\tfloat _middayEnd = middayEnd / 24.0f;\n\t\t\n\t\taddKeyframe(0.0f, night);\n\t\taddKeyframe(_midnightEnd, night);\n\t\taddKeyframe(_midnightEnd + (_middayStart - _midnightEnd) * 0.5f, dawn);\n\t\taddKeyframe(_middayStart, day);\n\t\taddKeyframe(_middayEnd, day);\n\t\taddKeyframe(_middayEnd + (1.0f - _middayEnd) * 0.5f, dusk);\n\t\taddKeyframe(1.0f, night);\n\t}\n};\n\nclass Screen;\n\nfloat getScroll(const Screen* screen);\nextern bool useNewSky;\nextern bool pauze;\nextern float time;\n\n\nclass SkyboxLayer : public Engine::Layer {\npublic:\n\tstatic Graphics::CubeMap* skyboxTexture;\n\n\tSkyboxLayer() : Layer() {}\n\tSkyboxLayer(Screen* screen, char flags = NoEvents) : Layer(\"Skybox\", screen, flags) {}\n\n\tvoid onInit(Engine::Registry64& registry) override;\n\tvoid onUpdate(Engine::Registry64& registry) override;\n\tvoid onEvent(Engine::Registry64& registry, Engine::Event& event) override;\n\tvoid onRender(Engine::Registry64& registry) override;\n\tvoid onClose(Engine::Registry64& registry) override;\n};\n\n};"
  },
  {
    "path": "application/layer/testLayer.cpp",
    "content": "#include \"core.h\"\n#include \"GL/glew.h\"\n\n#include \"testLayer.h\"\n#include \"view/screen.h\"\n#include \"../graphics/renderer.h\"\n#include \"imgui/imgui.h\"\n\nnamespace P3D::Application {\n\nvoid TestLayer::onInit(Engine::Registry64& registry) {\n\t\n}\n\nvoid TestLayer::onUpdate(Engine::Registry64& registry) {\n\n}\n\nvoid TestLayer::onEvent(Engine::Registry64& registry, Engine::Event& event) {\n\tusing namespace Engine;\n\n}\n\nvoid TestLayer::onRender(Engine::Registry64& registry) {\n\tusing namespace Graphics;\n\tusing namespace Renderer;\n\n\tScreen* screen = static_cast<Screen*>(this->ptr);\n}\n\nvoid TestLayer::onClose(Engine::Registry64& registry) {\n}\n\n};"
  },
  {
    "path": "application/layer/testLayer.h",
    "content": "#pragma once\n\n#include \"../engine/layer/layer.h\"\n\nnamespace P3D::Application {\n\nclass Screen;\n\nclass TestLayer : public Engine::Layer {\npublic:\n\tTestLayer() : Layer() {};\n\tTestLayer(Screen* screen, char flags = None) : Layer(\"TestLayer\", screen, flags) {};\n\n\tvoid onInit(Engine::Registry64& registry) override;\n\tvoid onUpdate(Engine::Registry64& registry) override;\n\tvoid onEvent(Engine::Registry64& registry, Engine::Event& event) override;\n\tvoid onRender(Engine::Registry64& registry) override;\n\tvoid onClose(Engine::Registry64& registry) override;\n};\n\n};"
  },
  {
    "path": "application/legacy/frames.h",
    "content": "#pragma once\n\n#include \"../graphics/gui/frame.h\"\n#include \"../graphics/gui/label.h\"\n#include \"../graphics/gui/slider.h\"\n#include \"../graphics/gui/checkBox.h\"\n#include \"../graphics/gui/image.h\"\n#include \"../graphics/gui/button.h\"\n#include \"../graphics/gui/directionEditor.h\"\n#include \"../graphics/gui/colorPicker.h\"\n#include \"../physics/misc/toString.h\"\n#include \"../graphics/debug/visualDebug.h\"\n#include \"../graphics/shader/shaderProgram.h\"\n#include \"../graphics/renderUtils.h\"\n#include \"../graphics/texture.h\"\n#include \"../graphics/resource/textureResource.h\"\n#include \"../util/resource/resourceManager.h\"\n#include \"../util/resource/resource.h\"\n#include \"shader/shaders.h\"\n#include \"extendedPart.h\"\n#include \"application.h\"\n#include \"worlds.h\"\n#include \"screen.h\"\n\nnamespace Application {\n\n// Frame blueprint\n\nstruct FrameBlueprint {\n\tvirtual void init() = 0;\n\tvirtual void update() = 0;\n};\n\nstruct ResourceManagerFrame : public FrameBlueprint, public Frame {\n\tstd::vector<Image*> images;\n\n\tResourceManagerFrame(double x, double y, std::string title) : Frame(x, y, 1, 1, title) {\n\t\tinit();\n\n\t\tGUI::add(this);\n\t}\n\n\tvoid init() override {\n\t\tupdate();\n\t}\n\n\tvoid update() override {\n\t\tauto textures = ResourceManager::getResourcesOfType(ResourceType::Texture);\n\n\t\tif (textures.size() != images.size()) {\n\t\t\tfor (Image* i : images)\n\t\t\t\tremove(i);\n\n\t\t\timages.clear();\n\n\t\t\tfor (Resource* r : textures) {\n\t\t\t\tTextureResource* tr = static_cast<TextureResource*>(r);\n\t\t\t\tImage* i = (new Image(0, 0, tr))->fixWidth(0.1);\n\t\t\t\timages.push_back(i);\n\t\t\t\tadd(i);\n\t\t\t}\n\t\t}\n\t}\n};\n\nstruct ImageFrame : public FrameBlueprint, public Frame {\n\tImage* image = nullptr;\n\n\tImageFrame(double x, double y, std::string title) : Frame(x, y, title) {\n\t\tinit();\n\n\t\tadd(image);\n\n\t\tGUI::add(this);\n\t}\n\n\tvoid init() override {\n\t\timage = (new Image(0, 0, nullptr))->fixWidth(1);\n\t}\n\n\tvoid update() override {\n\n\t}\n};\n\n// Environment frame\n\nstruct EnvironmentFrame : public FrameBlueprint, public Frame {\n\n\tLabel* gammaLabel = nullptr;\n\tSlider* gammaSlider = nullptr;\n\tLabel* gammaValueLabel = nullptr;\n\n\tLabel* exposureLabel = nullptr;\n\tSlider* exposureSlider = nullptr;\n\tLabel* exposureValueLabel = nullptr;\n\tCheckBox* hdrCheckBox = nullptr;\n\n\tLabel* sunLabel = nullptr;\n\tButton* sunColorButton = nullptr;\n\tDirectionEditor* sunDirectionEditor = nullptr;\n\n\tEnvironmentFrame(double x, double y) : Frame(x, y, \"Environment\") {\n\t\t// frame = new Frame(x, y, \"Environment\");\n\n\t\tinit();\n\n\t\tadd(hdrCheckBox, Align::FILL);\n\t\tadd(gammaLabel, Align::CENTER);\n\t\tadd(gammaSlider, Align::RELATIVE);\n\t\tadd(gammaValueLabel, Align::FILL);\n\t\tadd(exposureLabel, Align::CENTER);\n\t\tadd(exposureSlider, Align::RELATIVE);\n\t\tadd(exposureValueLabel, Align::FILL);\n\t\tadd(sunLabel, Align::CENTER);\n\t\tadd(sunColorButton, Align::CENTER);\n\t\tadd(sunDirectionEditor, Align::CENTER);\n\n\t\tGUI::add(this);\n\t}\n\n\tvoid init() override {\n\t\thdrCheckBox = new CheckBox(\"HDR\", 0, 0, true);\n\t\thdrCheckBox->checked = true;\n\t\thdrCheckBox->action = [] (CheckBox* c) {\n\t\t\tApplicationShaders::basicShader.updateHDR(c->checked);\n\t\t};\n\n\t\tgammaLabel = new Label(\"Gamma\", 0, 0);\n\t\tgammaSlider = new Slider(0, 0, 0, 3, 1);\n\t\tgammaSlider->action = [] (Slider* s) {\n\t\t\tApplicationShaders::basicShader.updateGamma(float(s->value));\n\t\t};\n\t\tgammaValueLabel = new Label(\"\", 0, 0);\n\n\t\texposureLabel = new Label(\"Exposure\", 0, 0);\n\t\texposureSlider = new Slider(0, 0, 0, 2, 1);\n\t\texposureSlider->action = [] (Slider* s) {\n\t\t\tApplicationShaders::basicShader.updateExposure(float(s->value));\n\t\t};\n\t\texposureValueLabel = new Label(\"\", 0, 0);\n\n\t\tsunLabel = new Label(\"Sun\", 0, 0);\n\t\tsunColorButton = new Button(0, 0, GUI::sliderBarWidth, GUI::sliderHandleHeight, false);\n\t\tsunDirectionEditor = new DirectionEditor(0, 0, GUI::sliderBarWidth, GUI::sliderBarWidth);\n\t\tsunDirectionEditor->action = [] (DirectionEditor* d) {\n\t\t\tApplicationShaders::basicShader.updateSunDirection(Vec3f(d->modelMatrix * Vec4f(0, 1, 0, 1)));\n\t\t};\n\n\t\tsunColorButton->setColor(Color(1));\n\t\tsunColorButton->action = [] (Button* button) {\n\t\t\tEnvironmentFrame* environmentFrame = static_cast<EnvironmentFrame*>(button->parent);\n\n\t\t\tGUI::colorPickerFrame->visible = true;\n\t\t\tGUI::colorPickerFrame->anchor = environmentFrame;\n\t\t\tGUI::select(GUI::colorPickerFrame);\n\n\t\t\tGUI::colorPicker->setRgba(button->idleColor);\n\t\t\tGUI::colorPicker->focus = button;\n\t\t\tGUI::colorPicker->action = [] (ColorPicker* p) {\n\t\t\t\tApplicationShaders::basicShader.updateSunColor(Vec3(p->getRgba()));\n\t\t\t};\n\t\t};\n\t}\n\n\tvoid update() override {\n\t\tif (!visible)\n\t\t\treturn;\n\n\t\tif (hdrCheckBox->checked) {\n\t\t\texposureSlider->enable();\n\t\t\texposureValueLabel->enable();\n\t\t\texposureLabel->enable();\n\t\t\texposureValueLabel->text = std::to_string(exposureSlider->value);\n\t\t} else {\n\t\t\texposureSlider->disable();\n\t\t\texposureValueLabel->disable();\n\t\t\texposureLabel->disable();\n\t\t}\n\n\t\tif (GUI::colorPicker->focus == sunColorButton) {\n\t\t\tsunColorButton->setColor(GUI::colorPicker->getRgba());\n\t\t}\n\n\t\tgammaValueLabel->text = std::to_string(gammaSlider->value);\n\t}\n};\n\n\n// Debug frame\n\nstruct DebugFrame : public FrameBlueprint, public Frame {\n\n\tLabel* vectorLabel = nullptr;\n\tCheckBox* infoVectorCheckBox = nullptr;\n\tCheckBox* positionCheckBox = nullptr;\n\tCheckBox* velocityCheckBox = nullptr;\n\tCheckBox* momentCheckBox = nullptr;\n\tCheckBox* forceCheckBox = nullptr;\n\tCheckBox* accelerationCheckBox = nullptr;\n\tCheckBox* angularImpulseCheckBox = nullptr;\n\tCheckBox* impulseCheckBox = nullptr;\n\tCheckBox* angularVelocityCheckBox = nullptr;\n\tLabel* pointLabel = nullptr;\n\tCheckBox* infoPointCheckBox = nullptr;\n\tCheckBox* centerOfMassCheckBox = nullptr;\n\tCheckBox* intersectionCheckBox = nullptr;\n\tLabel* renderLabel = nullptr;\n\tCheckBox* renderPiesCheckBox = nullptr;\n\tCheckBox* renderSpheresCheckBox = nullptr;\n\n\tDebugFrame(double x, double y) : Frame(x, y, \"Debug\") {\n\n\t\tinit();\n\n\t\tadd(vectorLabel, Align::CENTER);\n\t\tadd(infoVectorCheckBox, Align::FILL);\n\t\tadd(positionCheckBox, Align::FILL);\n\t\tadd(velocityCheckBox, Align::FILL);\n\t\tadd(accelerationCheckBox, Align::FILL);\n\t\tadd(forceCheckBox, Align::FILL);\n\t\tadd(momentCheckBox, Align::FILL);\n\t\tadd(impulseCheckBox, Align::FILL);\n\t\tadd(angularVelocityCheckBox, Align::FILL);\n\t\tadd(angularImpulseCheckBox, Align::FILL);\n\t\tadd(pointLabel, Align::CENTER);\n\t\tadd(infoPointCheckBox, Align::FILL);\n\t\tadd(centerOfMassCheckBox, Align::FILL);\n\t\tadd(intersectionCheckBox, Align::FILL);\n\t\tadd(renderLabel, Align::CENTER);\n\t\tadd(renderPiesCheckBox, Align::FILL);\n\t\tadd(renderSpheresCheckBox, Align::FILL);\n\n\t\tGUI::add(this);\n\t}\n\n\tvoid init() override {\n\t\tvisible = false;\n\n\t\tvectorLabel = new Label(\"Vectors\", 0, 0);\n\t\tinfoVectorCheckBox = new CheckBox(\"Info\", 0, 0, true);\n\t\tpositionCheckBox = new CheckBox(\"Position\", 0, 0, true);\n\t\tvelocityCheckBox = new CheckBox(\"Velocity\", 0, 0, true);\n\t\taccelerationCheckBox = new CheckBox(\"Acceleration\", 0, 0, true);\n\t\tforceCheckBox = new CheckBox(\"Force\", 0, 0, true);\n\t\tmomentCheckBox = new CheckBox(\"Moment\", 0, 0, true);\n\t\timpulseCheckBox = new CheckBox(\"Impulse\", 0, 0, true);\n\t\tangularVelocityCheckBox = new CheckBox(\"Angular velocity\", 0, 0, true);\n\t\tangularImpulseCheckBox = new CheckBox(\"Angular impulse\", 0, 0, true);\n\t\tpointLabel = new Label(\"Points\", 0, 0);\n\t\tinfoPointCheckBox = new CheckBox(\"Info\", 0, 0, true);\n\t\tcenterOfMassCheckBox = new CheckBox(\"Center of mass\", 0, 0, true);\n\t\tintersectionCheckBox = new CheckBox(\"Intersections\", 0, 0, true);\n\t\trenderLabel = new Label(\"Render\", 0, 0);\n\t\trenderPiesCheckBox = new CheckBox(\"Statistics\", 0, 0, true);\n\t\trenderSpheresCheckBox = new CheckBox(\"Collision spheres\", 0, 0, true);\n\t\tinfoVectorCheckBox->action = [] (CheckBox* c) { toggleVectorType(Debug::INFO_VEC); };\n\t\tvelocityCheckBox->action = [] (CheckBox* c) { toggleVectorType(Debug::VELOCITY); };\n\t\taccelerationCheckBox->action = [] (CheckBox* c) { toggleVectorType(Debug::ACCELERATION); };\n\t\tforceCheckBox->action = [] (CheckBox* c) { toggleVectorType(Debug::FORCE); };\n\t\tangularImpulseCheckBox->action = [] (CheckBox* c) { toggleVectorType(Debug::ANGULAR_IMPULSE); };\n\t\tpositionCheckBox->action = [] (CheckBox* c) { toggleVectorType(Debug::POSITION); };\n\t\tmomentCheckBox->action = [] (CheckBox* c) { toggleVectorType(Debug::MOMENT); };\n\t\timpulseCheckBox->action = [] (CheckBox* c) { toggleVectorType(Debug::IMPULSE); };\n\t\tangularVelocityCheckBox->action = [] (CheckBox* c) { toggleVectorType(Debug::ANGULAR_VELOCITY); };\n\t\tinfoPointCheckBox->action = [] (CheckBox* c) { togglePointType(Debug::INFO_POINT); };\n\t\tcenterOfMassCheckBox->action = [] (CheckBox* c) { togglePointType(Debug::CENTER_OF_MASS); };\n\t\tintersectionCheckBox->action = [] (CheckBox* c) { togglePointType(Debug::INTERSECTION); };\n\t\trenderPiesCheckBox->action = [] (CheckBox* c) { Debug::renderPiesEnabled = !Debug::renderPiesEnabled; };\n\t\trenderSpheresCheckBox->action = [] (CheckBox* c) { Debug::colissionSpheresMode = static_cast<Debug::SphereColissionRenderMode>((static_cast<int>(Debug::colissionSpheresMode) + 1) % 3); };\n\t}\n\n\tvoid update() override {\n\t\tif (!visible)\n\t\t\treturn;\n\n\t\tinfoVectorCheckBox->checked = Debug::vectorDebugEnabled[Debug::INFO_VEC];\n\t\tpositionCheckBox->checked = Debug::vectorDebugEnabled[Debug::POSITION];\n\t\tvelocityCheckBox->checked = Debug::vectorDebugEnabled[Debug::VELOCITY];\n\t\tmomentCheckBox->checked = Debug::vectorDebugEnabled[Debug::MOMENT];\n\t\tforceCheckBox->checked = Debug::vectorDebugEnabled[Debug::FORCE];\n\t\taccelerationCheckBox->checked = Debug::vectorDebugEnabled[Debug::ACCELERATION];\n\t\tangularImpulseCheckBox->checked = Debug::vectorDebugEnabled[Debug::ANGULAR_IMPULSE];\n\t\timpulseCheckBox->checked = Debug::vectorDebugEnabled[Debug::IMPULSE];\n\t\tangularVelocityCheckBox->checked = Debug::vectorDebugEnabled[Debug::ANGULAR_VELOCITY];\n\t\tinfoPointCheckBox->checked = Debug::pointDebugEnabled[Debug::INFO_POINT];\n\t\tcenterOfMassCheckBox->checked = Debug::pointDebugEnabled[Debug::CENTER_OF_MASS];\n\t\tintersectionCheckBox->checked = Debug::pointDebugEnabled[Debug::INTERSECTION];\n\t\trenderPiesCheckBox->checked = Debug::renderPiesEnabled;\n\t\trenderSpheresCheckBox->checked = Debug::colissionSpheresMode != Debug::SphereColissionRenderMode::NONE;\n\t}\n\n};\n\n\n// Properties frame\n\nstruct PropertiesFrame : public FrameBlueprint, public Frame {\n\n\tLabel* generalLabel = nullptr;\n\tLabel* partNameLabel = nullptr;\n\tLabel* partMeshIDLabel = nullptr;\n\n\tLabel* physicalLabel = nullptr;\n\tLabel* positionLabel = nullptr;\n\tLabel* velocityLabel = nullptr;\n\tLabel* angularVelocityLabel = nullptr;\n\tLabel* kineticEnergyLabel = nullptr;\n\tLabel* potentialEnergyLabel = nullptr;\n\tLabel* energyLabel = nullptr;\n\tLabel* massLabel = nullptr;\n\tLabel* inertiaLabel = nullptr;\n\tLabel* frictionLabel = nullptr;\n\tLabel* bouncynessLabel = nullptr;\n\tLabel* densityLabel = nullptr;\n\tLabel* conveyorEffectLabel = nullptr;\n\n\tLabel* materialLabel = nullptr;\n\tButton* ambientColorButton = nullptr;\n\tButton* diffuseColorButton = nullptr;\n\tButton* specularColorButton = nullptr;\n\tSlider* reflectanceSlider = nullptr;\n\tCheckBox* renderModeCheckBox = nullptr;\n\n\tPropertiesFrame(double x, double y) : Frame(x, y, \"Properties\") {\n\t\tinit();\n\n\t\tadd(generalLabel, Align::CENTER);\n\t\tadd(partNameLabel, Align::FILL);\n\t\tadd(partMeshIDLabel, Align::FILL);\n\n\t\tadd(physicalLabel, Align::CENTER);\n\t\tadd(positionLabel, Align::FILL);\n\t\tadd(velocityLabel, Align::FILL);\n\t\tadd(angularVelocityLabel, Align::FILL);\n\t\tadd(kineticEnergyLabel, Align::FILL);\n\t\tadd(potentialEnergyLabel, Align::FILL);\n\t\tadd(energyLabel, Align::FILL);\n\t\tadd(massLabel, Align::FILL);\n\t\tadd(inertiaLabel, Align::FILL);\n\t\tadd(frictionLabel, Align::FILL);\n\t\tadd(bouncynessLabel, Align::FILL);\n\t\tadd(densityLabel, Align::FILL);\n\t\tadd(conveyorEffectLabel, Align::FILL);\n\n\t\tadd(materialLabel, Align::CENTER);\n\t\tadd(ambientColorButton, Align::FILL);\n\t\tadd(diffuseColorButton, Align::FILL);\n\t\tadd(specularColorButton, Align::FILL);\n\t\tadd(reflectanceSlider, Align::FILL);\n\t\tadd(renderModeCheckBox, Align::FILL);\n\n\t\tGUI::add(this);\n\t}\n\n\tvoid init() override {\n\t\tgeneralLabel = new Label(\"General\", 0, 0);\n\t\tpartNameLabel = new Label(\"\", 0, 0);\n\t\tpartMeshIDLabel = new Label(\"\", 0, 0);\n\n\t\tphysicalLabel = new Label(\"Physical\", 0, 0);\n\t\tpositionLabel = new Label(\"\", 0, 0);\n\t\tvelocityLabel = new Label(\"\", 0, 0);\n\t\tangularVelocityLabel = new Label(\"\", 0, 0);\n\t\tkineticEnergyLabel = new Label(\"\", 0, 0);\n\t\tpotentialEnergyLabel = new Label(\"\", 0, 0);\n\t\tenergyLabel = new Label(\"\", 0, 0);\n\t\tmassLabel = new Label(\"\", 0, 0);\n\t\tinertiaLabel = new Label(\"\", 0, 0);\n\t\tfrictionLabel = new Label(\"\", 0, 0);\n\t\tbouncynessLabel = new Label(\"\", 0, 0);\n\t\tdensityLabel = new Label(\"\", 0, 0);\n\t\tconveyorEffectLabel = new Label(\"\", 0, 0);\n\n\t\tmaterialLabel = new Label(\"Material\", 0, 0);\n\t\trenderModeCheckBox = new CheckBox(\"Wireframe\", 0, 0, true);\n\t\trenderModeCheckBox->action = [] (CheckBox* c) {\n\t\t\tif (screen.selectedPart) {\n\t\t\t\tif (screen.selectedPart->renderMode == Renderer::FILL) {\n\t\t\t\t\tscreen.selectedPart->renderMode = Renderer::WIREFRAME;\n\t\t\t\t} else {\n\t\t\t\t\tscreen.selectedPart->renderMode = Renderer::FILL;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tambientColorButton = new Button(0, 0, GUI::sliderBarWidth, GUI::sliderHandleHeight, false);\n\t\tambientColorButton->action = [] (Button* button) {\n\t\t\tPropertiesFrame* propertiesFrame = static_cast<PropertiesFrame*>(button->parent);\n\n\t\t\tif (screen.selectedPart) {\n\t\t\t\tGUI::colorPicker->focus = button;\n\t\t\t\tGUI::select(GUI::colorPickerFrame);\n\t\t\t\tGUI::colorPickerFrame->visible = true;\n\t\t\t\tGUI::colorPickerFrame->anchor = propertiesFrame;\n\t\t\t\tGUI::colorPicker->action = [] (ColorPicker* colorPicker) {\n\t\t\t\t\tscreen.selectedPart->material.ambient = colorPicker->getRgba();\n\t\t\t\t};\n\n\t\t\t}\n\t\t};\n\n\t\tdiffuseColorButton = new Button(0, 0, GUI::sliderBarWidth, GUI::sliderHandleHeight, false);\n\t\tdiffuseColorButton->action = [] (Button* button) {\n\t\t\tPropertiesFrame* propertiesFrame = static_cast<PropertiesFrame*>(button->parent);\n\t\t\tif (screen.selectedPart) {\n\t\t\t\tGUI::colorPicker->focus = button;\n\t\t\t\tGUI::select(GUI::colorPickerFrame);\n\t\t\t\tGUI::colorPickerFrame->visible = true;\n\t\t\t\tGUI::colorPickerFrame->anchor = propertiesFrame;\n\t\t\t\tGUI::colorPicker->action = [] (ColorPicker* colorPicker) {\n\t\t\t\t\tscreen.selectedPart->material.diffuse = Vec3(colorPicker->getRgba());\n\t\t\t\t};\n\t\t\t}\n\t\t};\n\n\t\tspecularColorButton = new Button(0, 0, GUI::sliderBarWidth, GUI::sliderHandleHeight, false);\n\t\tspecularColorButton->action = [] (Button* button) {\n\t\t\tPropertiesFrame* propertiesFrame = static_cast<PropertiesFrame*>(button->parent);\n\t\t\tif (screen.selectedPart) {\n\t\t\t\tGUI::colorPicker->focus = button;\n\t\t\t\tGUI::select(GUI::colorPickerFrame);\n\t\t\t\tGUI::colorPickerFrame->visible = true;\n\t\t\t\tGUI::colorPickerFrame->anchor = propertiesFrame;\n\t\t\t\tGUI::colorPicker->action = [] (ColorPicker* colorPicker) {\n\t\t\t\t\tscreen.selectedPart->material.specular = Vec3(colorPicker->getRgba());\n\t\t\t\t};\n\t\t\t}\n\t\t};\n\n\t\treflectanceSlider = new Slider(0, 0, 0, 5, 1);\n\t\treflectanceSlider->action = [] (Slider* slider) {\n\t\t\tif (screen.selectedPart) {\n\t\t\t\tscreen.selectedPart->material.reflectance = static_cast<float>(slider->value);\n\t\t\t}\n\t\t};\n\t}\n\n\tvoid update() override {\n\t\tif (!visible)\n\t\t\treturn;\n\n\t\tExtendedPart* selectedPart = screen.selectedPart;\n\t\tPlayerWorld* world = screen.world;\n\n\t\tif (selectedPart) {\n\t\t\tpartMeshIDLabel->text = \"MeshID: \" + str(selectedPart->visualData.drawMeshId);\n\n\t\t\tpositionLabel->text = \"Position: \" + str(selectedPart->getCFrame().position);\n\t\t\tpartNameLabel->text = \"Name: \" + selectedPart->name;\n\t\t\tvelocityLabel->text = \"Velocity: \" + str(selectedPart->getMotion().velocity);\n\t\t\tangularVelocityLabel->text = \"Angular Velocity: \" + str(selectedPart->getMotion().angularVelocity);\n\t\t\tdouble kineticEnergy = selectedPart->parent->getKineticEnergy();\n\t\t\tdouble potentialEnergy = world->getPotentialEnergyOfPhysical(*selectedPart->parent->mainPhysical);\n\t\t\tkineticEnergyLabel->text = \"Kinetic Energy: \" + str(kineticEnergy);\n\t\t\tpotentialEnergyLabel->text = \"Potential Energy: \" + str(potentialEnergy);\n\t\t\tenergyLabel->text = \"Energy: \" + str(kineticEnergy + potentialEnergy);\n\t\t\tmassLabel->text = \"Mass: \" + str(selectedPart->getMass());\n\t\t\tinertiaLabel->text = \"Inertia: \" + str(Mat3(selectedPart->getInertia()));\n\t\t\tfrictionLabel->text = \"Friction: \" + str(selectedPart->properties.friction);\n\t\t\tbouncynessLabel->text = \"Bouncyness: \" + str(selectedPart->properties.bouncyness);\n\t\t\tdensityLabel->text = \"Density: \" + str(selectedPart->properties.density);\n\t\t\tconveyorEffectLabel->text = \"ConveyorEffect: \" + str(selectedPart->properties.conveyorEffect);\n\n\t\t\trenderModeCheckBox->checked = selectedPart->renderMode == Renderer::WIREFRAME;\n\n\t\t\tambientColorButton->disabled = false;\n\t\t\tambientColorButton->setColor(selectedPart->material.ambient);\n\t\t\tif (GUI::colorPicker->focus == ambientColorButton) {\n\t\t\t\tGUI::colorPicker->setRgba(selectedPart->material.ambient);\n\t\t\t}\n\n\t\t\tdiffuseColorButton->disabled = false;\n\t\t\tdiffuseColorButton->setColor(Vec4(selectedPart->material.diffuse, 1));\n\t\t\tif (GUI::colorPicker->focus == diffuseColorButton) {\n\t\t\t\tGUI::colorPicker->setRgba(Vec4(selectedPart->material.diffuse, 1));\n\t\t\t}\n\n\t\t\tspecularColorButton->disabled = false;\n\t\t\tspecularColorButton->setColor(Vec4(selectedPart->material.specular, 1));\n\t\t\tif (GUI::colorPicker->focus == specularColorButton) {\n\t\t\t\tGUI::colorPicker->setRgba(Vec4(selectedPart->material.specular, 1));\n\t\t\t}\n\n\t\t\treflectanceSlider->disabled = false;\n\t\t\treflectanceSlider->value = selectedPart->material.reflectance;\n\t\t} else {\n\t\t\tpartMeshIDLabel->text = \"MeshID: -\";\n\n\t\t\tpositionLabel->text = \"Position: -\";\n\t\t\tpartNameLabel->text = \"Name: -\";\n\t\t\tvelocityLabel->text = \"Velocity: -\";\n\t\t\tangularVelocityLabel->text = \"Angular Velocity: -\";\n\t\t\tkineticEnergyLabel->text = \"Kinetic Energy: -\";\n\t\t\tpotentialEnergyLabel->text = \"Potential Energy: -\";\n\t\t\tenergyLabel->text = \"Energy: -\";\n\t\t\tmassLabel->text = \"Mass: -\";\n\t\t\tinertiaLabel->text = \"Inertia: -\";\n\t\t\tfrictionLabel->text = \"Friction: -\";\n\t\t\tbouncynessLabel->text = \"Bouncyness: -\";\n\t\t\tdensityLabel->text = \"Density: -\";\n\t\t\tconveyorEffectLabel->text = \"ConveyorEffect: -\";\n\n\t\t\tambientColorButton->disabled = true;\n\t\t\tambientColorButton->setColor(Color(1));\n\n\t\t\tdiffuseColorButton->disabled = true;\n\t\t\tdiffuseColorButton->setColor(Color(1));\n\n\t\t\tspecularColorButton->disabled = true;\n\t\t\tspecularColorButton->setColor(Color(1));\n\n\t\t\treflectanceSlider->disabled = true;\n\t\t\treflectanceSlider->value = (reflectanceSlider->max + reflectanceSlider->min) / 2;\n\n\t\t\trenderModeCheckBox->checked = false;\n\t\t}\n\t}\n};\n\n};"
  },
  {
    "path": "application/math.natvis",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?> \n<AutoVisualizer xmlns=\"http://schemas.microsoft.com/vstudio/debugger/natvis/2010\">\n  <Type Name=\"Vector&lt;*,2&gt;\">\n    <DisplayString>{{{x, g}, {y, g}}}</DisplayString>\n  </Type>\n  <Type Name=\"Vector&lt;*,3&gt;\">\n    <DisplayString>{{{x, g}, {y, g}, {z, g}}}</DisplayString>\n  </Type>\n  <Type Name=\"Vector&lt;*,4&gt;\">\n    <DisplayString>{{{x, g}, {y, g}, {z, g}, {w, g}}}</DisplayString>\n  </Type>\n  <Type Name=\"Matrix&lt;*,2,2&gt;\">\n    <Expand>\n      <Synthetic Name=\"Row 1\"><DisplayString>{data[0],g}, {data[2],g}</DisplayString></Synthetic>\n      <Synthetic Name=\"Row 2\"><DisplayString>{data[1],g}, {data[3],g}</DisplayString></Synthetic>\n    </Expand>\n  </Type>\n  <Type Name=\"Matrix&lt;*,3,3&gt;\">\n    <Expand>\n      <Synthetic Name=\"Row 1\"><DisplayString>{data[0],g}, {data[3],g}, {data[6],g}</DisplayString></Synthetic>\n      <Synthetic Name=\"Row 2\"><DisplayString>{data[1],g}, {data[4],g}, {data[7],g}</DisplayString></Synthetic>\n      <Synthetic Name=\"Row 3\"><DisplayString>{data[2],g}, {data[5],g}, {data[8],g}</DisplayString></Synthetic>\n    </Expand>\n  </Type>\n  <Type Name=\"Matrix&lt;*,4,4&gt;\">\n    <Expand>\n      <Synthetic Name=\"Row 1\"><DisplayString>{data[0],g}, {data[4],g}, {data[8],g}, {data[12],g}</DisplayString></Synthetic>\n      <Synthetic Name=\"Row 2\"><DisplayString>{data[1],g}, {data[5],g}, {data[9],g}, {data[13],g}</DisplayString></Synthetic>\n      <Synthetic Name=\"Row 3\"><DisplayString>{data[2],g}, {data[6],g}, {data[10],g}, {data[14],g}</DisplayString></Synthetic>\n      <Synthetic Name=\"Row 3\"><DisplayString>{data[3],g}, {data[7],g}, {data[11],g}, {data[15],g}</DisplayString></Synthetic>\n    </Expand>\n  </Type>\n  <!--<Type Name=\"Matrix&lt;*,3,3&gt;\">\n    <Expand>\n      <Item Name=\"Row 1\">{{data[0], g}, {data[3], g}, {data[6], g}}</Item>\n      <Item Name=\"Row 2\">{{data[1], g}, {data[4], g}, {data[7], g}}</Item>\n      <Item Name=\"Row 2\">{{data[2], g}, {data[5], g}, {data[8], g}}</Item>\n    </Expand>\n  </Type>-->\n  \n  <Type Name=\"Position\">\n    <DisplayString>{{{x, g}, {y, g}, {z, g}}}</DisplayString>\n  </Type>\n\n  <Type Name=\"LargeMatrix&lt;*&gt;\">\n    <DisplayString>Width = {width}, Height = {height}</DisplayString>\n    <Expand>\n      <Item Name=\"width\">width</Item>\n      <Item Name=\"height\">height</Item>\n      <ArrayItems>\n        <Size>width * height</Size>\n        <ValuePointer>data</ValuePointer>\n      </ArrayItems>\n    </Expand>\n  </Type>\n  <Type Name=\"LargeVector&lt;*&gt;\">\n    <DisplayString>Size = {size}</DisplayString>\n    <Expand>\n      <Item Name=\"size\">size</Item>\n      <ArrayItems>\n        <Size>size</Size>\n        <ValuePointer>data</ValuePointer>\n      </ArrayItems>\n    </Expand>\n  </Type>\n</AutoVisualizer>\n"
  },
  {
    "path": "application/picker/ray.cpp",
    "content": "#include \"core.h\"\n\n#include \"ray.h\"\n#include \"view/screen.h\"\n\nnamespace P3D::Application {\n\nVec2f getNormalizedDeviceSpacePosition(const Vec2f& viewportSpacePosition, const Vec2f& screenSize) {\n\tfloat x = 2 * viewportSpacePosition.x / screenSize.x - 1;\n\tfloat y = 2 * viewportSpacePosition.y / screenSize.y - 1;\n\treturn Vec2f(x, -y);\n}\n\nVec3f calcRay(const Screen& screen, Vec2f mouse) {\n\tVec2f normalizedDeviceSpacePosition = getNormalizedDeviceSpacePosition(mouse, screen.dimension);\n\tVec4f clipSpacePosition = Vec4f(normalizedDeviceSpacePosition.x, normalizedDeviceSpacePosition.y, -1.0f, 1.0f);\n\tVec4f eyeCoordinates = screen.camera.invertedProjectionMatrix * clipSpacePosition;\n\teyeCoordinates = Vec4f(eyeCoordinates.x, eyeCoordinates.y, -1.0f, 0.0f);\n\tVec4f rayWorld = screen.camera.invertedViewMatrix * eyeCoordinates;\n\tVec3f rayDirection = normalize(Vec3f(rayWorld.x, rayWorld.y, rayWorld.z));\n\n\treturn rayDirection;\n}\n\nRay getMouseRay(const Screen& screen, const Vec2f& mouse) {\n\tPosition start = screen.camera.cframe.getPosition();\n\tVec3f direction = calcRay(screen, mouse);\n\n\treturn Ray { start, Vec3(direction) };\n}\n\n};"
  },
  {
    "path": "application/picker/ray.h",
    "content": "#pragma once\n\n#include <Physics3D/math/ray.h>\n\nnamespace P3D::Application {\n\nclass Screen;\n\nRay getMouseRay(const Screen& screen, const Vec2f& mouse);\n\n};"
  },
  {
    "path": "application/picker/selection.cpp",
    "content": "#include \"core.h\"\n\n#include \"selection.h\"\n#include \"application.h\"\n#include \"view/screen.h\"\n#include \"ecs/components.h\"\n\nnamespace P3D::Application {\n\n\tvoid Selection::recalculateSelection() {\n\t\tthis->boundingBox = std::nullopt;\n\t\tfor (auto entity : this->selection)\n\t\t\texpandSelection(entity);\n\t}\n\n\tvoid Selection::expandSelection(const Engine::Registry64::entity_type& entity) {\n\t\tIRef<Comp::Transform> transform = screen.registry.get<Comp::Transform>(entity);\n\t\tif (transform.invalid())\n\t\t\treturn;\n\n\t\tIRef<Comp::Hitbox> hitbox = screen.registry.get<Comp::Hitbox>(entity);\n\t\t\n\t\tif (selection.empty() || !this->boundingBox.has_value()) {\n\t\t\tif (hitbox.valid())\n\t\t\t\tthis->boundingBox = hitbox->getShape().getBounds();\n\t\t\telse\n\t\t\t\tthis->boundingBox = BoundingBox(0.2, 0.2, .2);\n\t\t} else {\n\t\t\tIRef<Comp::Transform> referenceTransform = screen.registry.get<Comp::Transform>(selection[0]);\n\t\t\tGlobalCFrame referenceFrame = referenceTransform->getCFrame();\n\t\t\tCFrame relativeFrame = referenceFrame.globalToLocal(transform->getCFrame());\n\n\t\t\tif (hitbox.valid()) {\n\t\t\t\tBoundingBox rotatedBounds = hitbox->getShape().getBounds(relativeFrame.getRotation());\n\t\t\t\tthis->boundingBox = this->boundingBox->expanded(relativeFrame.getPosition() + rotatedBounds.min).expanded(relativeFrame.getPosition() + rotatedBounds.max);\n\t\t\t} else {\n\t\t\t\tthis->boundingBox = this->boundingBox->expanded(boxShape(0.2, 0.2, 0.2).getBounds(relativeFrame.getRotation()));\n\t\t\t}\n\t\t}\n\t}\n\n\tbool Selection::empty() const {\n\t\treturn this->selection.empty();\n\t}\n\n\tstd::size_t Selection::size() const {\n\t\treturn this->selection.size();\n\t}\n\n\tbool Selection::contains(const Engine::Registry64::entity_type& entity) const {\n\t\tfor(const Engine::Registry64::entity_type& found : selection)\n\t\t\tif(found == entity)\n\t\t\t\treturn true;\n\n\t\treturn false;\n\t}\n\n\tbool Selection::isMultiSelection() const {\n\t\treturn size() > 1;\n\t}\n\n\tbool Selection::isSingleSelection() const {\n\t\treturn size() == 1;\n\t}\n\n\tEngine::Registry64::entity_type& Selection::operator[](int index) {\n\t\treturn this->selection[index];\n\t}\n\n\tvoid Selection::add(const Selection& other, bool recalculateBounds) {\n\t\tfor (const Engine::Registry64::entity_type& entity : other) \n\t\t\tthis->add(entity, recalculateBounds);\n\t}\n\n\tvoid Selection::remove(const Selection& other, bool recalculateBounds) {\n\t\tfor (const Engine::Registry64::entity_type& entity : other)\n\t\t\tthis->remove(entity, false);\n\n\t\tif (recalculateBounds) {\n\t\t\tthis->boundingBox = std::nullopt;\n\t\t\tfor (const Engine::Registry64::entity_type entity : *this)\n\t\t\t\texpandSelection(entity);\n\t\t}\n\t}\n\n\tvoid Selection::add(const Engine::Registry64::entity_type& entity, bool recalculateBounds) {\n\t\tauto iterator = std::find(this->selection.begin(), this->selection.end(), entity);\n\n\t\tif (iterator != this->selection.end())\n\t\t\treturn;\n\t\t\n\t\tthis->selection.push_back(entity);\n\n\t\tif (recalculateBounds) \n\t\t\texpandSelection(entity);\n\t\t\n\t}\n\n\tvoid Selection::remove(const Engine::Registry64::entity_type& entity, bool recalculateBounds) {\n\t\tif (entity == Engine::Registry64::null_entity)\n\t\t\treturn;\n\n\t\tauto iterator = std::find(this->selection.begin(), this->selection.end(), entity);\n\t\tif (iterator == this->selection.end())\n\t\t\treturn;\n\t\t\n\t\tthis->selection.erase(iterator);\n\n\t\tif (recalculateBounds) {\n\t\t\tthis->boundingBox = std::nullopt;\n\t\t\tfor (const Engine::Registry64::entity_type entity : *this) \n\t\t\t\texpandSelection(entity);\n\t\t}\n\t}\n\n\tvoid Selection::toggle(const Engine::Registry64::entity_type& entity, bool recalculateBounds) {\n\t\tauto iterator = std::find(this->selection.begin(), this->selection.end(), entity);\n\t\t\n\t\tif (iterator == selection.end())\n\t\t\tadd(entity, recalculateBounds);\n\t\telse\n\t\t\tremove(entity, recalculateBounds);\n\t}\n\n\tvoid Selection::clear() {\n\t\tthis->selection.clear();\n\t\tthis->boundingBox = std::nullopt;\n\t}\n\n\tvoid Selection::translate(const Vec3& translation) {\n\t\tfor (auto entity : this->selection) {\n\t\t\tIRef<Comp::Transform> transform = screen.registry.get<Comp::Transform>(entity);\n\t\t\tif (transform.valid())\n\t\t\t\ttransform->translate(translation);\n\t\t}\n\t}\n\n\tvoid Selection::rotate(const Vec3& normal, double angle) {\n\t\tstd::optional<GlobalCFrame> reference = getCFrame();\n\t\tif (!reference.has_value())\n\t\t\treturn;\n\t\t\n\t\tRotation rotation = Rotation::fromRotationVector(angle * normal);\n\t\tfor (auto entity : this->selection) {\n\t\t\tIRef<Comp::Transform> transform = screen.registry.get<Comp::Transform>(entity);\n\t\t\t\n\t\t\tif (transform.valid()) {\n\t\t\t\t//transform->rotate(normal, angle);\n\t\t\t\ttransform->rotate(rotation);\n\t\t\t\tVec3 delta = transform->getPosition() - reference->getPosition();\n\t\t\t\tVec3 translation = rotation * delta - delta;\n\t\t\t\ttransform->translate(translation);\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid Selection::scale(const Vec3& scale) {\n\t\tstd::optional<GlobalCFrame> reference = getCFrame();\n\t\tif (!reference.has_value())\n\t\t\treturn;\n\n\t\tfor (auto entity : this->selection) {\n\t\t\tIRef<Comp::Transform> transform = screen.registry.get<Comp::Transform>(entity);\n\t\t\tVec3 delta = transform->getPosition() - reference->getPosition();\n\t\t\tVec3 translation = elementWiseMul(delta, scale - Vec3(1.0, 1.0, 1.0));\n\t\t\ttransform->translate(translation);\n\t\t\ttransform->scale(scale.x, scale.y, scale.z);\n\t\t}\n\n\t\trecalculateSelection();\n\t}\n\n\tstd::optional<Shape> Selection::getHitbox() const {\n\t\tif (this->selection.empty())\n\t\t\treturn std::nullopt;\n\n\t\tif (this->size() == 1) {\n\t\t\tIRef<Comp::Hitbox> hitbox = screen.registry.get<Comp::Hitbox>(this->selection[0]);\n\t\t\tif (hitbox.invalid())\n\t\t\t\treturn std::nullopt;\n\n\t\t\treturn hitbox->getShape();\n\t\t}\n\n\t\treturn boxShape(boundingBox->getWidth(), boundingBox->getHeight(), boundingBox->getDepth());\n\t}\n\n\tstd::optional<GlobalCFrame> Selection::getCFrame() const {\n\t\tif (this->selection.empty())\n\t\t\treturn std::nullopt;\n\n\t\tIRef<Comp::Transform> transform = screen.registry.get<Comp::Transform>(this->selection[0]);\n\t\tif (transform.invalid())\n\t\t\treturn std::nullopt;\n\n\t\treturn GlobalCFrame(transform->getCFrame().localToGlobal(this->boundingBox->getCenter()), transform->getRotation());\n\t}\n\t\n\tstd::vector<Engine::Registry64::entity_type>::const_iterator Selection::begin() const {\n\t\treturn this->selection.begin();\n\t}\n\t\n\tstd::vector<Engine::Registry64::entity_type>::const_iterator Selection::end() const {\n\t\treturn this->selection.end();\n\t}\n\t\n\tstd::vector<Engine::Registry64::entity_type>::iterator Selection::begin() {\n\t\treturn this->selection.begin();\n\t}\n\t\n\tstd::vector<Engine::Registry64::entity_type>::iterator Selection::end() {\n\t\treturn this->selection.end();\n\t}\n\n\tstd::optional<Engine::Registry64::entity_type> Selection::first() const {\n\t\tif (selection.empty())\n\t\t\treturn std::nullopt;\n\n\t\treturn selection[0];\n\t}\n\tstd::optional<Engine::Registry64::entity_type> Selection::last() const {\n\t\tif (selection.empty())\n\t\t\treturn std::nullopt;\n\n\t\treturn selection[selection.size() - 1];\n\t}\n\n\n}\n"
  },
  {
    "path": "application/picker/selection.h",
    "content": "#pragma once\n\n#include \"../engine/ecs/registry.h\"\n#include \"../application/ecs/components.h\"\n\n#include <optional>\n\nnamespace P3D::Application {\n\n\tstruct Selection {\n\tprivate:\n\t\t// A bounding box in the cframe of the first entity in the selection\n\t\tstd::optional<BoundingBox> boundingBox;\n\t\tstd::vector<Engine::Registry64::entity_type> selection;\n\n\t\tvoid expandSelection(const Engine::Registry64::entity_type& entity);\n\t\t\n\tpublic:\n\t\t[[nodiscard]] bool empty() const;\n\t\t[[nodiscard]] std::size_t size() const;\n\t\t[[nodiscard]] bool contains(const Engine::Registry64::entity_type& entity) const;\n\t\t[[nodiscard]] bool isMultiSelection() const;\n\t\t[[nodiscard]] bool isSingleSelection() const;\n\t\t[[nodiscard]] Engine::Registry64::entity_type& operator[](int index);\n\t\t\n\t\tvoid add(const Selection& other, bool recalculateBounds = true);\n\t\tvoid add(const Engine::Registry64::entity_type& entity, bool recalculateBounds = true);\n\t\tvoid remove(const Selection& other, bool recalculateBounds = true);\n\t\tvoid remove(const Engine::Registry64::entity_type& entity, bool recalculateBounds = true);\n\t\tvoid toggle(const Engine::Registry64::entity_type& entity, bool recalculateBounds = true);\n\t\tvoid clear();\n\n\t\tvoid translate(const Vec3& translation);\n\t\tvoid rotate(const Vec3& normal, double angle);\n\t\tvoid scale(const Vec3& scale);\n\t\t\n\t\tvoid recalculateSelection();\n\t\t\n\t\t[[nodiscard]] std::optional<GlobalCFrame> getCFrame() const;\n\t\t[[nodiscard]] std::optional<Shape> getHitbox() const;\n\n\t\t[[nodiscard]] std::vector<Engine::Registry64::entity_type>::const_iterator begin() const;\n\t\t[[nodiscard]] std::vector<Engine::Registry64::entity_type>::const_iterator end() const;\n\t\t[[nodiscard]] std::vector<Engine::Registry64::entity_type>::iterator begin();\n\t\t[[nodiscard]] std::vector<Engine::Registry64::entity_type>::iterator end();\n\t\t[[nodiscard]] std::optional<Engine::Registry64::entity_type> first() const;\n\t\t[[nodiscard]] std::optional<Engine::Registry64::entity_type> last() const;\n\t};\n\t\n}\n"
  },
  {
    "path": "application/picker/tools/alignmentLinkTool.cpp",
    "content": "#include \"core.h\"\n#include \"alignmentLinkTool.h\"\n\n#include \"application.h\"\n#include \"selectionTool.h\"\n#include \"graphics/resource/textureResource.h\"\n#include \"util/resource/resourceManager.h\"\n#include \"view/screen.h\"\n\nnamespace P3D::Application {\n\nvoid AlignmentLinkTool::onRegister() {\n\tauto path = \"../res/textures/icons/\" + getName() + \".png\";\n\tResourceManager::add<Graphics::TextureResource>(getName(), path);\n}\n\nvoid AlignmentLinkTool::onDeregister() {\n\t// Remove texture\n}\n\nvoid AlignmentLinkTool::onSelect() {\n\tlinkSelection();\n}\n\nvoid AlignmentLinkTool::linkSelection() {\n\tif (SelectionTool::selection.size() < 2)\n\t\treturn;\n\n\tIRef<Comp::Collider> parentCollider = screen.registry.get<Comp::Collider>(SelectionTool::selection[0]);\n\tif (parentCollider.invalid())\n\t\treturn;\n\n\tfor (Engine::Registry64::entity_type& entity : SelectionTool::selection) {\n\t\tIRef<Comp::Collider> childCollider = screen.registry.get<Comp::Collider>(entity);\n\t\tif (childCollider.invalid())\n\t\t\tcontinue;\n\n\t\tif (childCollider->part == parentCollider->part)\n\t\t\tcontinue;\n\n\t\tCFrame cframe = parentCollider->part->getCFrame().globalToLocal(childCollider->part->getCFrame());\n\t\tAttachedPart partA { cframe, parentCollider->part };\n\t\tAttachedPart partB { CFrame(), childCollider->part };\n\t\tAlignmentLink* link = new AlignmentLink(partA, partB);\n\n\t\tscreen.worldMutex->lock();\n\t\ttry {\n\t\t\tworld.addLink(link);\n\t\t} catch (std::invalid_argument& error) {\n\t\t\tLog::debug(error.what());\n\t\t}\n\t\tscreen.worldMutex->unlock();\n\t}\n}\n\n}\n"
  },
  {
    "path": "application/picker/tools/alignmentLinkTool.h",
    "content": "#pragma once\n\n#include \"engine/tool/buttonTool.h\"\n#include \"graphics/glfwUtils.h\"\n\nnamespace P3D::Application {\n\nclass AlignmentLinkTool : public Engine::ButtonTool {\npublic:\n\tDEFINE_TOOL(\"Alignment Link\", \"Select two entities to create an alignment link beteen.\", Graphics::GLFW::Cursor::CROSSHAIR);\n\n\t~AlignmentLinkTool() override = default;\n\n\tvoid onRegister() override;\n\tvoid onDeregister() override;\n\tvoid onSelect() override;\n\n\tstatic void linkSelection();\n};\n\n}\n"
  },
  {
    "path": "application/picker/tools/attachmentTool.cpp",
    "content": "#include \"core.h\"\n#include \"attachmentTool.h\"\n\n#include \"application.h\"\n#include \"selectionTool.h\"\n#include \"graphics/resource/textureResource.h\"\n#include \"util/resource/resourceManager.h\"\n#include \"view/screen.h\"\n\nnamespace P3D::Application {\n\nvoid AttachmentTool::onRegister() {\n\tauto path = \"../res/textures/icons/\" + getName() + \".png\";\n\tResourceManager::add<Graphics::TextureResource>(getName(), path);\n}\n\nvoid AttachmentTool::onDeregister() {\n\t// Remove texture\n}\n\nvoid AttachmentTool::onSelect() {\n\tattachSelection();\n}\n\nvoid AttachmentTool::attachSelection() {\n\tif (SelectionTool::selection.size() < 2)\n\t\treturn;\n\t\n\tIRef<Comp::Collider> parentCollider = screen.registry.get<Comp::Collider>(SelectionTool::selection[0]);\n\tif (parentCollider.invalid())\n\t\treturn;\n\t\n\tfor (Engine::Registry64::entity_type& entity : SelectionTool::selection) {\n\t\tIRef<Comp::Collider> childCollider = screen.registry.get<Comp::Collider>(entity);\n\t\tif (childCollider.invalid())\n\t\t\tcontinue;\n\n\t\tif (childCollider->part == parentCollider->part)\n\t\t\tcontinue;\n\t\t\n\t\tCFrame cframe = parentCollider->part->getCFrame().globalToLocal(childCollider->part->getCFrame());\n\n\t\tscreen.worldMutex->lock();\n\t\ttry {\n\t\t\tparentCollider->part->attach(childCollider->part, cframe);\t\n\t\t} catch (std::invalid_argument& error) {\n\t\t\tLog::debug(error.what());\n\t\t}\n\t\tscreen.worldMutex->unlock();\n\t}\n}\n\n}\n"
  },
  {
    "path": "application/picker/tools/attachmentTool.h",
    "content": "#pragma once\n#include \"engine/tool/buttonTool.h\"\n#include \"graphics/glfwUtils.h\"\n\nnamespace P3D::Application {\n\nclass AttachmentTool : public Engine::ButtonTool {\npublic:\n\tDEFINE_TOOL(\"Attachment\", \"Select two entities to create an attachment beteen.\", Graphics::GLFW::Cursor::CROSSHAIR);\n\n\t~AttachmentTool() override = default;\n\n\tvoid onRegister() override;\n\tvoid onDeregister() override;\n\tvoid onSelect() override;\n\n\tstatic void attachSelection();\n};\n\t\n}\n"
  },
  {
    "path": "application/picker/tools/elasticLinkTool.cpp",
    "content": "#include \"core.h\"\n#include \"elasticLinkTool.h\"\n\n#include \"application.h\"\n#include \"selectionTool.h\"\n#include \"graphics/resource/textureResource.h\"\n#include \"Physics3D/softlinks/elasticLink.h\"\n#include \"util/resource/resourceManager.h\"\n#include \"view/screen.h\"\n\nnamespace P3D::Application {\n\nvoid ElasticLinkTool::onRegister() {\n\tauto path = \"../res/textures/icons/\" + getName() + \".png\";\n\tResourceManager::add<Graphics::TextureResource>(getName(), path);\n}\n\nvoid ElasticLinkTool::onDeregister() {\n\t// Remove texture\n}\n\nvoid ElasticLinkTool::onSelect() {\n\tlinkSelection();\n}\n\nvoid ElasticLinkTool::linkSelection() {\n\tif (SelectionTool::selection.size() < 2)\n\t\treturn;\n\n\tIRef<Comp::Collider> parentCollider = screen.registry.get<Comp::Collider>(SelectionTool::selection[0]);\n\tif (parentCollider.invalid())\n\t\treturn;\n\n\tfor (Engine::Registry64::entity_type& entity : SelectionTool::selection) {\n\t\tIRef<Comp::Collider> childCollider = screen.registry.get<Comp::Collider>(entity);\n\t\tif (childCollider.invalid())\n\t\t\tcontinue;\n\n\t\tif (childCollider->part == parentCollider->part)\n\t\t\tcontinue;\n\n\t\tCFrame cframe = parentCollider->part->getCFrame().globalToLocal(childCollider->part->getCFrame());\n\t\tAttachedPart part1 { cframe, parentCollider->part };\n\t\tAttachedPart part2 { CFrame(), childCollider->part };\n\t\tElasticLink* link = new ElasticLink(part1, part2, 5.0, 1.0);\n\n\t\tscreen.worldMutex->lock();\n\t\ttry {\n\t\t\tworld.addLink(link);\n\t\t} catch (std::invalid_argument& error) {\n\t\t\tLog::debug(error.what());\n\t\t}\n\t\tscreen.worldMutex->unlock();\n\t}\n}\n\n}\n"
  },
  {
    "path": "application/picker/tools/elasticLinkTool.h",
    "content": "#pragma once\n\n#include \"engine/tool/buttonTool.h\"\n#include \"graphics/glfwUtils.h\"\n\nnamespace P3D::Application {\n\nclass ElasticLinkTool : public Engine::ButtonTool {\npublic:\n\tDEFINE_TOOL(\"Elastic Link\", \"Select two entities to create an elastic link beteen.\", Graphics::GLFW::Cursor::CROSSHAIR);\n\n\t~ElasticLinkTool() override = default;\n\n\tvoid onRegister() override;\n\tvoid onDeregister() override;\n\tvoid onSelect() override;\n\n\tstatic void linkSelection();\n};\n\n}\n"
  },
  {
    "path": "application/picker/tools/fixedConstraintTool.cpp",
    "content": "#include \"core.h\"\n#include \"fixedConstraintTool.h\"\n\n#include \"application.h\"\n#include \"selectionTool.h\"\n#include \"graphics/resource/textureResource.h\"\n#include \"Physics3D/hardconstraints/fixedConstraint.h\"\n#include \"util/resource/resourceManager.h\"\n#include \"view/screen.h\"\n\nnamespace P3D::Application {\n\nvoid FixedConstraintTool::onRegister() {\n\tauto path = \"../res/textures/icons/\" + getName() + \".png\";\n\tResourceManager::add<Graphics::TextureResource>(getName(), path);\n}\n\nvoid FixedConstraintTool::onDeregister() {\n\t// Remove texture\n}\n\nvoid FixedConstraintTool::onSelect() {\n\tfixSelection();\n}\n\nvoid FixedConstraintTool::fixSelection() {\n\tif (SelectionTool::selection.size() < 2)\n\t\treturn;\n\n\tIRef<Comp::Collider> parentCollider = screen.registry.get<Comp::Collider>(SelectionTool::selection[0]);\n\tif (parentCollider.invalid())\n\t\treturn;\n\n\tfor (Engine::Registry64::entity_type& entity : SelectionTool::selection) {\n\t\tIRef<Comp::Collider> childCollider = screen.registry.get<Comp::Collider>(entity);\n\t\tif (childCollider.invalid())\n\t\t\tcontinue;\n\n\t\tif (childCollider->part == parentCollider->part)\n\t\t\tcontinue;\n\n\t\tCFrame cframe = parentCollider->part->getCFrame().globalToLocal(childCollider->part->getCFrame());\n\t\tFixedConstraint* constraint = new FixedConstraint();\n\n\t\tscreen.worldMutex->lock();\n\t\ttry {\n\t\t\tparentCollider->part->attach(childCollider->part, constraint, cframe, CFrame());\n\t\t} catch (std::invalid_argument& error) {\n\t\t\tLog::debug(error.what());\n\t\t}\n\t\tscreen.worldMutex->unlock();\n\t}\n}\n\n}\n"
  },
  {
    "path": "application/picker/tools/fixedConstraintTool.h",
    "content": "#pragma once\n\n#include \"engine/tool/buttonTool.h\"\n#include \"graphics/glfwUtils.h\"\n\nnamespace P3D::Application {\n\nclass FixedConstraintTool : public Engine::ButtonTool {\npublic:\n\tDEFINE_TOOL(\"Fixed Constraint\", \"Select two entities to create a fixed constraints beteen.\", Graphics::GLFW::Cursor::CROSSHAIR);\n\n\t~FixedConstraintTool() override = default;\n\n\tvoid onRegister() override;\n\tvoid onDeregister() override;\n\tvoid onSelect() override;\n\n\tstatic void fixSelection();\n};\n\n}\n"
  },
  {
    "path": "application/picker/tools/magneticLinkTool.cpp",
    "content": "#include \"core.h\"\n#include \"magneticLinkTool.h\"\n\n#include \"application.h\"\n#include \"selectionTool.h\"\n#include \"graphics/resource/textureResource.h\"\n#include \"Physics3D/softlinks/magneticLink.h\"\n#include \"util/resource/resourceManager.h\"\n#include \"view/screen.h\"\n\nnamespace P3D::Application {\n\nvoid MagneticLinkTool::onRegister() {\n\tauto path = \"../res/textures/icons/\" + getName() + \".png\";\n\tResourceManager::add<Graphics::TextureResource>(getName(), path);\n}\n\nvoid MagneticLinkTool::onDeregister() {\n\t// Remove texture\n}\n\nvoid MagneticLinkTool::onSelect() {\n\tlinkSelection();\n}\n\nvoid MagneticLinkTool::linkSelection() {\n\tif (SelectionTool::selection.size() < 2)\n\t\treturn;\n\n\tIRef<Comp::Collider> parentCollider = screen.registry.get<Comp::Collider>(SelectionTool::selection[0]);\n\tif (parentCollider.invalid())\n\t\treturn;\n\n\tfor (Engine::Registry64::entity_type& entity : SelectionTool::selection) {\n\t\tIRef<Comp::Collider> childCollider = screen.registry.get<Comp::Collider>(entity);\n\t\tif (childCollider.invalid())\n\t\t\tcontinue;\n\n\t\tif (childCollider->part == parentCollider->part)\n\t\t\tcontinue;\n\n\t\tCFrame cframe = parentCollider->part->getCFrame().globalToLocal(childCollider->part->getCFrame());\n\t\tAttachedPart part1 { cframe, parentCollider->part };\n\t\tAttachedPart part2 { CFrame(), childCollider->part };\n\t\tMagneticLink* link = new MagneticLink(part1, part2, 1.0);\n\n\t\tscreen.worldMutex->lock();\n\t\ttry {\n\t\t\tworld.addLink(link);\n\t\t} catch (std::invalid_argument& error) {\n\t\t\tLog::debug(error.what());\n\t\t}\n\t\tscreen.worldMutex->unlock();\n\t}\n}\n\n}\n"
  },
  {
    "path": "application/picker/tools/magneticLinkTool.h",
    "content": "#pragma once\n\n#include \"engine/tool/buttonTool.h\"\n#include \"graphics/glfwUtils.h\"\n\nnamespace P3D::Application {\n\nclass MagneticLinkTool : public Engine::ButtonTool {\npublic:\n\tDEFINE_TOOL(\"Magnetic Link\", \"Select two entities to create a magnetic link beteen.\", Graphics::GLFW::Cursor::CROSSHAIR);\n\n\t~MagneticLinkTool() override = default;\n\n\tvoid onRegister() override;\n\tvoid onDeregister() override;\n\tvoid onSelect() override;\n\n\tstatic void linkSelection();\n};\n\n}\n"
  },
  {
    "path": "application/picker/tools/motorConstraintTool.cpp",
    "content": "#include \"core.h\"\n#include \"motorConstraintTool.h\"\n\n#include \"application.h\"\n#include \"selectionTool.h\"\n#include \"graphics/resource/textureResource.h\"\n#include \"Physics3D/hardconstraints/constraintTemplates.h\"\n#include \"Physics3D/hardconstraints/fixedConstraint.h\"\n#include \"Physics3D/hardconstraints/controller/constController.h\"\n#include \"util/resource/resourceManager.h\"\n#include \"view/screen.h\"\n\nnamespace P3D::Application {\n\nvoid MotorConstraintTool::onRegister() {\n\tauto path = \"../res/textures/icons/\" + getName() + \".png\";\n\tResourceManager::add<Graphics::TextureResource>(getName(), path);\n}\n\nvoid MotorConstraintTool::onDeregister() {\n\t// Remove texture\n}\n\nvoid MotorConstraintTool::onSelect() {\n\tconstrainSelection();\n}\n\nvoid MotorConstraintTool::constrainSelection() {\n\tif (SelectionTool::selection.size() < 2)\n\t\treturn;\n\n\tIRef<Comp::Collider> parentCollider = screen.registry.get<Comp::Collider>(SelectionTool::selection[0]);\n\tif (parentCollider.invalid())\n\t\treturn;\n\n\tfor (Engine::Registry64::entity_type& entity : SelectionTool::selection) {\n\t\tIRef<Comp::Collider> childCollider = screen.registry.get<Comp::Collider>(entity);\n\t\tif (childCollider.invalid())\n\t\t\tcontinue;\n\n\t\tif (childCollider->part == parentCollider->part)\n\t\t\tcontinue;\n\n\t\tCFrame cframe = parentCollider->part->getCFrame().globalToLocal(childCollider->part->getCFrame());\n\t\tMotorConstraintTemplate<ConstController>* constraint = new MotorConstraintTemplate<ConstController>(1.0);\n\n\t\tscreen.worldMutex->lock();\n\t\ttry {\n\t\t\tparentCollider->part->attach(childCollider->part, constraint, cframe, CFrame());\n\t\t} catch (std::invalid_argument& error) {\n\t\t\tLog::debug(error.what());\n\t\t}\n\t\tscreen.worldMutex->unlock();\n\t}\n}\n\n}\n"
  },
  {
    "path": "application/picker/tools/motorConstraintTool.h",
    "content": "#pragma once\n\n#include \"engine/tool/buttonTool.h\"\n#include \"graphics/glfwUtils.h\"\n\nnamespace P3D::Application {\n\nclass MotorConstraintTool : public Engine::ButtonTool {\npublic:\n\tDEFINE_TOOL(\"Motor Constraint\", \"Select two entities to create a motor constraint beteen.\", Graphics::GLFW::Cursor::CROSSHAIR);\n\n\t~MotorConstraintTool() override = default;\n\n\tvoid onRegister() override;\n\tvoid onDeregister() override;\n\tvoid onSelect() override;\n\n\tstatic void constrainSelection();\n};\n\n}\n"
  },
  {
    "path": "application/picker/tools/pathTool.cpp",
    "content": "#include <core.h>\n#include \"pathTool.h\"\n\n#include \"application/application.h\"\n#include \"application/view/screen.h\"\n#include \"selectionTool.h\"\n#include \"util/resource/resourceManager.h\"\n#include \"graphics/resource/textureResource.h\"\n#include \"application/shader/shaders.h\"\n#include \"graphics/meshRegistry.h\"\n#include \"graphics/mesh/primitive.h\"\n\nnamespace P3D::Application {\n\nstatic URef<LinePrimitive> deltaLine = nullptr;\n\nvoid PathTool::onRegister() {\n\tauto path = \"../res/textures/icons/\" + getName() + \".png\";\n\tResourceManager::add<Graphics::TextureResource>(getName(), path);\n\n\tdeltaLine = std::make_unique<LinePrimitive>();\n}\n\nvoid PathTool::onDeregister() {\n\n}\n\nvoid PathTool::onRender() {\n\tRenderer::enableDepthTest();\n\n\tint divisions = 20;\n\tdouble size = 1.0;\n\tVec3 right = screen.camera.getRightDirection();\n\tVec3 up = screen.camera.getUpDirection();\n\tVec3 forward = screen.camera.getForwardDirection();\n\tVec3 center = castPositionToVec3(screen.camera.cframe.getPosition() + forward * distance);\n\tShaders::maskShader->updateColor(Colors::RED);\n\tShaders::maskShader->updateModel(GlobalCFrame().asMat4());\n\tfor (int index = -divisions / 2; index <= divisions / 2; index++) {\n\t\tVec3 dx = right * index * size;\n\t\tVec3 dy = up * index * size;\n\t\tVec3 mx = right * divisions / 2 * size;\n\t\tVec3 my = up * divisions / 2 * size;\n\t\tdeltaLine->resize(center - mx + dy, center + mx + dy);\n\t\tdeltaLine->render();\n\t\tdeltaLine->resize(center + dx - my, center + dx + my);\n\t\tdeltaLine->render();\n\t}\n\n\tShaders::maskShader->updateColor(Colors::RED);\n\tfor (std::size_t index = 0; index < nodes.size(); index++) {\n\t\tShaders::maskShader->updateModel(GlobalCFrame(castVec3ToPosition(nodes[index])).asMat4WithPreScale(DiagonalMat3({0.1, 0.1, 0.1})));\n\t\tMeshRegistry::get(MeshRegistry::sphere)->render();\n\n\t\tif (index > 0) {\n\t\t\tShaders::maskShader->updateModel(GlobalCFrame().asMat4());\n\t\t\tdeltaLine->resize(nodes[index], nodes[index - 1]);\n\t\t\tdeltaLine->render();\n\t\t}\n\t}\n\n\tRenderer::disableDepthTest();\n}\n\nvoid PathTool::onUpdate() {\n\n}\n\nvoid PathTool::onEvent(Engine::Event& event) {\n\tusing namespace Engine;\n\n\tEventDispatcher dispatcher(event);\n\tdispatcher.dispatch<MousePressEvent>(EVENT_BIND(PathTool::onMousePress));\n\tdispatcher.dispatch<MouseReleaseEvent>(EVENT_BIND(PathTool::onMouseRelease));\n\tdispatcher.dispatch<MouseDragEvent>(EVENT_BIND(PathTool::onMouseDrag));\n}\n\nVec3 intersect(double distance) {\n\tVec3 normal = -screen.camera.getForwardDirection();\n\tPosition center = screen.camera.cframe.getPosition() - normal * distance;\n\tdouble t = (center - SelectionTool::ray.origin) * normal / (SelectionTool::ray.direction * normal);\n\n\treturn castPositionToVec3(SelectionTool::ray.origin) + t * SelectionTool::ray.direction;\n}\n\nbool PathTool::onMousePress(Engine::MousePressEvent& event) {\n\tusing namespace Engine;\n\tif (event.getButton() != Mouse::LEFT)\n\t\treturn false;\n\n\tnodes.push_back(intersect(distance));\n\n\tactive = true;\n}\n\nbool PathTool::onMouseRelease(Engine::MouseReleaseEvent& event) {\n\tusing namespace Engine;\n\tif (event.getButton() != Mouse::LEFT)\n\t\treturn false;\n\t\n}\n\nbool PathTool::onMouseDrag(Engine::MouseDragEvent& event) {\n\tusing namespace Engine;\n\tif (event.getButton() != Mouse::LEFT)\n\t\treturn false;\n\n\tnodes.push_back(intersect(distance));\n\n\tactive = false;\n}\n\n}\n"
  },
  {
    "path": "application/picker/tools/pathTool.h",
    "content": "#pragma once\n#include \"engine/event/mouseEvent.h\"\n#include \"engine/tool/stateTool.h\"\n#include \"graphics/glfwUtils.h\"\n\nnamespace P3D::Application {\n\nclass PathTool : public Engine::StateTool {\nprivate:\n\tbool active = false;\n\n\tdouble distance = 20;\n\tstd::vector<Vec3> nodes;\n\npublic:\n\tDEFINE_TOOL(\"Path tool\", \"\", Graphics::GLFW::Cursor::ARROW);\n\n\t~PathTool() override = default;\n\n\tvoid onRegister() override;\n\tvoid onDeregister() override;\n\tvoid onRender() override;\n\tvoid onUpdate() override;\n\tvoid onEvent(Engine::Event& event) override;\n\n\tbool onMousePress(Engine::MousePressEvent& event);\n\tbool onMouseRelease(Engine::MouseReleaseEvent& event);\n\tbool onMouseDrag(Engine::MouseDragEvent& event);\n};\n\n};"
  },
  {
    "path": "application/picker/tools/pistonConstraintTool.cpp",
    "content": "#include \"core.h\"\n#include \"pistonConstraintTool.h\"\n\n#include \"application.h\"\n#include \"selectionTool.h\"\n#include \"graphics/resource/textureResource.h\"\n#include \"Physics3D/hardconstraints/fixedConstraint.h\"\n#include \"Physics3D/hardconstraints/sinusoidalPistonConstraint.h\"\n#include \"util/resource/resourceManager.h\"\n#include \"view/screen.h\"\n\nnamespace P3D::Application {\n\nvoid PistonConstraintTool::onRegister() {\n\tauto path = \"../res/textures/icons/\" + getName() + \".png\";\n\tResourceManager::add<Graphics::TextureResource>(getName(), path);\n}\n\nvoid PistonConstraintTool::onDeregister() {\n\t// Remove texture\n}\n\nvoid PistonConstraintTool::onSelect() {\n\tconstrainSelection();\n}\n\nvoid PistonConstraintTool::constrainSelection() {\n\tif (SelectionTool::selection.size() < 2)\n\t\treturn;\n\n\tIRef<Comp::Collider> parentCollider = screen.registry.get<Comp::Collider>(SelectionTool::selection[0]);\n\tif (parentCollider.invalid())\n\t\treturn;\n\n\tfor (Engine::Registry64::entity_type& entity : SelectionTool::selection) {\n\t\tIRef<Comp::Collider> childCollider = screen.registry.get<Comp::Collider>(entity);\n\t\tif (childCollider.invalid())\n\t\t\tcontinue;\n\n\t\tif (childCollider->part == parentCollider->part)\n\t\t\tcontinue;\n\n\t\tCFrame cframe = parentCollider->part->getCFrame().globalToLocal(childCollider->part->getCFrame());\n\t\tSinusoidalPistonConstraint* constraint = new SinusoidalPistonConstraint(2, 5, 1);\n\n\t\tscreen.worldMutex->lock();\n\t\ttry {\n\t\t\tparentCollider->part->attach(childCollider->part, constraint, cframe, CFrame());\n\t\t} catch (std::invalid_argument& error) {\n\t\t\tLog::debug(error.what());\n\t\t}\n\t\tscreen.worldMutex->unlock();\n\t}\n}\n\n}\n"
  },
  {
    "path": "application/picker/tools/pistonConstraintTool.h",
    "content": "#pragma once\n\n#include \"engine/tool/buttonTool.h\"\n#include \"graphics/glfwUtils.h\"\n\nnamespace P3D::Application {\n\nclass PistonConstraintTool : public Engine::ButtonTool {\npublic:\n\tDEFINE_TOOL(\"Piston Constraint\", \"Select two entities to create a motor constraint beteen.\", Graphics::GLFW::Cursor::CROSSHAIR);\n\n\t~PistonConstraintTool() override = default;\n\n\tvoid onRegister() override;\n\tvoid onDeregister() override;\n\tvoid onSelect() override;\n\n\tstatic void constrainSelection();\n};\n\n}\n"
  },
  {
    "path": "application/picker/tools/regionSelectionTool.cpp",
    "content": "﻿#include \"core.h\"\n\n#include \"regionSelectionTool.h\"\n\n#include \"../engine/event/event.h\"\n#include \"../engine/event/mouseEvent.h\"\n#include \"../graphics/gui/gui.h\"\n#include \"../graphics/gui/guiUtils.h\"\n#include \"../graphics/path/path.h\"\n#include \"../graphics/resource/textureResource.h\"\n#include <Physics3D/boundstree/filters/visibilityFilter.h>\n#include \"../util/resource/resourceManager.h\"\n#include \"selectionTool.h\"\n\n#include \"../../view/screen.h\"\n#include \"../../application.h\"\n#include \"../../shader/shaders.h\"\n#include \"../../input/standardInputHandler.h\"\n#include \"../../ecs/components.h\"\n#include \"../../worlds.h\"\n#include <cmath>\n\nnamespace P3D::Application {\n\n\tvoid RegionSelectionTool::onRegister() {\n\t\tauto path = \"../res/textures/icons/\" + getName() + \".png\";\n\t\tResourceManager::add<TextureResource>(getName(), path);\n\t}\n\n\tvoid RegionSelectionTool::onDeregister() {\n\t\t// Remove texture\n\t}\n\n\tvoid RegionSelectionTool::onRender() {\n\t\tusing namespace Graphics;\n\n\t\tRenderer::beginScene();\n\n\t\tGraphics::Shaders::guiShader->bind();\n\t\tGraphics::Shaders::guiShader->setUniform(\"projectionMatrix\", screen.camera.orthoMatrix);\n\n\t\tPath::batch = GUI::batch;\n\t\tif (getToolStatus() == kActive) {\n\t\t\tVec2 a = GUI::map(Vec2(region.x, region.y));\n\t\t\tVec2 b = GUI::map(handler->getMousePosition());\n\t\t\tVec2 position(std::min(a.x, b.x), std::min(a.y, b.y));\n\t\t\tVec2 dimension(std::abs(a.x - b.x), std::abs(a.y - b.y));\n\t\t\tPath::rect(position, dimension);\n\t\t\tPath::batch->submit();\n\t\t}\n\n\t\tRenderer::endScene();\n\t}\n\n\tvoid RegionSelectionTool::onEvent(Engine::Event& event) {\n\t\tusing namespace Engine;\n\n\t\tEventDispatcher dispatcher(event);\n\t\tdispatcher.dispatch<MousePressEvent>(EVENT_BIND(RegionSelectionTool::onMousePress));\n\t\tdispatcher.dispatch<MouseReleaseEvent>(EVENT_BIND(RegionSelectionTool::onMouseRelease));\n\t}\n\n\tbool RegionSelectionTool::onMousePress(Engine::MousePressEvent& event) {\n\t\tusing namespace Engine;\n\n\t\tif (event.getButton() != Mouse::LEFT)\n\t\t\treturn false;\n\n\t\tregion.x = event.getX();\n\t\tregion.y = event.getY();\n\n\t\t// Multi selection check\n\t\tif (!event.getModifiers().isCtrlPressed())\n\t\t\tSelectionTool::clear();\n\n\t\tsetToolStatus(kActive);\n\n\t\treturn false;\n\t}\n\n\tbool RegionSelectionTool::onMouseRelease(Engine::MouseReleaseEvent& event) {\n\t\tusing namespace Engine;\n\n\t\tif (event.getButton() != Mouse::LEFT)\n\t\t\treturn false;\n\n\t\tregion.z = event.getX();\n\t\tregion.w = event.getY();\n\n\t\tif (region.x == region.z && region.y == region.w) { // Single selection\n\t\t\tauto intersectedEntity = SelectionTool::getIntersectedEntity();\n\n\t\t\tif (intersectedEntity.has_value())\n\t\t\t\tSelectionTool::toggle(intersectedEntity->first);\n\t\t} else { // Region selection\n\t\t\tVec4 mappedRegion = GUI::mapRegion(region, Vec2(0, screen.dimension.x), Vec2(screen.dimension.y, 0), Vec2(-1, 1), Vec2(-1, 1));\n\t\t\tauto [left, right] = GUI::minmax(mappedRegion.x, mappedRegion.z);\n\t\t\tauto [down, up] = GUI::minmax(mappedRegion.y, mappedRegion.w);\n\t\t\tVisibilityFilter visibilityFilter = VisibilityFilter::forSubWindow(screen.camera.cframe.position, screen.camera.getForwardDirection(), screen.camera.getUpDirection(), screen.camera.fov, screen.camera.aspect, screen.camera.zfar, left, right, down, up);\n\n\t\t\tauto view = screen.registry.view<Comp::Hitbox, Comp::Transform>();\n\t\t\tstd::shared_lock<UpgradeableMutex> worldReadLock(*screen.worldMutex);\n\t\t\tfor (auto entity : view) {\n\t\t\t\tIRef<Comp::Hitbox> hitbox = view.get<Comp::Hitbox>(entity);\n\t\t\t\tIRef<Comp::Transform> transform = view.get<Comp::Transform>(entity);\n\n\t\t\t\tShape shape = hitbox->getShape();\n\t\t\t\tif (!transform->isRootPart())\n\t\t\t\t\tshape = shape.scaled(transform->getScale());\n\n\t\t\t\tBounds bounds = shape.getBounds(transform->getRotation()) + transform->getPosition();\n\t\t\t\tif (visibilityFilter(bounds))\n\t\t\t\t\tSelectionTool::select(entity);\n\t\t\t}\n\t\t}\n\n\t\tsetToolStatus(kIdle);\n\n\n\t\treturn false;\n\t}\n}\n"
  },
  {
    "path": "application/picker/tools/regionSelectionTool.h",
    "content": "﻿#pragma once\n\n#include \"../graphics/glfwUtils.h\"\n#include \"../engine/event/mouseEvent.h\"\n#include \"../engine/tool/stateTool.h\"\n#include \"../engine/ecs/registry.h\"\n#include \"ecs/components.h\"\n\nstruct ExtendedPart;\n\nnamespace P3D::Application {\n\nclass RegionSelectionTool : public Engine::StateTool {\nprivate:\n\tenum SelectionToolStatus : Engine::ToolStatus {\n\t\tkIdle = 0,\n\t\tkActive = 1\n\t};\n\n\tVec4i region;\n\npublic:\n\tDEFINE_TOOL(\"Select region\", \"Selects one or multiple entities within a region.\", Graphics::GLFW::Cursor::CROSSHAIR);\n\n\t~RegionSelectionTool() override = default;\n\n\tvoid onRegister() override;\n\tvoid onDeregister() override;\n\tvoid onRender() override;\n\tvoid onEvent(Engine::Event& event) override;\n\n\tbool onMousePress(Engine::MousePressEvent& event);\n\tbool onMouseRelease(Engine::MouseReleaseEvent& event);\n};\n\n}"
  },
  {
    "path": "application/picker/tools/rotationTool.cpp",
    "content": "#include \"core.h\"\n\n#include \"rotationTool.h\"\n\n#include \"worlds.h\"\n#include \"application.h\"\n#include \"selectionTool.h\"\n#include \"translationTool.h\"\n#include \"view/screen.h\"\n#include \"shader/shaders.h\"\n\n#include <Physics3D/geometry/shapeLibrary.h>\n#include <Physics3D/math/rotation.h>\n#include <Physics3D/threading/upgradeableMutex.h>\n#include \"../graphics/extendedTriangleMesh.h\"\n#include \"../graphics/mesh/primitive.h\"\n#include \"../graphics/mesh/indexedMesh.h\"\n#include \"../graphics/resource/textureResource.h\"\n#include \"../util/resource/resourceManager.h\"\n#include \"engine/input/keyboard.h\"\n#include \"imgui/imgui.h\"\n#include \"input/standardInputHandler.h\"\n\nnamespace P3D::Application {\n\t\n\tconstexpr static Rotation transformations[] {\n\t\tRotation::Predefined::Y_90,\t// X\n\t\tRotation::Predefined::X_270, // Y\t\t\t\n\t\tRotation::Predefined::IDENTITY // Z\n\t};\n\n\tstatic std::optional<Position> startPosition;\n\n\tstatic URef<LinePrimitive> deltaLine = nullptr;\n\tstatic URef<LinePrimitive> unitLine = nullptr;\n\tstatic URef<LinePrimitive> infiniteLine = nullptr;\n\tstatic URef<IndexedMesh> handleMesh;\n\tstatic ExtendedTriangleMesh handleShape;\n\t\n\tvoid RotationTool::onRegister() {\n\t\tusing namespace Graphics;\n\n\t\t// Load icon\n\t\tstd::string path = \"../res/textures/icons/\" + getName() + \".png\";\n\t\tResourceManager::add<TextureResource>(getName(), path);\n\n\t\t// Create alignment line\n\t\tdeltaLine = std::make_unique<LinePrimitive>();\n\t\tunitLine = std::make_unique<LinePrimitive>();\n\t\tinfiniteLine = std::make_unique<LinePrimitive>();\n\n\t\tunitLine->resize(Vec3f(0, 0, 0), Vec3f(0, 0, 0.5));\n\t\tinfiniteLine->resize(Vec3f(0, 0, -100000), Vec3f(0, 0, 100000));\n\t\t\n\t\t// Create handle shapes\n\t\thandleShape = ExtendedTriangleMesh::generateSmoothNormalsShape(ShapeLibrary::createTorus(1.0f, 0.03f, 80, 12));\n\t\thandleMesh = std::make_unique<IndexedMesh>(handleShape);\n\n\t\t// Set idle status\n\t\tsetToolStatus(kIdle);\n\t}\n\n\tvoid RotationTool::onDeregister() {\n\t\t// Todo remove icon\n\t\t// Todo remove line\n\n\t\thandleMesh->close();\n\t}\n\n\tvoid RotationTool::onRender() {\n\t\tusing namespace Graphics;\n\t\t\n\t\tstd::optional<GlobalCFrame> cframe = SelectionTool::selection.getCFrame();\n\t\tif (!cframe.has_value())\n\t\t\treturn;\n\n\t\tbool local = !handler->keys[Engine::Keyboard::KEY_LEFT_CONTROL.getCode()];\n\t\tif (!local)\n\t\t\tcframe = GlobalCFrame(cframe->position);\n\n\t\tMat4f model = cframe->asMat4();\n\t\tMat4f modelX = model * joinDiagonal(Mat3f(transformations[0].asRotationMatrix()), 1.0f);\n\t\tMat4f modelY = model * joinDiagonal(Mat3f(transformations[1].asRotationMatrix()), 1.0f);\n\t\tMat4f modelZ = model * joinDiagonal(Mat3f(transformations[2].asRotationMatrix()), 1.0f);\n\t\tMat4f modelC = GlobalCFrame(cframe->getPosition(), Rotation::fromDirection(Vec3(screen.camera.cframe.position - cframe->getPosition()))).asMat4();\n\n\t\tauto status = getToolStatus();\t\t\n\t\tShaders::maskShader->updateModel(modelX);\n\t\tShaders::maskShader->updateColor(Colors::RGB_R);\n\t\tunitLine->render();\n\t\tif (status == kRotateX)\n\t\t\tinfiniteLine->render();\n\n\t\tShaders::maskShader->updateModel(modelY);\n\t\tShaders::maskShader->updateColor(Colors::RGB_G);\n\t\tunitLine->render();\n\t\tif (status == kRotateY) \n\t\t\tinfiniteLine->render();\n\n\t\tShaders::maskShader->updateModel(modelZ);\n\t\tShaders::maskShader->updateColor(Colors::RGB_B);\n\t\tunitLine->render();\n\t\tif (status == kRotateZ) \n\t\t\tinfiniteLine->render();\n\n\t\tShaders::basicShader->updateModel(modelC);\n\t\tShaders::basicShader->updateMaterial(Graphics::Comp::Material(Colors::YELLOW));\n\t\thandleMesh->render();\n\n\t\t// X\n\t\tShaders::basicShader->updateMaterial(Graphics::Comp::Material(Colors::RGB_R));\n\t\tShaders::basicShader->updateModel(modelX);   \n\t\thandleMesh->render();\n\t\t\n\t\t// Y\n\t\tShaders::basicShader->updateModel(modelY);\n\t\tShaders::basicShader->updateMaterial(Graphics::Comp::Material(Colors::RGB_G));\n\t\thandleMesh->render();\n\n\t\t// Z\n\t\tShaders::basicShader->updateMaterial(Graphics::Comp::Material(Colors::RGB_B));\n\t\tShaders::basicShader->updateModel(modelZ);\n\t\thandleMesh->render();\n\n\t\tif (startPosition.has_value() && active) {\n\t\t\tShaders::basicShader->updateMaterial(Graphics::Comp::Material(Colors::ORANGE));\n\t\t\tShaders::basicShader->updateModel(GlobalCFrame(startPosition.value()), DiagonalMat3::IDENTITY() * 0.5);\n\t\t\tVec3f doubleRelativePosition = (castPositionToVec3f(cframe->position) - castPositionToVec3f(startPosition.value())) * 2.0f;\n\t\t\tdeltaLine->resize(Vec3f(), doubleRelativePosition);\n\t\t\tdeltaLine->render();\n\t\t}\n\t}\n\n\tvoid RotationTool::onUpdate() {\n\t\t// Keep the tool status if the tool is active\n\t\tif (this->active)\n\t\t\treturn;\n\n\t\t// Reset tool status\n\t\tsetToolStatus(kIdle);\n\t\tSelectionTool::intersectedPoint = std::nullopt;\n\n\t\t// The intersection distance to find\n\t\tstd::optional<double> closestIntersectionDistance;\n\n\t\t// Look for edit tool intersections if the selection has a cframe\n\t\tstd::optional<GlobalCFrame> cframe = SelectionTool::selection.getCFrame();\n\t\tif (!cframe.has_value())\n\t\t\treturn;\n\n\t\tbool local = !handler->keys[Engine::Keyboard::KEY_LEFT_CONTROL.getCode()];\n\t\tif (!local)\n\t\t\tcframe = GlobalCFrame(cframe->position);\n\n\t\tGlobalCFrame frame = *cframe;\n\t\tfor (char status = kRotateX; status <= kRotateC; status++) {\n\t\t\tif (status == kRotateC) {\n\t\t\t\tframe.rotation = Rotation::fromDirection(Vec3(screen.camera.cframe.position - cframe->getPosition()));\n\t\t\t} else {\n\t\t\t\tframe.rotation = cframe->getRotation() * transformations[status - 1];\n\t\t\t}\n\t\t\t\n\t\t\tstd::optional<double> distance = SelectionTool::intersect(frame, handleShape);\n\n\t\t\tif (!distance.has_value())\n\t\t\t\tcontinue;\n\n\t\t\tif (!closestIntersectionDistance.has_value() || 0.0 < distance && distance < closestIntersectionDistance) {\n\t\t\t\tclosestIntersectionDistance = distance;\n\t\t\t\tsetToolStatus(status);\n\t\t\t}\n\t\t}\n\n\t\tif (closestIntersectionDistance.has_value())\n\t\t\tSelectionTool::intersectedPoint = SelectionTool::ray.origin + SelectionTool::ray.direction * *closestIntersectionDistance;\n\t}\n\n\tvoid RotationTool::onEvent(Engine::Event& event) {\n\t\tusing namespace Engine;\n\n\t\tEventDispatcher dispatcher(event);\n\t\tdispatcher.dispatch<MousePressEvent>(EVENT_BIND(RotationTool::onMousePress));\n\t\tdispatcher.dispatch<MouseReleaseEvent>(EVENT_BIND(RotationTool::onMouseRelease));\n\t\tdispatcher.dispatch<MouseDragEvent>(EVENT_BIND(RotationTool::onMouseDrag));\n\t}\n\n\tbool RotationTool::onMousePress(Engine::MousePressEvent& event) {\n\t\tusing namespace Engine;\n\t\tif (event.getButton() != Mouse::LEFT)\n\t\t\treturn false;\n\n\t\t// Auto select an entity if the selection status is idle, in that case no edit tool or entity is intersected\n\t\tauto status = getToolStatus();\n\t\tif (status == kIdle) {\n\t\t\t// Find the intersected entity\n\t\t\tauto intersectedEntity = SelectionTool::getIntersectedEntity();\n\t\t\t\t\t\n\t\t\t// If control is pressed, add to selection, but don't change the tool status \n\t\t\tif (event.getModifiers().isCtrlPressed()) {\n\t\t\t\t// No intersection causes nothing\n\t\t\t\tif (!intersectedEntity.has_value())\n\t\t\t\t\treturn false;\n\t\t\t} else {\n\t\t\t\t// Clear the selection before selecting the new entity\n\t\t\t\tSelectionTool::selection.clear();\n\n\t\t\t\t// No intersection causes only deselection\n\t\t\t\tif (!intersectedEntity.has_value())\n\t\t\t\t\treturn false;\n\n\t\t\t\tsetToolStatus(kTranslateC);\n\t\t\t\tSelectionTool::intersectedPoint = intersectedEntity->second;\n\t\t\t}\n\n\t\t\tSelectionTool::select(intersectedEntity->first);\n\t\t}\n\n\t\t// Set the selected point \n\t\tSelectionTool::selectedPoint = SelectionTool::intersectedPoint;\n\n\t\t// Set start position\n\t\tstartPosition = SelectionTool::selectedPoint;\n\n\t\t// Set edit status to active\n\t\tthis->active = true;\n\n\t\treturn false;\n\t}\n\n\tbool RotationTool::onMouseRelease(Engine::MouseReleaseEvent& event) {\n\t\tusing namespace Engine;\n\t\tif (event.getButton() != Mouse::LEFT)\n\t\t\treturn false;\n\n\t\t// Set inactive\n\t\tthis->active = false;\n\n\t\t// Reset magnet\n\t\tTranslationTool::magnet.selectedPart = nullptr;\n\n\t\t// Clear start position\n\t\tstartPosition = std::nullopt;\n\n\t\treturn false;\n\t};\n\n\tbool RotationTool::onMouseDrag(Engine::MouseDragEvent& event) {\n\t\tif (!this->active)\n\t\t\treturn false;\n\t\t\n\t\tauto status = getToolStatus();\n\t\tif (status == kIdle)\n\t\t\treturn false;\n\n\t\tbool clamp = handler->keys[Engine::Keyboard::KEY_LEFT_ALT.getCode()];\n\t\tbool local = !handler->keys[Engine::Keyboard::KEY_LEFT_CONTROL.getCode()];\n\n\t\tstd::unique_lock<UpgradeableMutex> worldWriteLock(*screen.worldMutex);\n\t\tswitch (status) {\n\t\t\tcase kRotateX:\n\t\t\t\trotateAroundLine({ 1, 0, 0 }, clamp, local);\n\t\t\t\tbreak;\n\t\t\tcase kRotateY:\n\t\t\t\trotateAroundLine({ 0, 1, 0 }, clamp, local);\n\t\t\t\tbreak;\n\t\t\tcase kRotateZ:\n\t\t\t\trotateAroundLine({ 0, 0, 1 }, clamp, local);\n\t\t\t\tbreak;\n\t\t\tcase kRotateC:\n\t\t\t\trotateAroundLine(screen.camera.cframe.rotation * Vec3(0, 0, 1), clamp, false);\n\t\t\t\tbreak;\n\t\t\tcase kTranslateC:\n\t\t\t\tTranslationTool::translateInPlane(screen.camera.cframe.rotation * Vec3(0, 0, 1), clamp, false);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tvoid RotationTool::rotateAroundLine(const Vec3& direction, bool clamp, bool local) {\n\t\tif (SelectionTool::selection.empty())\n\t\t\treturn;\n\n\t\tstd::optional<GlobalCFrame> cframe = SelectionTool::selection.getCFrame();\n\t\tif (!cframe.has_value())\n\t\t\treturn;\n\t\t\n\t\t// Plane of edit tool, which can be expressed as all points p where (p - position) * normal = 0. Where n is the edit direction and p0 the center of the selected part\n\t\tPosition position = cframe->getPosition();\n\n\t\t// Apply model matrix\n\t\tVec3 normal = local ? cframe->localToRelative(direction) : direction;\n\n\t\t// Calculate intersection of mouse ray and edit plane\n\t\tdouble ln = SelectionTool::ray.direction * normal;\n\t\tif (ln == 0.0)\n\t\t\treturn; // No rotation if plane is perpendicular to mouse ray\n\n\t\t// Vector from part center to intersection\n\t\tPosition intersection = SelectionTool::ray.origin + (position - SelectionTool::ray.origin) * normal / (SelectionTool::ray.direction * normal) * SelectionTool::ray.direction;\n\t\tVec3 intersectionVector = intersection - position;\n\n\t\t// Length check\n\t\tVec3 relativeSelectedPoint = *SelectionTool::selectedPoint - position;\n\t\tdouble length1sq = lengthSquared(intersectionVector);\n\t\tdouble length2sq = lengthSquared(relativeSelectedPoint);\n\t\tif (length1sq == 0.0 || length2sq == 0.0)\n\t\t\treturn; // Prevent errors when vector is the zero vector\n\n\t\t// Triple product to find angle sign\n\t\tdouble triple = relativeSelectedPoint * (intersectionVector % normal);\n\t\tdouble sign = triple > 0.0 ? 1.0 : -1.0;\n\n\t\t// Get angle between last intersectionVector and new one\n\t\tdouble cosa = relativeSelectedPoint * intersectionVector / sqrt(length1sq * length2sq);\n\n\t\t// No rotation when vectors coincide\n\t\tif (!(std::abs(cosa) < 1))\n\t\t\treturn;\n\n\t\tdouble angle = sign * acos(cosa);\n\n\t\tif (clamp) {\n\t\t\tdouble rad15 = 0.261799;\n\t\t\tangle = angle - fmod(angle, rad15);\n\t\t}\n\n\t\tif (angle != 0.0) {\n\t\t\t// Update last intersectionVector\n\t\t\tSelectionTool::selectedPoint = position + intersectionVector;\n\n\t\t\t// Apply rotation\n\t\t\tSelectionTool::selection.rotate(normal, angle);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "application/picker/tools/rotationTool.h",
    "content": "#pragma once\n\n#include \"../graphics/glfwUtils.h\"\n#include \"../engine/event/mouseEvent.h\"\n#include \"../engine/tool/stateTool.h\"\n#include \"ecs/components.h\"\n\nnamespace P3D::Application {\n\nclass RotationTool : public Engine::StateTool {\nprivate:\n\tenum SelectionToolStatus : Engine::ToolStatus {\n\t\tkIdle = 0,\n\t\tkRotateX = 1,\n\t\tkRotateY = 2,\n\t\tkRotateZ = 3,\n\t\tkRotateC = 4,\n\t\tkTranslateC = 5\n\t};\n\n\tbool active = false;\n\npublic:\n\tDEFINE_TOOL(\"Rotate\", \"Rotate entities by using the handles\", Graphics::GLFW::Cursor::ARROW);\n\n\tvirtual ~RotationTool() override = default;\t\n\n\tvoid onRegister() override;\n\tvoid onDeregister() override;\n\tvoid onRender() override;\n\tvoid onUpdate() override;\n\tvoid onEvent(Engine::Event& event) override;\n\n\tbool onMousePress(Engine::MousePressEvent& event);\n\tbool onMouseRelease(Engine::MouseReleaseEvent& event);\n\tbool onMouseDrag(Engine::MouseDragEvent& event);\n\n\tstatic void rotateAroundLine(const Vec3& direction, bool clamp, bool local);\n};\n\n};"
  },
  {
    "path": "application/picker/tools/scaleTool.cpp",
    "content": "#include \"core.h\"\n\n#include \"scaleTool.h\"\n\n#include \"worlds.h\"\n#include \"application.h\"\n#include \"selectionTool.h\"\n#include \"translationTool.h\"\n#include \"view/screen.h\"\n#include \"shader/shaders.h\"\n\n#include <Physics3D/geometry/shapeLibrary.h>\n#include <Physics3D/math/rotation.h>\n#include <Physics3D/threading/upgradeableMutex.h>\n#include \"../graphics/extendedTriangleMesh.h\"\n#include \"../graphics/mesh/primitive.h\"\n#include \"../graphics/mesh/indexedMesh.h\"\n#include \"../graphics/resource/textureResource.h\"\n#include \"../util/resource/resourceManager.h\"\n#include \"engine/input/keyboard.h\"\n#include \"imgui/imgui.h\"\n#include \"input/standardInputHandler.h\"\n\nnamespace P3D::Application {\n\t\n\tconstexpr static Rotation transformations[] {\n\t\tRotation::Predefined::Y_90,\t// X, XY\n\t\tRotation::Predefined::X_270, // Y\t\t\t\n\t\tRotation::Predefined::IDENTITY, // Z, YZ\n\t\tRotation::Predefined::Z_270 // XZ\n\t};\n\n\tconstexpr static std::size_t mapping[] {\n\t\t0, // X\n\t\t1, // Y\n\t\t2, // Z\n\t\t2, // C\n\t\t0, // XY\n\t\t3, // XZ\n\t\t2  // YZ\n\t};\n\n\tstatic LinePrimitive* line = nullptr;\n\tstatic IndexedMesh* quadMesh;\n\tstatic ExtendedTriangleMesh quadShape;\n\tstatic IndexedMesh* handleMesh;\n\tstatic ExtendedTriangleMesh handleShape;\n\tstatic IndexedMesh* centerMesh;\n\tstatic ExtendedTriangleMesh centerShape;\n\n\tstatic Polyhedron createBoxOnStick(float boxSide, float stickRadius) {\n\t\tVec2f vecs[] { { 0.0f, stickRadius }, { 1.0f - boxSide, stickRadius }, { 1.0f - boxSide, boxSide / sqrtf(2.0f) }, { 1.0f, boxSide / sqrtf(2.0f) }};\n\t\treturn ShapeLibrary::createRevolvedShape(0.0f, vecs, 4, 1.0f, 4).rotated(Rotation::rotZ(3.14159265359 / 4));\n\t}\n\t\n\tvoid ScaleTool::onRegister() {\n\t\tusing namespace Graphics;\n\n\t\t// Load icon\n\t\tstd::string path = \"../res/textures/icons/\" + getName() + \".png\";\n\t\tResourceManager::add<TextureResource>(getName(), path);\n\n\t\t// Create alignment line\n\t\tline = new LinePrimitive();\n\t\tline->resize(Vec3f(0, 0, -100000), Vec3f(0, 0, 100000));\n\t\t\n\t\t// Create handle shapes\n\t\thandleShape = ExtendedTriangleMesh::generateSplitNormalsShape(createBoxOnStick(0.2f, 0.03f));\n\t\thandleMesh = new IndexedMesh(handleShape);\n\t\tcenterShape = ExtendedTriangleMesh::generateSplitNormalsShape(ShapeLibrary::createCube(0.2f));\n\t\tcenterMesh = new IndexedMesh(centerShape);\n\t\tquadShape = ExtendedTriangleMesh::generateSplitNormalsShape(ShapeLibrary::createBox(0.02f, 0.25f, 0.25f).translated({ 0, 0.5, 0.5 }));\n\t\tquadMesh = new IndexedMesh(quadShape);\n\t\t\n\t\t// Set idle status\n\t\tsetToolStatus(kIdle);\n\t}\n\n\tvoid ScaleTool::onDeregister() {\n\t\t// Todo remove icon\n\t\t// Todo remove line\n\n\t\thandleMesh->close();\n\t\tcenterMesh->close();\n\t\tquadMesh->close();\n\t}\n\n\tvoid ScaleTool::onRender() {\n\t\tusing namespace Graphics;\n\t\t\n\t\tstd::optional<GlobalCFrame> cframe = SelectionTool::selection.getCFrame();\n\t\tif (!cframe.has_value())\n\t\t\treturn;\n\n\t\tMat4f model = cframe->asMat4();\n\t\tMat4f modelX = model * joinDiagonal(Mat3f(transformations[0].asRotationMatrix()), 1.0f);\n\t\tMat4f modelY = model * joinDiagonal(Mat3f(transformations[1].asRotationMatrix()), 1.0f);\n\t\tMat4f modelZ = model * joinDiagonal(Mat3f(transformations[2].asRotationMatrix()), 1.0f);\n\t\tMat4f modelXZ = model * joinDiagonal(Mat3f(transformations[3].asRotationMatrix()), 1.0f);\n\n\t\tauto status = getToolStatus();\t\t\n\t\tif (status == kScaleX || status == kScaleXY || status == kScaleXZ || status == kScaleXYZ) {\n\t\t\tShaders::maskShader->updateModel(modelX);\n\t\t\tShaders::maskShader->updateColor(Colors::RGB_R);\n\t\t\tline->render();\n\t\t}\n\n\t\tif (status == kScaleY || status == kScaleXY || status == kScaleYZ || status == kScaleXYZ) {\n\t\t\tShaders::maskShader->updateModel(modelY);\n\t\t\tShaders::maskShader->updateColor(Colors::RGB_G);\n\t\t\tline->render();\n\t\t}\n\n\t\tif (status == kScaleZ || status == kScaleXZ || status == kScaleYZ || status == kScaleXYZ) {\n\t\t\tShaders::maskShader->updateModel(modelZ);\n\t\t\tShaders::maskShader->updateColor(Colors::RGB_B);\n\t\t\tline->render();\n\t\t}\n\n\t\tShaders::basicShader->updateModel(model);\n\t\tShaders::basicShader->updateMaterial(Graphics::Comp::Material(Colors::WHITE));\n\t\tcenterMesh->render();\n\n\t\t// X, XY\n\t\tShaders::basicShader->updateMaterial(Graphics::Comp::Material(Colors::RGB_R));\n\t\tShaders::basicShader->updateModel(modelX);\n\t\thandleMesh->render();\n\t\tShaders::basicShader->updateMaterial(Graphics::Comp::Material(Colors::RGB_B));\n\t\tquadMesh->render();\n\n\t\t// Y, XZ\n\t\tShaders::basicShader->updateModel(modelY);\n\t\tShaders::basicShader->updateMaterial(Graphics::Comp::Material(Colors::RGB_G));\n\t\thandleMesh->render();\n\t\tShaders::basicShader->updateModel(modelXZ);\n\t\tquadMesh->render();\n\n\t\t// Z, YZ\n\t\tShaders::basicShader->updateMaterial(Graphics::Comp::Material(Colors::RGB_B));\n\t\tShaders::basicShader->updateModel(modelZ);\n\t\thandleMesh->render();\n\t\tShaders::basicShader->updateMaterial(Graphics::Comp::Material(Colors::RGB_R));\n\t\tquadMesh->render();\n\t}\n\n\tvoid ScaleTool::onUpdate() {\n\t\t// Keep the tool status if the tool is active\n\t\tif (this->active)\n\t\t\treturn;\n\n\t\t// Reset tool status\n\t\tsetToolStatus(kIdle);\n\t\tSelectionTool::intersectedPoint = std::nullopt;\n\n\t\t// The intersection distance to find\n\t\tstd::optional<double> closestIntersectionDistance;\n\n\t\t// Look for edit tool intersections if the selection has a cframe\n\t\tstd::optional<GlobalCFrame> cframe = SelectionTool::selection.getCFrame();\n\t\tif (!cframe.has_value())\n\t\t\treturn;\n\t\t\n\t\tGlobalCFrame frame = *cframe;\n\t\tfor (char status = kScaleX; status <= kScaleYZ; status++) {\n\t\t\tExtendedTriangleMesh shape;\n\t\t\tswitch (status) {\n\t\t\t\tcase kScaleXYZ:\n\t\t\t\t\tshape = centerShape;\n\t\t\t\t\tbreak;\n\t\t\t\tcase kScaleX:\n\t\t\t\tcase kScaleY:\n\t\t\t\tcase kScaleZ:\n\t\t\t\t\tshape = handleShape;\n\t\t\t\t\tbreak;\n\t\t\t\tcase kScaleXY:\n\t\t\t\tcase kScaleXZ:\n\t\t\t\tcase kScaleYZ:\n\t\t\t\t\tshape = quadShape;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\tframe.rotation = cframe->getRotation() * transformations[mapping[status - 1]];\n\t\t\tstd::optional<double> distance = SelectionTool::intersect(frame, shape);\n\n\t\t\tif (!distance.has_value())\n\t\t\t\tcontinue;\n\n\t\t\tif (!closestIntersectionDistance.has_value() || 0.0 < distance && distance < closestIntersectionDistance) {\n\t\t\t\tclosestIntersectionDistance = distance;\n\t\t\t\tsetToolStatus(status);\n\t\t\t}\n\t\t}\n\n\t\tif (closestIntersectionDistance.has_value())\n\t\t\tSelectionTool::intersectedPoint = SelectionTool::ray.origin + SelectionTool::ray.direction * *closestIntersectionDistance;\n\t}\n\n\tvoid ScaleTool::onEvent(Engine::Event& event) {\n\t\tusing namespace Engine;\n\n\t\tEventDispatcher dispatcher(event);\n\t\tdispatcher.dispatch<MousePressEvent>(EVENT_BIND(ScaleTool::onMousePress));\n\t\tdispatcher.dispatch<MouseReleaseEvent>(EVENT_BIND(ScaleTool::onMouseRelease));\n\t\tdispatcher.dispatch<MouseDragEvent>(EVENT_BIND(ScaleTool::onMouseDrag));\n\t}\n\n\tbool ScaleTool::onMousePress(Engine::MousePressEvent& event) {\n\t\tusing namespace Engine;\n\t\tif (event.getButton() != Mouse::LEFT)\n\t\t\treturn false;\n\n\t\t// Auto select an entity if the selection status is idle, in that case no edit tool or entity is intersected\n\t\tauto status = getToolStatus();\n\t\tif (status == kIdle) {\n\t\t\t// Find the intersected entity\n\t\t\tauto intersectedEntity = SelectionTool::getIntersectedEntity();\n\t\t\t\t\t\n\t\t\t// If control is pressed, add to selection, but don't change the tool status \n\t\t\tif (event.getModifiers().isCtrlPressed()) {\n\t\t\t\t// No intersection causes nothing\n\t\t\t\tif (!intersectedEntity.has_value())\n\t\t\t\t\treturn false;\n\t\t\t} else {\n\t\t\t\t// Clear the selection before selecting the new entity\n\t\t\t\tSelectionTool::selection.clear();\n\n\t\t\t\t// No intersection causes only deselection\n\t\t\t\tif (!intersectedEntity.has_value())\n\t\t\t\t\treturn false;\n\n\t\t\t\t// If an intersection is found, select it and behave like center edit\n\t\t\t\tsetToolStatus(kTranslateC);\n\t\t\t\tSelectionTool::intersectedPoint = intersectedEntity->second;\n\t\t\t}\n\n\t\t\tSelectionTool::select(intersectedEntity->first);\n\t\t}\n\n\t\t// Set the selected point \n\t\tSelectionTool::selectedPoint = SelectionTool::intersectedPoint;\n\n\t\t// Set edit status to active\n\t\tthis->active = true;\n\n\t\treturn false;\n\t}\n\n\tbool ScaleTool::onMouseRelease(Engine::MouseReleaseEvent& event) {\n\t\tusing namespace Engine;\n\t\tif (event.getButton() != Mouse::LEFT)\n\t\t\treturn false;\n\n\t\tthis->active = false;\n\n\t\tTranslationTool::magnet.selectedPart = nullptr;\n\n\t\treturn false;\n\t};\n\n\tbool ScaleTool::onMouseDrag(Engine::MouseDragEvent& event) {\n\t\tif (!this->active)\n\t\t\treturn false;\n\t\t\n\t\tauto status = getToolStatus();\n\t\tif (status == kIdle)\n\t\t\treturn false;\n\n\t\tbool clamp = handler->keys[Engine::Keyboard::KEY_LEFT_ALT.getCode()];\n\n\t\tstd::unique_lock<UpgradeableMutex> worldLock(*screen.worldMutex);\n\t\tswitch (status) {\n\t\t\tcase kScaleX:\n\t\t\t\tscaleAlongLine({ 1, 0, 0 });\n\t\t\t\tbreak;\n\t\t\tcase kScaleY:\n\t\t\t\tscaleAlongLine({ 0, 1, 0 });\n\t\t\t\tbreak;\n\t\t\tcase kScaleZ:\n\t\t\t\tscaleAlongLine({ 0, 0, 1 });\n\t\t\t\tbreak;\n\t\t\tcase kScaleXYZ:\n\t\t\t\tscaleXYZ();\n\t\t\t\tbreak;\n\t\t\tcase kScaleXY:\n\t\t\t\tscaleInPlane({ 0, 0, 1 });\n\t\t\t\tbreak;\n\t\t\tcase kScaleXZ:\n\t\t\t\tscaleInPlane({ 0, 1, 0 });\n\t\t\t\tbreak;\n\t\t\tcase kScaleYZ:\n\t\t\t\tscaleInPlane({ 1, 0, 0 });\n\t\t\t\tbreak;\n\t\t\tcase kTranslateC:\n\t\t\t\tTranslationTool::translateInPlane(screen.camera.cframe.rotation * Vec3(0, 0, 1), clamp, false);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tvoid ScaleTool::scaleAlongLine(const Vec3& direction) {\n\t\t// Closest point on ray1 (A + s * a) from ray2 (B + t * b). Ray1 is the ray from the parts' center in the direction of the edit tool, ray2 is the mouse ray. Directions a and b are normalized. Only s is calculated.\n\t\tif (SelectionTool::selection.empty())\n\t\t\treturn;\n\n\t\tstd::optional<GlobalCFrame> cframe = SelectionTool::selection.getCFrame();\n\t\tif (!cframe.has_value())\n\t\t\treturn;\n\n\t\t// Rotate direction according to model rotation\n\t\tRay ray1 = { cframe->getPosition(), cframe->localToRelative(direction) };\n\t\tRay ray2 = SelectionTool::ray;\n\n\t\t// Calculate s\n\t\tVec3 c = ray2.origin - ray1.origin;\n\t\tdouble ab = ray1.direction * ray2.direction;\n\t\tdouble bc = ray2.direction * c;\n\t\tdouble ac = ray1.direction * c;\n\t\tdouble s = (ac - ab * bc) / (1.0 - ab * ab);\n\n\t\t// Translation, relative to tool intersection\n\t\tVec3 translationCorrection = ray1.direction * (ray1.direction * (*SelectionTool::selectedPoint - cframe->getPosition()));\n\t\tVec3 translation = s * ray1.direction - translationCorrection;\n\n\t\t*SelectionTool::selectedPoint += translation;\n\t\tSelectionTool::selection.scale(Vec3(1.0, 1.0, 1.0) + translation);\n\t}\n\n\tvoid ScaleTool::scaleInPlane(const Vec3& normal) {\n\t\tif (SelectionTool::selection.empty())\n\t\t\treturn;\n\t\t\n\t\tstd::optional<GlobalCFrame> cframe = SelectionTool::selection.getCFrame();\n\t\tif (!cframe.has_value())\n\t\t\treturn;\n\n\t\tVec3 direction = cframe->localToRelative(normal);\n\t\tdouble distance = (*SelectionTool::selectedPoint - SelectionTool::ray.origin) * direction / (SelectionTool::ray.direction * direction);\n\t\tPosition planeIntersection = SelectionTool::ray.origin + SelectionTool::ray.direction * distance;\n\n\t\tVec3 translation = planeIntersection - *SelectionTool::selectedPoint;\n\t\t*SelectionTool::selectedPoint += translation;\n\n\t\tSelectionTool::selection.scale(Vec3(1.0, 1.0, 1.0) + translation);\n\t\t\n\t}\n\n\tvoid ScaleTool::scaleXYZ() {\n\t\tif (SelectionTool::selection.empty())\n\t\t\treturn;\n\n\t\tstd::optional<GlobalCFrame> cframe = SelectionTool::selection.getCFrame();\n\t\tif (!cframe.has_value())\n\t\t\treturn;\n\n\t\tstd::optional<Shape> hitbox = SelectionTool::selection.getHitbox();\n\t\tif (!hitbox.has_value())\n\t\t\treturn;\n\t\t\n\t\tVec3 direction = normalize(Vec3(screen.camera.cframe.position - cframe->getPosition()));\n\t\tdouble distance = (*SelectionTool::selectedPoint - SelectionTool::ray.origin) * direction / (SelectionTool::ray.direction * direction);\n\t\tPosition planeIntersection = SelectionTool::ray.origin + SelectionTool::ray.direction * distance;\n\n\t\tdouble amount = lengthSquared(castPositionToVec3(*SelectionTool::selectedPoint)) - lengthSquared(castPositionToVec3(planeIntersection));\n\t\t*SelectionTool::selectedPoint = planeIntersection;\n\t\t\n\t\t\n\t\tSelectionTool::selection.scale({ 1.0 + amount, 1.0 + amount, 1.0 + amount });\n\t}\n\n\n}\n"
  },
  {
    "path": "application/picker/tools/scaleTool.h",
    "content": "#pragma once\n\n#include \"../graphics/glfwUtils.h\"\n#include \"../engine/event/mouseEvent.h\"\n#include \"../engine/tool/stateTool.h\"\n#include \"ecs/components.h\"\n\nnamespace P3D::Application {\n\nclass ScaleTool : public Engine::StateTool {\nprivate:\n\tenum SelectionToolStatus : Engine::ToolStatus {\n\t\tkIdle    = 0,\n\t\tkScaleX = 1,\n\t\tkScaleY = 2,\n\t\tkScaleZ = 3,\n\t\tkScaleXYZ = 4,\n\t\tkScaleXY = 5,\n\t\tkScaleXZ = 6,\n\t\tkScaleYZ = 7,\n\t\tkTranslateC = 8\n\t};\n\n\tbool active = false;\n\npublic:\n\tDEFINE_TOOL(\"Scale\", \"Scale entities by using the handles\", Graphics::GLFW::Cursor::ARROW);\n\n\t~ScaleTool() = default;\t\n\n\tvoid onRegister() override;\n\tvoid onDeregister() override;\n\tvoid onRender() override;\n\tvoid onUpdate() override;\n\tvoid onEvent(Engine::Event& event) override;\n\n\tbool onMousePress(Engine::MousePressEvent& event);\n\tbool onMouseRelease(Engine::MouseReleaseEvent& event);\n\tbool onMouseDrag(Engine::MouseDragEvent& event);\n\n\tvoid scaleAlongLine(const Vec3& direction);\n\tvoid scaleInPlane(const Vec3& normal);\n\tvoid scaleXYZ();\n};\n\n};"
  },
  {
    "path": "application/picker/tools/selectionTool.cpp",
    "content": "#include \"core.h\"\n\n#include \"selectionTool.h\"\n\n#include \"../engine/event/event.h\"\n#include \"../engine/event/mouseEvent.h\"\n#include \"../graphics/resource/textureResource.h\"\n#include \"../util/resource/resourceManager.h\"\n\n#include \"../../view/screen.h\"\n#include \"../../application.h\"\n#include \"../../shader/shaders.h\"\n#include \"../../input/standardInputHandler.h\"\n#include \"../../ecs/components.h\"\n#include \"../../worlds.h\"\n\n#include <Physics3D/boundstree/filters/rayIntersectsBoundsFilter.h>\n#include <Physics3D/threading/upgradeableMutex.h>\n\n#include <optional>\n\nnamespace P3D::Graphics {\nclass TextureResource;\n}\n\nnamespace P3D::Application {\n\nRay SelectionTool::ray;\nVec2 SelectionTool::mouse;\nSelection SelectionTool::selection;\nstd::optional<Position> SelectionTool::selectedPoint;\nstd::optional<Position> SelectionTool::intersectedPoint;\n\nvoid SelectionTool::onRegister() {\n\tauto path = \"../res/textures/icons/\" + getName() + \".png\";\n\tResourceManager::add<TextureResource>(getName(), path);\n}\n\nvoid SelectionTool::onDeregister() {\n\t// Remove texture\n}\n\nvoid SelectionTool::onRender() {\n\tusing namespace Graphics;\n}\n\nvoid SelectionTool::onEvent(Engine::Event& event) {\n\tusing namespace Engine;\n\n\tEventDispatcher dispatcher(event);\n\tdispatcher.dispatch<MousePressEvent>(EVENT_BIND(SelectionTool::onMousePress));\n}\n\nbool SelectionTool::onMousePress(Engine::MousePressEvent& event) {\n\tusing namespace Engine;\n\n\tif (event.getButton() != Mouse::LEFT)\n\t\treturn false;\n\n\t// Multi selection check\n\tif (!event.getModifiers().isCtrlPressed())\n\t\tclear();\n\n\t// Single selection\n\tauto intersectedEntity = getIntersectedEntity();\n\n\tif (intersectedEntity.has_value())\n\t\ttoggle(intersectedEntity->first);\n\t\n\treturn false;\n}\n\nvoid SelectionTool::clear() {\n\tselection.clear();\n}\n\nvoid SelectionTool::toggle(const Engine::Registry64::entity_type& entity) {\n\tselection.toggle(entity);\n}\n\nvoid SelectionTool::select(const Engine::Registry64::entity_type& entity) {\n\tselection.add(entity);\n}\n\nvoid SelectionTool::single(const Engine::Registry64::entity_type& entity) {\n\tselection.clear();\n\tselection.add(entity);\n}\n\nstd::optional<std::pair<Engine::Registry64::entity_type, Position>> SelectionTool::getIntersectedCollider() {\n\tEngine::Registry64::entity_type intersectedEntity = 0;\n\tdouble closestIntersectionDistance = std::numeric_limits<double>::max();\n\n\t{\n\t\tauto view = screen.registry.view<Comp::Hitbox, Comp::Transform, Comp::Collider>();\n\t\tstd::shared_lock<UpgradeableMutex> worldReadLock(*screen.worldMutex);\n\t\tfor (auto entity : view) {\n\t\t\tIRef<Comp::Hitbox> hitbox = view.get<Comp::Hitbox>(entity);\n\t\t\tIRef<Comp::Transform> transform = view.get<Comp::Transform>(entity);\n\t\t\tstd::optional<double> distance = intersect(transform->getCFrame(), hitbox);\n\t\t\tif (distance.has_value() && distance < closestIntersectionDistance) {\n\t\t\t\tclosestIntersectionDistance = *distance;\n\t\t\t\tintersectedEntity = entity;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (intersectedEntity == 0)\n\t\treturn std::nullopt;\n\n\tPosition intersection = ray.origin + ray.direction * closestIntersectionDistance;\n\n\treturn std::make_pair(intersectedEntity, intersection);\n}\n\nstd::optional<std::pair<Engine::Registry64::entity_type, Position>> SelectionTool::getIntersectedEntity() {\n\tEngine::Registry64::entity_type intersectedEntity = Engine::Registry64::null_entity;\n\tdouble closestIntersectionDistance = std::numeric_limits<double>::max();\n\n\t{\n\t\tauto view = screen.registry.view<Comp::Hitbox, Comp::Transform>();\n\t\tstd::shared_lock<UpgradeableMutex> worldReadLock(*screen.worldMutex);\n\t\tfor(auto entity : view) {\n\t\t\tIRef<Comp::Hitbox> hitbox = view.get<Comp::Hitbox>(entity);\n\t\t\tIRef<Comp::Transform> transform = view.get<Comp::Transform>(entity);\n\t\t\tstd::optional<double> distance = intersect(transform->getCFrame(), hitbox);\n\t\t\tif(distance.has_value() && distance < closestIntersectionDistance) {\n\t\t\t\tclosestIntersectionDistance = *distance;\n\t\t\t\tintersectedEntity = entity;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (intersectedEntity == 0)\n\t\treturn std::nullopt;\n\n\tPosition intersection = ray.origin + ray.direction * closestIntersectionDistance;\n\t\n\treturn std::make_pair(intersectedEntity, intersection);\n}\n\nstd::optional<double> SelectionTool::intersect(const GlobalCFrame& cframe, IRef<Comp::Hitbox> hitbox) {\n\tShape shape = hitbox->getShape();\n\tVec3 relativePosition = cframe.getPosition() - ray.origin;\n\tdouble maxRadius = shape.getMaxRadius();\n\tif (pointToLineDistanceSquared(ray.direction, relativePosition) > maxRadius * maxRadius)\n\t\treturn std::nullopt;\n\n\tRayIntersectBoundsFilter filter(ray);\n\tif (hitbox->isPartAttached())\n\t\tif (!filter(*hitbox->getPart()))\n\t\t\treturn std::nullopt;\n\n\tdouble distance = shape.getIntersectionDistance(cframe.globalToLocal(ray.origin), cframe.relativeToLocal(ray.direction));\n\n\tif (distance < 0.0 || distance == std::numeric_limits<double>::max())\n\t\treturn std::nullopt;\n\n\treturn distance;\n}\n\nstd::optional<double> SelectionTool::intersect(const GlobalCFrame& cframe, const Shape& shape) {\n\tVec3 relativePosition = cframe.getPosition() - ray.origin;\n\tdouble maxRadius = shape.getMaxRadius();\n\tif (pointToLineDistanceSquared(ray.direction, relativePosition) > maxRadius * maxRadius)\n\t\treturn std::nullopt;\n\n\tdouble distance = shape.getIntersectionDistance(cframe.globalToLocal(ray.origin), cframe.relativeToLocal(ray.direction));\n\tif (distance == 0.0 || distance == std::numeric_limits<double>::max())\n\t\treturn std::nullopt;\n\n\treturn distance;\n}\n\nstd::optional<double> SelectionTool::intersect(const GlobalCFrame& cframe, const ExtendedTriangleMesh& shape) {\n\tVec3 relativePosition = cframe.getPosition() - ray.origin;\n\t//double maxRadius = shape.getMaxRadius();\n\t//if (pointToLineDistanceSquared(ray.direction, relativePosition) > maxRadius * maxRadius)\n\t//\treturn std::nullopt;\n\t\n\tdouble distance = shape.getIntersectionDistance(cframe.globalToLocal(ray.origin), cframe.relativeToLocal(ray.direction));\n\tif (distance == 0.0 || distance == std::numeric_limits<double>::max())\n\t\treturn std::nullopt;\n\n\treturn distance;\n}\n\n};\n"
  },
  {
    "path": "application/picker/tools/selectionTool.h",
    "content": "#pragma once\n\n#include \"../graphics/glfwUtils.h\"\n#include \"../engine/event/mouseEvent.h\"\n#include \"../engine/tool/stateTool.h\"\n#include \"../engine/ecs/registry.h\"\n#include <Physics3D/math/ray.h>\n#include <Physics3D/math/linalg/vec.h>\n#include \"../../ecs/components.h\"\n#include \"../selection.h\"\n#include <optional>\n\nstruct ExtendedPart;\n\nnamespace P3D::Application {\n\nclass SelectionTool : public Engine::Tool {\npublic:\n\tDEFINE_TOOL(\"Select\", \"Selects one or multiple entities.\", Graphics::GLFW::Cursor::ARROW);\n\t\n\tstatic Ray ray;\n\tstatic Vec2 mouse;\n\tstatic Selection selection;\n\tstatic std::optional<Position> selectedPoint;\n\tstatic std::optional<Position> intersectedPoint;\n\n\t~SelectionTool() override = default;\t\n\n\tvoid onRegister() override;\n\tvoid onDeregister() override;\n\tvoid onRender() override;\n\tvoid onEvent(Engine::Event& event) override;\n\n\tstatic bool onMousePress(Engine::MousePressEvent& event);\n\n\tstatic void clear();\n\tstatic void select(const Engine::Registry64::entity_type& entity);\n\tstatic void toggle(const Engine::Registry64::entity_type& entity);\n\tstatic void single(const Engine::Registry64::entity_type& entity);\n\n\tstatic std::optional<std::pair<Engine::Registry64::entity_type, Position>> getIntersectedEntity();\n\tstatic std::optional<std::pair<Engine::Registry64::entity_type, Position>> getIntersectedCollider();\n\tstatic std::optional<double> intersect(const GlobalCFrame& cframe, IRef<Comp::Hitbox> hitbox);\n\tstatic std::optional<double> intersect(const GlobalCFrame& cframe, const Shape& shape);\n\tstatic std::optional<double> intersect(const GlobalCFrame& cframe, const Graphics::ExtendedTriangleMesh& shape);\n};\n\n};"
  },
  {
    "path": "application/picker/tools/springLinkTool.cpp",
    "content": "#include \"core.h\"\n#include \"springLinkTool.h\"\n\n#include \"application.h\"\n#include \"selectionTool.h\"\n#include \"graphics/resource/textureResource.h\"\n#include \"Physics3D/softlinks/springLink.h\"\n#include \"util/resource/resourceManager.h\"\n#include \"view/screen.h\"\n\nnamespace P3D::Application {\n\nvoid SpringLinkTool::onRegister() {\n\tauto path = \"../res/textures/icons/\" + getName() + \".png\";\n\tResourceManager::add<Graphics::TextureResource>(getName(), path);\n}\n\nvoid SpringLinkTool::onDeregister() {\n\t// Remove texture\n}\n\nvoid SpringLinkTool::onSelect() {\n\tlinkSelection();\n}\n\nvoid SpringLinkTool::linkSelection() {\n\tif (SelectionTool::selection.size() < 2)\n\t\treturn;\n\n\tIRef<Comp::Collider> parentCollider = screen.registry.get<Comp::Collider>(SelectionTool::selection[0]);\n\tif (parentCollider.invalid())\n\t\treturn;\n\n\tfor (Engine::Registry64::entity_type& entity : SelectionTool::selection) {\n\t\tIRef<Comp::Collider> childCollider = screen.registry.get<Comp::Collider>(entity);\n\t\tif (childCollider.invalid())\n\t\t\tcontinue;\n\n\t\tif (childCollider->part == parentCollider->part)\n\t\t\tcontinue;\n\n\t\tCFrame cframe = parentCollider->part->getCFrame().globalToLocal(childCollider->part->getCFrame());\n\t\tAttachedPart part1 { cframe, parentCollider->part };\n\t\tAttachedPart part2 { CFrame(), childCollider->part };\n\t\tSpringLink* link = new SpringLink(part1, part2, 5.0, 1.0);\n\n\t\tscreen.worldMutex->lock();\n\t\ttry {\n\t\t\tworld.addLink(link);\n\t\t} catch (std::invalid_argument& error) {\n\t\t\tLog::debug(error.what());\n\t\t}\n\t\tscreen.worldMutex->unlock();\n\t}\n}\n\n}\n"
  },
  {
    "path": "application/picker/tools/springLinkTool.h",
    "content": "#pragma once\n\n#include \"engine/tool/buttonTool.h\"\n#include \"graphics/glfwUtils.h\"\n\nnamespace P3D::Application {\n\nclass SpringLinkTool : public Engine::ButtonTool {\npublic:\n\tDEFINE_TOOL(\"Spring Link\", \"Select two entities to create a spring link beteen.\", Graphics::GLFW::Cursor::CROSSHAIR);\n\n\t~SpringLinkTool() override = default;\n\n\tvoid onRegister() override;\n\tvoid onDeregister() override;\n\tvoid onSelect() override;\n\n\tstatic void linkSelection();\n};\n\n}\n"
  },
  {
    "path": "application/picker/tools/toolSpacing.h",
    "content": "#pragma once\n#include \"engine/tool/tool.h\"\n#include \"graphics/glfwUtils.h\"\n\nnamespace P3D::Application {\n\t\n\tclass ToolSpacing : public Engine::Tool {\n\tpublic:\n\t\tDEFINE_TOOL(\"Spacing\", \"\", Graphics::GLFW::Cursor::CROSSHAIR);\n\t};\n}\n"
  },
  {
    "path": "application/picker/tools/translationTool.cpp",
    "content": "#include \"core.h\"\n\n#include \"translationTool.h\"\n\n#include \"worlds.h\"\n#include \"application.h\"\n#include \"selectionTool.h\"\n#include \"view/screen.h\"\n#include \"shader/shaders.h\"\n\n#include <Physics3D/geometry/shapeLibrary.h>\n#include <Physics3D/math/rotation.h>\n#include <Physics3D/threading/upgradeableMutex.h>\n#include \"../graphics/extendedTriangleMesh.h\"\n#include \"../graphics/mesh/primitive.h\"\n#include \"../graphics/mesh/indexedMesh.h\"\n#include \"../graphics/resource/textureResource.h\"\n#include \"../util/resource/resourceManager.h\"\n#include \"imgui/imgui.h\"\n#include \"input/standardInputHandler.h\"\n\n#define PICKER_STRENGTH 100\n#define PICKER_SPEED_STRENGTH 12\n\nnamespace P3D::Application {\n\t\n\tconstexpr static Rotation transformations[] {\n\t\tRotation::Predefined::Y_90,\t// X, XY\n\t\tRotation::Predefined::X_270, // Y\t\t\t\n\t\tRotation::Predefined::IDENTITY, // Z, YZ\n\t\tRotation::Predefined::Z_270 // XZ\n\t};\n\n\tconstexpr static std::size_t mapping[] {\n\t\t0, // X\n\t\t1, // Y\n\t\t2, // Z\n\t\t2, // C\n\t\t0, // XY\n\t\t3, // XZ\n\t\t2  // YZ\n\t};\n\n\tstatic std::optional<Position> startPosition;\n\n\tstatic URef<LinePrimitive> deltaLine = nullptr;\n\tstatic URef<LinePrimitive> infiniteLine = nullptr;\n\n\tstatic URef<IndexedMesh> quadMesh;\n\tstatic ExtendedTriangleMesh quadShape;\n\tstatic URef<IndexedMesh> centerMesh;\n\tstatic ExtendedTriangleMesh centerShape;\n\tstatic URef<IndexedMesh> handleMesh;\n\tstatic ExtendedTriangleMesh handleShape;\n\n\tMagnetForce TranslationTool::magnet(PICKER_STRENGTH, PICKER_SPEED_STRENGTH);\n\n\tstatic Polyhedron createArrow(float arrowHeadLength, float arrowHeadRadius, float stickRadius) {\n\t\tVec2f contour[] {\n\t\t\t{ 0.0f, stickRadius },\n\t\t\t{ 1.0f - arrowHeadLength, stickRadius },\n\t\t\t{ 1.0f - arrowHeadLength, arrowHeadRadius }\n\t\t};\n\t\t\n\t\treturn ShapeLibrary::createRevolvedShape(0.0f, contour, 3, 1.0f, 24);\n\t}\n\t\n\tvoid TranslationTool::onRegister() {\n\t\tusing namespace Graphics;\n\n\t\t// Load icon\n\t\tstd::string path = \"../res/textures/icons/\" + getName() + \".png\";\n\t\tResourceManager::add<TextureResource>(getName(), path);\n\n\t\t// Create alignment line\n\t\tdeltaLine = std::make_unique<LinePrimitive>();\n\t\tinfiniteLine = std::make_unique<LinePrimitive>();\n\t\tinfiniteLine->resize(Vec3f(0, 0, -100000), Vec3f(0, 0, 100000));\n\t\t\n\t\t// Create handle shapes\n\t\thandleShape = ExtendedTriangleMesh::generateSplitNormalsShape(createArrow(0.3f, 0.07f, 0.03f));\n\t\thandleMesh = std::make_unique<IndexedMesh>(handleShape);\n\t\tcenterShape = ExtendedTriangleMesh::generateSmoothNormalsShape(ShapeLibrary::createSphere(0.13f, 3));\n\t\tcenterMesh = std::make_unique<IndexedMesh>(centerShape);\n\t\tquadShape = ExtendedTriangleMesh::generateSplitNormalsShape(ShapeLibrary::createBox(0.02f, 0.25f, 0.25f).translated({0, 0.5, 0.5}));\n\t\tquadMesh = std::make_unique<IndexedMesh>(quadShape);\n\n\t\t// Set idle status\n\t\tsetToolStatus(kIdle);\n\n\t\tscreen.world->addExternalForce(&TranslationTool::magnet);\n\t}\n\n\tvoid TranslationTool::onDeregister() {\n\t\t// Todo remove icon\n\t\t// Todo remove line\n\n\t\tcenterMesh->close();\n\t\thandleMesh->close();\n\t\tquadMesh->close();\n\t}\n\n\tvoid TranslationTool::onRender() {\n\t\tusing namespace Graphics;\n\n\t\tstd::optional<GlobalCFrame> cframe = SelectionTool::selection.getCFrame();\n\t\tif (!cframe.has_value())\n\t\t\treturn;\n\n\t\t//bool local = !ImGui::GetIO().KeyCtrl;\n\t\tbool local = handler->keys[Engine::Keyboard::KEY_LEFT_CONTROL.getCode()];\n\t\tif (!local)\n\t\t\tcframe = GlobalCFrame(cframe->position);\n\n\t\tstd::optional<GlobalCFrame> rootCFrame;\n\t\tif (SelectionTool::selection.isSingleSelection()) {\n\t\t\tIRef<Comp::Transform> rootTransform = screen.registry.get<Comp::Transform>(SelectionTool::selection.first().value());\n\t\t\tif (rootTransform.valid() && rootTransform->hasOffset())\n\t\t\t\trootCFrame = rootTransform->getRootCFrame();\n\t\t}\n\n\t\tMat4f model = cframe->asMat4();\n\t\tMat4f modelX = model * joinDiagonal(Mat3f(transformations[0].asRotationMatrix()), 1.0f);\n\t\tMat4f modelY = model * joinDiagonal(Mat3f(transformations[1].asRotationMatrix()), 1.0f);\n\t\tMat4f modelZ = model * joinDiagonal(Mat3f(transformations[2].asRotationMatrix()), 1.0f);\n\t\tMat4f modelXZ = model * joinDiagonal(Mat3f(transformations[3].asRotationMatrix()), 1.0f);\n\n\t\tauto status = getToolStatus();\t\t\n\t\tif (status == kTranslateX || status == kTranslateXY || status == kTranslateXZ) {\n\t\t\tShaders::maskShader->updateModel(modelX);\n\t\t\tShaders::maskShader->updateColor(Colors::RGB_R);\n\t\t\tinfiniteLine->render();\n\t\t}\n\n\t\tif (status == kTranslateY || status == kTranslateXY || status == kTranslateYZ) {\n\t\t\tShaders::maskShader->updateModel(modelY);\n\t\t\tShaders::maskShader->updateColor(Colors::RGB_G);\n\t\t\tinfiniteLine->render();\n\t\t}\n\n\t\tif (status == kTranslateZ || status == kTranslateXZ || status == kTranslateYZ) {\n\t\t\tShaders::maskShader->updateModel(modelZ);\n\t\t\tShaders::maskShader->updateColor(Colors::RGB_B);\n\t\t\tinfiniteLine->render();\n\t\t}\n\n\t\t// Center\n\t\tShaders::basicShader->updateModel(model);\n\t\tShaders::basicShader->updateMaterial(Graphics::Comp::Material(Colors::WHITE));\n\t\tcenterMesh->render();\n\n\t\t// X, XY\n\t\tShaders::basicShader->updateMaterial(Graphics::Comp::Material(Colors::RGB_R));\n\t\tShaders::basicShader->updateModel(modelX);   \n\t\thandleMesh->render();\n\t\tShaders::basicShader->updateMaterial(Graphics::Comp::Material(Colors::RGB_B));\n\t\tquadMesh->render();\n\t\t\n\t\t// Y, XZ\n\t\tShaders::basicShader->updateModel(modelY);\n\t\tShaders::basicShader->updateMaterial(Graphics::Comp::Material(Colors::RGB_G));\n\t\thandleMesh->render();\n\t\tShaders::basicShader->updateModel(modelXZ);\n\t\tquadMesh->render();\n\n\t\t// Z, YZ\n\t\tShaders::basicShader->updateMaterial(Graphics::Comp::Material(Colors::RGB_B));\n\t\tShaders::basicShader->updateModel(modelZ);\n\t\thandleMesh->render();\n\t\tShaders::basicShader->updateMaterial(Graphics::Comp::Material(Colors::RGB_R));\n\t\tquadMesh->render();\n\n\t\t// Root XYZ\n\t\tif (rootCFrame.has_value()) {\n\t\t\tMat4f rootModel = rootCFrame.value().asMat4WithPreScale(DiagonalMat3::IDENTITY() * 0.25);\n\t\t\tMat4f rootModelX = rootModel * joinDiagonal(Mat3f(transformations[0].asRotationMatrix()), 1.0f);\n\t\t\tMat4f rootModelY = rootModel * joinDiagonal(Mat3f(transformations[1].asRotationMatrix()), 1.0f);\n\t\t\tMat4f rootModelZ = rootModel * joinDiagonal(Mat3f(transformations[2].asRotationMatrix()), 1.0f);\n\t\t\t\n\t\t\tShaders::basicShader->updateMaterial(Graphics::Comp::Material(Colors::WHITE));\n\t\t\tShaders::basicShader->updateModel(rootModel);\n\t\t\tcenterMesh->render();\n\t\t\tShaders::basicShader->updateMaterial(Graphics::Comp::Material(Colors::RGB_R));\n\t\t\tShaders::basicShader->updateModel(rootModelX);\n\t\t\thandleMesh->render();\n\t\t\tShaders::basicShader->updateMaterial(Graphics::Comp::Material(Colors::RGB_G));\n\t\t\tShaders::basicShader->updateModel(rootModelY);\n\t\t\thandleMesh->render();\n\t\t\tShaders::basicShader->updateMaterial(Graphics::Comp::Material(Colors::RGB_B));\n\t\t\tShaders::basicShader->updateModel(rootModelZ);\n\t\t\thandleMesh->render();\n\t\t\tShaders::basicShader->updateModel(Mat4::IDENTITY());\n\t\t\tShaders::basicShader->updateMaterial(Graphics::Comp::Material(Colors::GRAY));\n\t\t\tdeltaLine->resize(castPositionToVec3f(rootCFrame.value().position), castPositionToVec3f(cframe.value().position));\n\t\t\tdeltaLine->render();\n\t\t}\n\n\t\t// Delta line\n\t\tif (startPosition.has_value() && active) {\n\t\t\tShaders::basicShader->updateMaterial(Graphics::Comp::Material(Colors::ORANGE));\n\t\t\tShaders::basicShader->updateModel(GlobalCFrame(startPosition.value()), DiagonalMat3::IDENTITY() * 0.5);\n\t\t\tVec3f doubleRelativePosition = (castPositionToVec3f(cframe->position) - castPositionToVec3f(startPosition.value())) * 2.0f;\n\t\t\tdeltaLine->resize(Vec3f(), doubleRelativePosition);\n\t\t\tdeltaLine->render();\n\t\t\tcenterMesh->render();\n\t\t}\n\t}\n\n\tvoid TranslationTool::onUpdate() {\n\t\t// Keep the tool status if the tool is active\n\t\tif (this->active)\n\t\t\treturn;\n\n\t\t// Reset tool status\n\t\tsetToolStatus(kIdle);\n\t\tSelectionTool::intersectedPoint = std::nullopt;\n\n\t\t// The intersection distance to find\n\t\tstd::optional<double> closestIntersectionDistance;\n\n\t\t// Look for edit tool intersections if the selection has a cframe\n\t\tstd::optional<GlobalCFrame> cframe = SelectionTool::selection.getCFrame();\n\t\tif (!cframe.has_value())\n\t\t\treturn;\n\n\t\tbool local = !handler->keys[Engine::Keyboard::KEY_LEFT_CONTROL.getCode()];\n\t\tif (!local)\n\t\t\tcframe = GlobalCFrame(cframe->position);\n\t\t\n\t\tGlobalCFrame frame = *cframe;\n\t\tfor (char status = kTranslateX; status <= kTranslateYZ; status++) {\n\t\t\tExtendedTriangleMesh shape;\n\t\t\tswitch (status) {\n\t\t\t\tcase kTranslateC:\n\t\t\t\t\tshape = centerShape;\n\t\t\t\t\tbreak;\n\t\t\t\tcase kTranslateX:\n\t\t\t\tcase kTranslateY:\n\t\t\t\tcase kTranslateZ:\n\t\t\t\t\tshape = handleShape;\n\t\t\t\t\tbreak;\n\t\t\t\tcase kTranslateXY:\n\t\t\t\tcase kTranslateXZ:\n\t\t\t\tcase kTranslateYZ:\n\t\t\t\t\tshape = quadShape;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tframe.rotation = cframe->getRotation() * transformations[mapping[status - 1]];\n\t\t\tstd::optional<double> distance = SelectionTool::intersect(frame, shape);\n\n\t\t\tif (!distance.has_value())\n\t\t\t\tcontinue;\n\n\t\t\tif (!closestIntersectionDistance.has_value() || 0.0 < distance && distance < closestIntersectionDistance) {\n\t\t\t\tclosestIntersectionDistance = distance;\n\t\t\t\tsetToolStatus(status);\n\t\t\t}\n\t\t}\n\n\t\tif (closestIntersectionDistance.has_value())\n\t\t\tSelectionTool::intersectedPoint = SelectionTool::ray.origin + SelectionTool::ray.direction * *closestIntersectionDistance;\n\t}\n\n\tvoid TranslationTool::onEvent(Engine::Event& event) {\n\t\tusing namespace Engine;\n\n\t\tEventDispatcher dispatcher(event);\n\t\tdispatcher.dispatch<MousePressEvent>(EVENT_BIND(TranslationTool::onMousePress));\n\t\tdispatcher.dispatch<MouseReleaseEvent>(EVENT_BIND(TranslationTool::onMouseRelease));\n\t\tdispatcher.dispatch<MouseDragEvent>(EVENT_BIND(TranslationTool::onMouseDrag));\n\t}\n\n\tbool TranslationTool::onMousePress(Engine::MousePressEvent& event) {\n\t\tusing namespace Engine;\n\t\tif (event.getButton() != Mouse::LEFT)\n\t\t\treturn false;\n\n\t\t// Auto select an entity if the selection status is idle, in that case no edit tool or entity is intersected\n\t\tauto status = getToolStatus();\n\t\tif (status == kIdle) {\n\t\t\t// Find the intersected entity\n\t\t\tauto intersectedEntity = SelectionTool::getIntersectedEntity();\n\t\t\t\t\t\n\t\t\t// If control is pressed, add to selection, but don't change the tool status \n\t\t\tif (event.getModifiers().isCtrlPressed()) {\n\t\t\t\t// No intersection causes nothing\n\t\t\t\tif (!intersectedEntity.has_value())\n\t\t\t\t\treturn false;\n\t\t\t} else {\n\t\t\t\t// Clear the selection before selecting the new entity\n\t\t\t\tSelectionTool::selection.clear();\n\n\t\t\t\t// No intersection causes only deselection\n\t\t\t\tif (!intersectedEntity.has_value())\n\t\t\t\t\treturn false;\n\t\t\t\t\n\t\t\t\t// If an intersection is found, select it and behave like center edit\n\t\t\t\tsetToolStatus(kTranslateC);\n\t\t\t\tSelectionTool::intersectedPoint = intersectedEntity->second;\n\t\t\t}\n\n\t\t\tSelectionTool::select(intersectedEntity->first);\n\t\t}\n\n\t\t// Set the selected point \n\t\tSelectionTool::selectedPoint = SelectionTool::intersectedPoint;\n\n\t\t// Set start position\n\t\tstd::optional<GlobalCFrame> selectionCFrame = SelectionTool::selection.getCFrame();\n\t\tstartPosition = selectionCFrame.has_value() ? std::make_optional(selectionCFrame->position) : std::nullopt;\n\n\t\t// Set edit status to active\n\t\tthis->active = true;\n\n\t\treturn false;\n\t}\n\n\tbool TranslationTool::onMouseRelease(Engine::MouseReleaseEvent& event) {\n\t\tusing namespace Engine;\n\t\tif (event.getButton() != Mouse::LEFT)\n\t\t\treturn false;\n\n\t\t// Reset magnet point\n\t\tthis->magnet.selectedPart = nullptr;\n\n\t\t// Set inactive\n\t\tthis->active = false;\n\n\t\t// Reset old position\n\t\tstartPosition = std::nullopt;\n\n\t\treturn false;\n\t}\n\n\tbool TranslationTool::onMouseDrag(Engine::MouseDragEvent& event) {\n\t\tif (!this->active)\n\t\t\treturn false;\n\t\t\n\t\tauto status = getToolStatus();\n\t\tif (status == kIdle)\n\t\t\treturn false;\n\n\t\tbool clamp = handler->keys[Engine::Keyboard::KEY_LEFT_ALT.getCode()];\n\t\tbool local = !handler->keys[Engine::Keyboard::KEY_LEFT_CONTROL.getCode()];\n\n\t\tstd::unique_lock<UpgradeableMutex> worldWriteLock(*screen.worldMutex);\n\t\tswitch (status) {\n\t\t\tcase kTranslateX:\n\t\t\t\ttranslateAlongLine({ 1, 0, 0 }, clamp, local);\n\t\t\t\tbreak;\n\t\t\tcase kTranslateY:\n\t\t\t\ttranslateAlongLine({ 0, 1, 0 }, clamp, local);\n\t\t\t\tbreak;\n\t\t\tcase kTranslateZ:\n\t\t\t\ttranslateAlongLine({ 0, 0, 1 }, clamp, local);\n\t\t\t\tbreak;\n\t\t\tcase kTranslateC:\n\t\t\t\ttranslateInPlane(screen.camera.cframe.rotation * Vec3(0, 0, 1), clamp, false);\n\t\t\t\tbreak;\n\t\t\tcase kTranslateXY:\n\t\t\t\ttranslateInPlane({ 0, 0, 1 }, clamp, local);\n\t\t\t\tbreak;\n\t\t\tcase kTranslateXZ:\n\t\t\t\ttranslateInPlane({ 0, 1, 0 }, clamp, local);\n\t\t\t\tbreak;\n\t\t\tcase kTranslateYZ:\n\t\t\t\ttranslateInPlane({ 1, 0, 0 }, clamp, local);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tvoid TranslationTool::translateInPlane(const Vec3& normal, bool clamp, bool local) {\n\t\tif (SelectionTool::selection.empty())\n\t\t\treturn;\n\n\t\tVec3 direction;\n\t\tstd::optional<GlobalCFrame> cframe = SelectionTool::selection.getCFrame();\n\t\tif (local) {\n\t\t\tif (!cframe.has_value())\n\t\t\t\treturn;\n\n\t\t\tdirection = cframe->getRotation().localToGlobal(normal);\n\t\t} else {\n\t\t\tdirection = normal;\n\t\t}\n\t\t\n\t\tdouble distance = (*SelectionTool::selectedPoint - SelectionTool::ray.origin) * direction / (SelectionTool::ray.direction * direction);\n\t\tPosition planeIntersection = SelectionTool::ray.origin + SelectionTool::ray.direction * distance;\n\n\t\tif (isPaused()) {\n\t\t\tVec3 translation = planeIntersection - *SelectionTool::selectedPoint;\n\n\t\t\t// Clamp to grid\n\t\t\tif (clamp) {\n\t\t\t\tif (local) {\n\t\t\t\t\tVec3 localTranslation = cframe->getRotation().globalToLocal(translation);\n\t\t\t\t\tlocalTranslation = Vec3(round(localTranslation.x), round(localTranslation.y), round(localTranslation.z));\n\t\t\t\t\ttranslation = cframe->getRotation().localToGlobal(localTranslation);\n\t\t\t\t} else {\n\t\t\t\t\tVec3 resultingPosition = castPositionToVec3(cframe->translated(translation).getPosition());\n\t\t\t\t\tVec3 clampedPosition = Vec3(round(resultingPosition.x), round(resultingPosition.y), round(resultingPosition.z));\n\t\t\t\t\tVec3 difference = resultingPosition - clampedPosition;\n\t\t\t\t\ttranslation -= difference;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t*SelectionTool::selectedPoint += translation;\n\t\t\t\n\t\t\tSelectionTool::selection.translate(translation);\n\t\t} else {\n\t\t\t// Only allow single selection\n\t\t\tif (SelectionTool::selection.size() > 1)\n\t\t\t\treturn;\n\n\t\t\tIRef<Comp::Transform> transform = screen.registry.get<Comp::Transform>(SelectionTool::selection[0]);\n\t\t\tif (transform.invalid())\n\t\t\t\treturn;\n\t\t\tif (!transform->isRootPart())\n\t\t\t\treturn;\n\t\t\t\n\t\t\tTranslationTool::magnet.selectedPart = std::get<ExtendedPart*>(transform->root);\n\t\t\tTranslationTool::magnet.magnetPoint = planeIntersection;\n\t\t}\n\t}\n\n\tvoid TranslationTool::translateAlongLine(const Vec3& direction, bool clamp, bool local) {\n\t\t// Closest point on ray1 (A + s * a) from ray2 (B + t * b). Ray1 is the ray from the parts' center in the direction of the edit tool, ray2 is the mouse ray. Directions a and b are normalized. Only s is calculated.\n\t\tif (SelectionTool::selection.empty())\n\t\t\treturn;\n\t\t\n\t\tstd::optional<GlobalCFrame> cframe = SelectionTool::selection.getCFrame();\n\t\tif (!cframe.has_value())\n\t\t\treturn;\n\t\t\n\t\t// Rotate direction according to model rotation\n\t\tRay ray1 = { cframe->getPosition(), local ? cframe->localToRelative(direction) : direction };\n\t\tRay ray2 = SelectionTool::ray;\n\n\t\t// Calculate s\n\t\tVec3 c = ray2.origin - ray1.origin;\n\t\tdouble ab = ray1.direction * ray2.direction;\n\t\tdouble bc = ray2.direction * c;\n\t\tdouble ac = ray1.direction * c;\n\t\tdouble s = (ac - ab * bc) / (1.0 - ab * ab);\n\n\t\t// Translation, relative to tool intersection\n\t\tVec3 translationCorrection = ray1.direction * (ray1.direction * (*SelectionTool::selectedPoint - cframe->getPosition()));\n\t\tVec3 translation = s * ray1.direction - translationCorrection;\n\n\t\t// Clamp to grid\n\t\tif (clamp) {\n\t\t\tif (local) {\n\t\t\t\tVec3 localTranslation = cframe->getRotation().globalToLocal(translation);\n\t\t\t\tlocalTranslation = Vec3(round(localTranslation.x), round(localTranslation.y), round(localTranslation.z));\n\t\t\t\ttranslation = cframe->getRotation().localToGlobal(localTranslation);\n\t\t\t} else {\n\t\t\t\tVec3 resultingPosition = castPositionToVec3(cframe->translated(translation).getPosition());\n\t\t\t\tVec3 clampedPosition = Vec3(round(resultingPosition.x), round(resultingPosition.y), round(resultingPosition.z));\n\t\t\t\tVec3 difference = resultingPosition - clampedPosition;\n\t\t\t\ttranslation -= difference;\n\t\t\t}\n\t\t}\n\n\t\t*SelectionTool::selectedPoint += translation;\n\t\tSelectionTool::selection.translate(translation);\n\t}\n\n}\n"
  },
  {
    "path": "application/picker/tools/translationTool.h",
    "content": "#pragma once\n\n#include \"../graphics/glfwUtils.h\"\n#include \"../engine/event/mouseEvent.h\"\n#include \"../engine/tool/stateTool.h\"\n#include \"ecs/components.h\"\n#include <Physics3D/externalforces/magnetForce.h>\n\nnamespace P3D::Application {\n\nclass TranslationTool : public Engine::StateTool {\nprivate:\n\tenum SelectionToolStatus : Engine::ToolStatus {\n\t\tkIdle        = 0,\n\t\tkTranslateX  = 1,\n\t\tkTranslateY  = 2,\n\t\tkTranslateZ  = 3,\n\t\tkTranslateC  = 4,\n\t\tkTranslateXY = 5,\n\t\tkTranslateXZ = 6,\n\t\tkTranslateYZ = 7,\n\t};\n\n\tbool active = false;\n\npublic:\n\tstatic MagnetForce magnet;\n\n\tDEFINE_TOOL(\"Translate\", \"Translate entities by clicking and dragging or using the handles\", Graphics::GLFW::Cursor::ARROW);\n\t\n\t~TranslationTool() override = default;\n\n\tvoid onRegister() override;\n\tvoid onDeregister() override;\n\tvoid onRender() override;\n\tvoid onUpdate() override;\n\tvoid onEvent(Engine::Event& event) override;\n\n\tbool onMousePress(Engine::MousePressEvent& event);\n\tbool onMouseRelease(Engine::MouseReleaseEvent& event);\n\tbool onMouseDrag(Engine::MouseDragEvent& event);\n\t\n\tstatic void translateInPlane(const Vec3& normal, bool clamp, bool local);\n\tstatic void translateAlongLine(const Vec3& direction, bool clamp, bool local);\n};\n\n};"
  },
  {
    "path": "application/resources.cpp",
    "content": "#include \"core.h\"\n\n#include \"resources.h\"\n\n#include \"../util/resource/resourceDescriptor.h\"\n\n#ifdef _MSC_VER\n#include \"resource.h\"\nResourceDescriptor applicationResources[] {\n\t{ IDR_SHADER1, \"SHADER\" },\n\t{ IDR_SHADER2, \"SHADER\" },\n\t{ IDR_SHADER3, \"SHADER\" },\n\t{ IDR_SHADER4, \"SHADER\" },\n\t{ IDR_SHADER5, \"SHADER\" },\n\t{ IDR_SHADER6, \"SHADER\" },\n\t{ IDR_SHADER7, \"SHADER\" },\n\t{ IDR_SHADER8, \"SHADER\" },\n\t{ IDR_SHADER9, \"SHADER\" },\n\t{ IDR_SHADER10, \"SHADER\" },\n\t{ IDR_SHADER11, \"SHADER\" },\n\t{ IDR_SHADER12, \"SHADER\" },\n\t{ IDR_SHADER13, \"SHADER\" },\n\t{ IDR_SHADER14, \"SHADER\" },\n\t{ IDR_SHADER15, \"SHADER\" },\n\t{ IDR_SHADER16, \"SHADER\" },\n\t{ IDR_SHADER17, \"SHADER\" },\n\t{ IDR_SHADER18, \"SHADER\" },\n\t{ IDR_OBJ1, \"OBJ\" },\n\t{ IDR_OBJ2, \"OBJ\" }\n};\n#else\n\nResourceDescriptor applicationResources[] {\n\t{ \"../res/shaders/basic.shader\"       , \"SHADER\" },\n\t{ \"../res/shaders/vector.shader\"      , \"SHADER\" },\n\t{ \"../res/shaders/origin.shader\"      , \"SHADER\" },\n\t{ \"../res/shaders/font.shader\"        , \"SHADER\" },\n\t{ \"../res/shaders/depth.shader\"       , \"SHADER\" },\n\t{ \"../res/shaders/quad.shader\"        , \"SHADER\" },\n\t{ \"../res/shaders/postprocess.shader\" , \"SHADER\" },\n\t{ \"../res/shaders/skybox.shader\"      , \"SHADER\" },\n\t{ \"../res/shaders/mask.shader\"        , \"SHADER\" },\n\t{ \"../res/shaders/point.shader\"       , \"SHADER\" },\n\t{ \"../res/shaders/test.shader\"        , \"SHADER\" },\n\t{ \"../res/shaders/blur.shader\"        , \"SHADER\" },\n\t{ \"../res/shaders/line.shader\"        , \"SHADER\" },\n\t{ \"../res/shaders/instance.shader\"    , \"SHADER\" },\n\t{ \"../res/shaders/sky.shader\"         , \"SHADER\" },\n\t{ \"../res/shaders/lighting.shader\"    , \"SHADER\" },\n\t{ \"../res/shaders/debug.shader\"       , \"SHADER\" },\n\t{ \"../res/shaders/depthbuffer.shader\" , \"SHADER\" },\n\t{ \"../res/models/stall.obj\"           , \"OBJ\" },\n\t{ \"../res/models/sphere.obj\"          , \"OBJ\" }\n};\n\n#endif"
  },
  {
    "path": "application/resources.h",
    "content": "#pragma once\n\nstruct ResourceDescriptor;\n\nextern ResourceDescriptor applicationResources[];\n\n#define BASIC_SHADER 0\n#define VECTOR_SHADER 1\n#define ORIGIN_SHADER 2\n#define FONT_SHADER 3\n#define DEPTH_SHADER 4\n#define QUAD_SHADER 5\n#define POSTPROCESS_SHADER 6\n#define SKYBOX_SHADER 7\n#define MASK_SHADER 8\n#define POINT_SHADER 9\n#define TEST_SHADER 10\n#define BLUR_SHADER 11\n#define LINE_SHADER 12\n#define INSTANCE_SHADER 13\n#define SKY_SHADER 14\n#define LIGHTING_SHADER 15\n#define DEBUG_SHADER 16\n#define DEPTHBUFFER_SHADER 17\n#define SPHERE_MODEL 18\n#define STALL_MODEL 19\n"
  },
  {
    "path": "application/shader/basicShader.cpp",
    "content": "#include \"core.h\"\n\n#include \"basicShader.h\"\n\n#include \"../graphics/ecs/components.h\"\n#include \"extendedPart.h\"\n\nnamespace P3D::Application {\n\nvoid BasicShader::updatePart(const ExtendedPart& part) {\n\tbind();\n\tupdateTexture(false);\n\tupdateModel(part.getCFrame(), DiagonalMat3f(part.hitbox.scale));\n}\n\nvoid BasicShader::updateMaterial(const Graphics::Comp::Material& material) {\n\tbind();\n\tsetUniform(\"material.albedo\", Vec4f(material.albedo));\n\tsetUniform(\"material.metalness\", material.metalness);\n\tsetUniform(\"material.roughness\", material.roughness);\n\tsetUniform(\"material.ambientOcclusion\", material.ao);\n}\n\nvoid BasicShader::updateTexture(bool textured) {\n\tbind();\n\tsetUniform(\"material.albedoMap\", 0);\n\tsetUniform(\"material.normalMap\", 1);\n\tsetUniform(\"material.metalnessMap\", 2);\n\tsetUniform(\"material.roughnessMap\", 3);\n\tsetUniform(\"material.ambientOcclusionMap\", 4);\n\tsetUniform(\"material.textured\", textured);\n}\n\n};"
  },
  {
    "path": "application/shader/basicShader.h",
    "content": "#pragma once\n\n#include \"shaderBase.h\"\n#include \"util/stringUtil.h\"\n\nnamespace P3D::Graphics::Comp {\nstruct Material;\n}\n\nnamespace P3D::Application {\nusing namespace Graphics;\n\nstruct ExtendedPart;\n\nstruct BasicShader : public StandardMeshShaderBase, public BasicShaderBase {\n\tBasicShader() : ShaderResource(\"BasicShader\", \"../res/shaders/basic.shader\"), StandardMeshShaderBase(\"BasicShader\", \"../res/shaders/basic.shader\"), BasicShaderBase(\"BasicShader\", \"../res/shaders/basic.shader\") {}\n\n\tvoid updatePart(const ExtendedPart& part);\n\tvoid updateTexture(bool textured);\n\tvoid updateMaterial(const Graphics::Comp::Material& material);\n};\n\nstruct InstanceShader : public InstancedMeshShaderBase, public BasicShaderBase {\n\tInstanceShader() : ShaderResource(\"InstanceShader\", \"../res/shaders/instance.shader\"), InstancedMeshShaderBase(\"InstanceShader\", \"../res/shaders/instance.shader\"), BasicShaderBase(\"InstanceShader\", \"../res/shaders/instance.shader\") {\n\t\tInstanceShader::bind();\n\t\tfor (int i = 0; i < 31; i++) \n\t\t\tsetUniform(Util::format(\"textures[%d]\", i), i);\n\t}\n};\n\n};"
  },
  {
    "path": "application/shader/shaderBase.cpp",
    "content": "#include \"core.h\"\n\n#include \"shaderBase.h\"\n\n#include <Physics3D/math/globalCFrame.h>\n#include \"ecs/components.h\"\n\nnamespace P3D::Application {\n\n#pragma region ProjectionShaderBase\n\nvoid ProjectionShaderBase::updateProjection(const Mat4f& viewMatrix, const Mat4f& projectionMatrix, const Position& viewPosition) {\n\tbind();\n\tsetUniform(\"viewMatrix\", viewMatrix);\n\tsetUniform(\"projectionMatrix\", projectionMatrix);\n\tsetUniform(\"viewPosition\", viewPosition);\n}\n\nvoid ProjectionShaderBase::updateProjectionMatrix(const Mat4f& projectionMatrix) {\n\tbind();\n\tsetUniform(\"projectionMatrix\", projectionMatrix);\n}\n\nvoid ProjectionShaderBase::updateViewMatrix(const Mat4f& viewMatrix) {\n\tbind();\n\tsetUniform(\"viewMatrix\", viewMatrix);\n}\n\nvoid ProjectionShaderBase::updateViewPosition(const Position& viewPosition) {\n\tbind();\n\tsetUniform(\"viewPosition\", viewPosition);\n}\n\n#pragma endregion\n\n#pragma region StandardMeshShaderBase\n\nvoid StandardMeshShaderBase::updateModel(const Mat4f& modelMatrix) {\n\tbind();\n\tsetUniform(\"modelMatrix\", modelMatrix);\n}\n\nvoid StandardMeshShaderBase::updateModel(const GlobalCFrame& modelCFrame, const DiagonalMat3f& scale) {\n\tthis->updateModel(modelCFrame.asMat4WithPreScale(scale));\n}\n\n#pragma endregion\n\n#pragma region BasicShaderBase\n\nvoid BasicShaderBase::updateLightCount(std::size_t lightCount) {\n\tbind();\n\n\tsetUniform(\"lightCount\", static_cast<int>(lightCount));\n}\n\t\nvoid BasicShaderBase::updateLight(std::size_t index, const Position& position, const Comp::Light& light) {\n\tbind();\n\n\tstd::string variable = \"lights[\" + std::to_string(static_cast<int>(index)) + \"].\";\n\n\t// position\n\tsetUniform(variable + \"position\", position);\n\n\t// color\n\tsetUniform(variable + \"color\", Vec3f(light.color));\n\n\t// intensity\n\tsetUniform(variable + \"intensity\", light.intensity);\n\n\t// attenuation.constant\n\tsetUniform(variable + \"attenuation.constant\", light.attenuation.constant);\n\n\t// attenuation.linear\n\tsetUniform(variable + \"attenuation.linear\", light.attenuation.linear);\n\n\t// attenuation.exponent\n\tsetUniform(variable + \"attenuation.exponent\", light.attenuation.exponent);\n}\n\nvoid BasicShaderBase::updateSunDirection(const Vec3f& sunDirection) {\n\tbind();\n\tsetUniform(\"sunDirection\", sunDirection);\n}\n\nvoid BasicShaderBase::updateSunColor(const Vec3f& sunColor) {\n\tbind();\n\tsetUniform(\"sunColor\", sunColor);\n}\n\nvoid BasicShaderBase::updateGamma(float gamma) {\n\tbind();\n\tsetUniform(\"gamma\", gamma);\n}\n\nvoid BasicShaderBase::updateHDR(float hdr) {\n\tbind();\n\tsetUniform(\"hdr\", hdr);\n}\n\nvoid BasicShaderBase::updateExposure(float exposure) {\n\tbind();\n\tsetUniform(\"exposure\", exposure);\n}\n\n#pragma endregion\n\n}\n"
  },
  {
    "path": "application/shader/shaderBase.h",
    "content": "#pragma once\n\n#include <Physics3D/math/position.h>\n#include <Physics3D/math/globalCFrame.h>\n#include <Physics3D/math/linalg/mat.h>\n\n#include \"../graphics/resource/shaderResource.h\"\n\nnamespace P3D::Application {\n\tnamespace Comp {\n\t\tstruct Light;\n\t}\n\n\tusing namespace Graphics;\n\nstruct ProjectionShaderBase : public virtual ShaderResource {\n\tProjectionShaderBase(const std::string& name, const std::string& path, bool isPath = true) : ShaderResource(name, path, isPath) {}\n\n\tvoid updateProjection(const Mat4f& viewMatrix, const Mat4f& projectionMatrix, const Position& viewPosition);\n\tvoid updateProjectionMatrix(const Mat4f& projectionMatrix);\n\tvoid updateViewMatrix(const Mat4f& viewMatrix);\n\tvoid updateViewPosition(const Position& viewPosition);\n};\n\nstruct StandardMeshShaderBase : public ProjectionShaderBase {\n\tStandardMeshShaderBase(const std::string& name, const std::string& path, bool isPath = true) : ProjectionShaderBase(name, path, isPath) {}\n\n\tvoid updateModel(const Mat4f& modelMatrix);\n\tvoid updateModel(const GlobalCFrame& modelCFrame, const DiagonalMat3f& scale);\n};\n\nstruct InstancedMeshShaderBase : public ProjectionShaderBase {\n\tInstancedMeshShaderBase(const std::string& name, const std::string& path, bool isPath = true) : ProjectionShaderBase(name, path, isPath) {}\n};\n\nstruct BasicShaderBase : public virtual ShaderResource {\n\tBasicShaderBase(const std::string& name, const std::string& path, bool isPath = true) : ShaderResource(name, path, isPath) {}\n\n\tvoid updateSunDirection(const Vec3f& sunDirection);\n\tvoid updateSunColor(const Vec3f& sunColor);\n\tvoid updateGamma(float gamma);\n\tvoid updateHDR(float hdr);\n\tvoid updateExposure(float exposure);\n\tvoid updateLightCount(std::size_t lightCount);\n\tvoid updateLight(std::size_t index, const Position& position, const Comp::Light& light);\n};\n\n}"
  },
  {
    "path": "application/shader/shaders.cpp",
    "content": "#include \"core.h\"\n\n#include \"shaders.h\"\n#include \"extendedPart.h\"\n\n#include \"../graphics/texture.h\"\n#include \"../graphics/renderer.h\"\n#include \"../util/resource/resourceManager.h\"\n\n#include <sstream>\n\nnamespace P3D::Application {\n\nnamespace Shaders {\n\t\nSRef<BasicShader> basicShader;\nSRef<DepthShader> depthShader;\nSRef<VectorShader> vectorShader;\nSRef<OriginShader> originShader;\nSRef<FontShader> fontShader;\nSRef<PostProcessShader> postProcessShader;\nSRef<SkyboxShader> skyboxShader;\nSRef<PointShader> pointShader;\nSRef<TestShader> testShader;\nSRef<LineShader> lineShader;\nSRef<MaskShader> maskShader;\nSRef<InstanceShader> instanceShader;\nSRef<LightingShader> lightingShader;\nSRef<SkyShader> skyShader;\nSRef<DebugShader> debugShader;\nSRef<DepthBufferShader> depthBufferShader;\n\nvoid onInit() {\n\n\t// GShader init\n\tbasicShader = std::make_shared<BasicShader>();\n\tdepthShader = std::make_shared<DepthShader>();\n\tvectorShader = std::make_shared<VectorShader>();\n\tfontShader = std::make_shared<FontShader>();\n\toriginShader = std::make_shared<OriginShader>();\n\tpostProcessShader = std::make_shared<PostProcessShader>();\n\tskyboxShader = std::make_shared<SkyboxShader>();\n\tpointShader = std::make_shared<PointShader>();\n\ttestShader = std::make_shared<TestShader>();\n\tlineShader = std::make_shared<LineShader>();\n\tmaskShader = std::make_shared<MaskShader>();\n\tinstanceShader = std::make_shared<InstanceShader>();\n\tskyShader = std::make_shared<SkyShader>();\n\tlightingShader = std::make_shared<LightingShader>();\n\tdebugShader = std::make_shared<DebugShader>();\n\tdepthBufferShader = std::make_shared<DepthBufferShader>();\n\n\tResourceManager::add(basicShader.get());\n\tResourceManager::add(depthShader.get());\n\tResourceManager::add(vectorShader.get());\n\tResourceManager::add(fontShader.get());\n\tResourceManager::add(originShader.get());\n\tResourceManager::add(postProcessShader.get());\n\tResourceManager::add(skyboxShader.get());\n\tResourceManager::add(pointShader.get());\n\tResourceManager::add(testShader.get());\n\tResourceManager::add(lineShader.get());\n\tResourceManager::add(maskShader.get());\n\tResourceManager::add(instanceShader.get());\n\tResourceManager::add(skyShader.get());\n\tResourceManager::add(lightingShader.get());\n\tResourceManager::add(debugShader.get());\n\tResourceManager::add(depthBufferShader.get());\n}\n\nvoid onClose() {\n\tbasicShader->close();\n\tdepthShader->close();\n\tvectorShader->close();\n\tfontShader->close();\n\toriginShader->close();\n\tskyboxShader->close();\n\tpostProcessShader->close();\n\tpointShader->close();\n\ttestShader->close();\n\tlineShader->close();\n\tmaskShader->close();\n\tinstanceShader->close();\n\tskyShader->close();\n\tlightingShader->close();\n\tdebugShader->close();\n\tdepthBufferShader->close();\n}\n\n}\n\n// SkyboxShader\n\nvoid SkyboxShader::updateCubeMap(Graphics::CubeMap* skybox) {\n\tbind();\n\tsetUniform(\"skyboxTexture\", skybox->getUnit());\n}\n\nvoid SkyboxShader::updateLightDirection(const Vec3f& lightDirection) {\n\tbind();\n\tsetUniform(\"lightDirection\", lightDirection);\n}\n\n\n// MeskShader\n\nvoid MaskShader::updateColor(const Color& color) {\n\tbind();\n\tsetUniform(\"color\", Vec4f(color));\n}\n\n\n// DepthShader\n\nvoid DepthShader::updateLight(const Mat4f& lightMatrix) {\n\tbind();\n\tsetUniform(\"lightMatrix\", lightMatrix);\n}\n\n\n// PostProcessShader\n\nvoid PostProcessShader::updateTexture(SRef<Texture> texture) {\n\tbind();\n\ttexture->bind();\n\tsetUniform(\"textureSampler\", texture->getUnit());\n}\n\nvoid PostProcessShader::updateTexture(SRef<HDRTexture> texture) {\n\tbind();\n\ttexture->bind();\n\tsetUniform(\"textureSampler\", texture->getUnit());\n}\n\n\n// OriginShader\n\nvoid OriginShader::updateProjection(const Mat4f& viewMatrix, const Mat4f& rotatedViewMatrix, const Mat4f& projectionMatrix, const Mat4f& orthoMatrix, const Position& viewPosition) {\n\tbind();\n\tsetUniform(\"viewMatrix\", viewMatrix);\n\tsetUniform(\"rotatedViewMatrix\", rotatedViewMatrix);\n\tsetUniform(\"projectionMatrix\", projectionMatrix);\n\tsetUniform(\"orthoMatrix\", orthoMatrix);\n\tsetUniform(\"viewPosition\", viewPosition);\n}\n\n\n// FontShader\n\nvoid FontShader::updateColor(const Color& color) {\n\tbind();\n\tsetUniform(\"color\", Vec4f(color));\n}\n\nvoid FontShader::updateProjection(const Mat4f& projectionMatrix) {\n\tbind();\n\tsetUniform(\"projectionMatrix\", projectionMatrix);\n}\n\nvoid FontShader::updateTexture(SRef<Texture> texture) {\n\tbind();\n\ttexture->bind();\n\tsetUniform(\"text\", texture->getUnit());\n}\n\n// SkyShader\n\nvoid SkyShader::updateTime(float time) {\n\tbind();\n\tsetUniform(\"time\", time);\n}\n\n// DepthBufferShader\n\nvoid DepthBufferShader::updateDepthMap(GLID unit, GLID id) {\n\tbind();\n\tRenderer::activeTexture(unit);\n\tRenderer::bindTexture2D(id);\n\tsetUniform(\"depthMap\", unit);\n}\n\nvoid DepthBufferShader::updatePlanes(float near, float far) {\n\tbind();\n\tsetUniform(\"far\", far);\n\tsetUniform(\"near\", near);\n}\n\n};"
  },
  {
    "path": "application/shader/shaders.h",
    "content": "#pragma once\n\n#include <Physics3D/math/globalCFrame.h>\n#include \"../graphics/shader/shader.h\"\n#include \"../graphics/resource/shaderResource.h\"\n#include \"../graphics/gui/color.h\"\n#include \"../shader/basicShader.h\"\n#include \"../shader/shaderBase.h\"\n\nnamespace P3D::Graphics {\n\tclass HDRTexture;\n\tclass Texture;\n\tclass CubeMap;\n};\n\nnamespace P3D::Application {\nusing namespace Graphics;\n\nstruct Light;\nstruct Material;\nstruct ExtendedPart;\n\nstruct DepthBufferShader : public ShaderResource {\n\tDepthBufferShader() : ShaderResource(\"DepthBufferShader\", \"../res/shaders/depthbuffer.shader\") {}\n\n\tvoid updateDepthMap(GLID unit, GLID id);\n\tvoid updatePlanes(float near, float far);\n};\n\nstruct DebugShader : public StandardMeshShaderBase {\n\tDebugShader() : ShaderResource(\"DebugShader\", \"../res/shaders/debug.shader\"), StandardMeshShaderBase(\"DebugShader\", \"../res/shaders/debug.shader\") {}\n};\n\nstruct SkyboxShader : public ProjectionShaderBase {\n\tSkyboxShader() : ShaderResource(\"SkyboxShader\", \"../res/shaders/skybox.shader\"), ProjectionShaderBase(\"SkyboxShader\", \"../res/shaders/skybox.shader\") {}\n\n\tvoid updateCubeMap(CubeMap* skybox);\n\tvoid updateLightDirection(const Vec3f& lightDirection);\n};\n\nstruct MaskShader : public StandardMeshShaderBase {\n\tMaskShader() : ShaderResource(\"MaskShader\", \"../res/shaders/mask.shader\"), StandardMeshShaderBase(\"MaskShader\", \"../res/shaders/mask.shader\") {}\n\n\tvoid updateColor(const Color& color);\n};\n\nstruct DepthShader : public StandardMeshShaderBase {\n\tDepthShader() : ShaderResource(\"DepthShader\", \"../res/shaders/depth.shader\"), StandardMeshShaderBase(\"DepthShader\", \"../res/shaders/depth.shader\") {}\n\n\tvoid updateLight(const Mat4f& lightMatrix);\n};\n\nstruct PostProcessShader : public ShaderResource {\n\t PostProcessShader() : ShaderResource(\"PostProcessShader\", \"../res/shaders/postProcess.shader\") {}\n\n\tvoid updateTexture(SRef<Texture> texture);\n\tvoid updateTexture(SRef<HDRTexture> texture);\n};\n\nstruct OriginShader : public ShaderResource {\n\tOriginShader() : ShaderResource(\"OriginShader\", \"../res/shaders/origin.shader\") {}\n\n\tvoid updateProjection(const Mat4f& viewMatrix, const Mat4f& rotatedViewMatrix, const Mat4f& projectionMatrix, const Mat4f& orthoMatrix, const Position& viewPosition);\n};\n\nstruct FontShader : public ShaderResource {\n\tFontShader() : ShaderResource(\"FontShader\", \"../res/shaders/font.shader\") {}\n\n\tvoid updateColor(const Color& color);\n\tvoid updateProjection(const Mat4f& projectionMatrix);\n\tvoid updateTexture(SRef<Texture> texture);\n};\n\nstruct VectorShader : public ProjectionShaderBase {\n\tVectorShader() : ShaderResource(\"VectorShader\", \"../res/shaders/vector.shader\"), ProjectionShaderBase(\"VectorShader\", \"../res/shaders/vector.shader\") {}\n};\n\nstruct PointShader : public ProjectionShaderBase {\n\tPointShader() : ShaderResource(\"PointShader\", \"../res/shaders/point.shader\"), ProjectionShaderBase(\"PointShader\", \"../res/shaders/point.shader\") {}\n};\n\nstruct TestShader : public StandardMeshShaderBase {\n\tTestShader() : ShaderResource(\"TestShader\", \"../res/shaders/test.shader\"), StandardMeshShaderBase(\"TestShader\", \"../res/shaders/test.shader\") {}\n};\n\nstruct LineShader : public ProjectionShaderBase {\n\tLineShader() : ShaderResource(\"LineShader\", \"../res/shaders/line.shader\"), ProjectionShaderBase(\"LineShader\", \"../res/shaders/line.shader\") {}\n};\n\nstruct SkyShader : public ProjectionShaderBase {\n\tSkyShader() : ShaderResource(\"SkyShader\", \"../res/shaders/sky.shader\"), ProjectionShaderBase(\"SkyShader\", \"../res/shaders/sky.shader\") {}\n\n\tvoid updateTime(float time);\n};\n\nstruct LightingShader : public BasicShaderBase {\n\tLightingShader() : ShaderResource(\"LightingShader\", \"../res/shaders/lighting.shader\"), BasicShaderBase(\"LightingShader\", \"../res/shaders/lighting.shader\") {}\n};\n\nnamespace Shaders {\nextern SRef<BasicShader> basicShader;\nextern SRef<DepthShader> depthShader;\nextern SRef<VectorShader> vectorShader;\nextern SRef<OriginShader> originShader;\nextern SRef<FontShader> fontShader;\nextern SRef<PostProcessShader> postProcessShader;\nextern SRef<SkyboxShader> skyboxShader;\nextern SRef<PointShader> pointShader;\nextern SRef<TestShader> testShader;\nextern SRef<LineShader> lineShader;\nextern SRef<InstanceShader> instanceShader;\nextern SRef<MaskShader> maskShader;\nextern SRef<SkyShader> skyShader;\nextern SRef<LightingShader> lightingShader;\nextern SRef<DebugShader> debugShader;\nextern SRef<DepthBufferShader> depthBufferShader;\n\nvoid onInit();\nvoid onClose();\n}\n\n};"
  },
  {
    "path": "application/view/camera.cpp",
    "content": "#include \"core.h\"\n\n#include \"camera.h\"\n#include \"screen.h\"\n#include \"application.h\"\n#include \"../graphics/gui/guiUtils.h\"\n\n#include \"../engine/event/event.h\"\n#include \"../engine/event/mouseEvent.h\"\n#include \"../engine/event/keyEvent.h\"\n#include \"../engine/input/keyboard.h\"\n#include \"../engine/options/keyboardOptions.h\"\n\n#include \"../extendedPart.h\"\n#include \"worlds.h\"\n#include \"picker/tools/selectionTool.h\"\n\nnamespace P3D::Application {\n\nCamera::Camera(const Position& position, const Rotation& rotation) : cframe(GlobalCFrame(position, rotation)), velocity(0.35), angularVelocity(0.04), flying(true) {\n\tonUpdate();\n};\n\nCamera::Camera() : cframe(GlobalCFrame()), velocity(0.35), angularVelocity(0.04), flying(true) {\n\tonUpdate();\n};\n\nvoid Camera::setPosition(Position position) {\n\tflags |= ViewDirty;\n\n\tcframe.position = position;\n}\n\nvoid Camera::setPosition(Fix<32> x, Fix<32> y, Fix<32> z) {\n\tsetPosition(Position(x, y, z));\n}\n\nvoid Camera::setRotation(const Rotation& rotation) {\n\tflags |= ViewDirty;\n\n\tcframe.rotation = rotation;\n}\n\nvoid Camera::setRotation(double alpha, double beta, double gamma) {\n\tthis->setRotation(Rotation::fromEulerAngles(alpha, beta, gamma));\n}\n\nvoid Camera::setRotation(Vec3 rotation) {\n\tsetRotation(rotation.x, rotation.y, rotation.z);\n}\n\nMat4f Camera::getViewRotation() {\n\treturn joinDiagonal(Mat3f(cframe.rotation.asRotationMatrix().transpose()), 1.0f);\n}\n\nvoid Camera::rotate(Screen& screen, double dalpha, double dbeta, double dgamma, bool leftDragging, bool accelerating) {\n\tflags |= ViewDirty;\n\trotating = accelerating;\n\n\tcframe.rotation = Rotation::rotY(currentAngularVelocity * dbeta) * cframe.rotation * Rotation::rotX(currentAngularVelocity * dalpha);\n\n\t/*if (leftDragging) {\n\t\tscreen.world->asyncModification([&screen] () {\n\t\t\t// TODO Picker::moveGrabbedEntityLateral(screen);\n\t\t});\n\t}*/\n\t// Accelerate camera rotation\n\tif (accelerating)\n\t\tcurrentAngularVelocity += angularVelocity * angularVelocityIncrease;\n\n\t// Clamp camera angular velocity\n\tif (currentAngularVelocity > angularVelocity)\n\t\tcurrentAngularVelocity = angularVelocity;\n\n\t// Save last rotation\n\tlastRotation = Vec3(dalpha, dbeta, dgamma);\n\n\t// Save left dragging value\n\twasLeftDragging = leftDragging;\n}\n\nvoid Camera::rotate(Screen& screen, Vec3 delta, bool leftDragging, bool accelerating) {\n\trotate(screen, delta.x, delta.y, delta.z, leftDragging, accelerating);\n}\n\nvoid Camera::move(Screen& screen, double dx, double dy, double dz, bool leftDragging, bool accelerating) {\n\tflags |= ViewDirty;\n\tmoving = accelerating;\n\n\t(*screen.eventHandler.cameraMoveHandler) (screen, this, Vec3(dx, dy, dz));\n\n\tVec3 translation = Vec3();\n\n\tif (dx != 0) {\n\t\tVec3 cameraRotationX = cframe.rotation * Vec3(1, 0, 0);\n\t\tVec3 translationX = normalize(Vec3(cameraRotationX.x, 0, cameraRotationX.z)) * dx;\n\t\ttranslation += translationX;\n\t}\n\n\tif (dy != 0) {\n\t\tVec3 translationY = Vec3(0, dy, 0);\n\t\ttranslation += translationY;\n\t}\n\n\tif (dz != 0) {\n\t\tVec3 cameraRotationZ = cframe.rotation * Vec3(0, 0, 1);\n\t\tVec3 translationZ = normalize(Vec3(cameraRotationZ.x, 0, cameraRotationZ.z)) * dz;\n\t\ttranslation += translationZ;\n\t}\n\n\ttranslation *= currentVelocity;\n\n\tcframe += translation;\n\n\tif (wasLeftDragging)\n\t\tSelectionTool::selection.translate(translation);\n\n\t// Accelerate camera movement\n\tif (accelerating)\n\t\tcurrentVelocity += velocity * velocityIncrease;\n\n\t// Clamp camera velocity\n\tif (currentVelocity > velocity)\n\t\tcurrentVelocity = velocity;\n\n\t// Save last direction\n\tlastDirection = Vec3(dx, dy, dz);\n\n\t// Save left dragging value\n\twasLeftDragging = leftDragging;\n}\n\nvoid Camera::move(Screen& screen, Vec3 delta, bool leftDragging, bool accelerating) {\n\tmove(screen, delta.x, delta.y, delta.z, leftDragging, accelerating);\n}\n\nbool Camera::onKeyRelease(Engine::KeyReleaseEvent& event) {\n\tusing namespace Engine;\n\tKey key = event.getKey();\n\n\tif (key == KeyboardOptions::Move::forward ||\n\t\tkey == KeyboardOptions::Move::backward ||\n\t\tkey == KeyboardOptions::Move::left ||\n\t\tkey == KeyboardOptions::Move::right ||\n\t\tkey == KeyboardOptions::Move::ascend ||\n\t\tkey == KeyboardOptions::Move::descend) {\n\t\tmoving = false;\n\t}\n\n\tif (key == KeyboardOptions::Rotate::left ||\n\t\tkey == KeyboardOptions::Rotate::right ||\n\t\tkey == KeyboardOptions::Rotate::up ||\n\t\tkey == KeyboardOptions::Rotate::down) {\n\t\trotating = false;\n\t}\n\n\treturn false;\n}\n\nbool Camera::onMouseDrag(Engine::MouseDragEvent& event) {\n\tdouble dmx = event.getNewX() - event.getOldX();\n\tdouble dmy = event.getNewY() - event.getOldY();\n\n\t// Camera rotating\n\tif (event.isRightDragging())\n\t\trotate(screen, -dmy * 0.1, -dmx * 0.1, 0, event.isLeftDragging());\n\n\n\t// Camera moving\n\tif (event.isMiddleDragging())\n\t\tmove(screen, dmx * 0.2, -dmy * 0.2, 0, event.isLeftDragging());\n\n\treturn false;\n}\n\nbool Camera::onMouseScroll(Engine::MouseScrollEvent& event) {\n\tvelocity = Graphics::GUI::clamp(velocity * (1 + 0.2 * event.getYOffset()), 0.001, 100);\n\n\tthirdPersonDistance -= event.getYOffset();\n\n\treturn true;\n};\n\nvoid Camera::onEvent(Engine::Event& event) {\n\tusing namespace Engine;\n\n\tEventDispatcher dispatcher(event);\n\tdispatcher.dispatch<MouseDragEvent>(EVENT_BIND(Camera::onMouseDrag));\n\tdispatcher.dispatch<MouseScrollEvent>(EVENT_BIND(Camera::onMouseScroll));\n\tdispatcher.dispatch<KeyReleaseEvent>(EVENT_BIND(Camera::onKeyRelease));\n}\n\nvoid Camera::onUpdate(float fov, float aspect, float znear, float zfar) {\n\tthis->fov = fov;\n\tthis->aspect = aspect;\n\tthis->znear = znear;\n\tthis->zfar = zfar;\n\n\tflags |= ProjectionDirty;\n\n\tonUpdate();\n}\n\nvoid Camera::onUpdate(float aspect) {\n\tthis->aspect = aspect;\n\n\tflags |= ProjectionDirty;\n\n\torthoMatrix = ortho(-aspect, aspect, -1.0f, 1.0f, -1000.0f, 1000.0f);\n\n\tonUpdate();\n}\n\nvoid Camera::onUpdate() {\n\n\tif (currentVelocity != 0) {\n\t\t// Clamp camera velocity\n\t\tif (currentVelocity < 0) {\n\t\t\tcurrentVelocity = 0;\n\t\t\twasLeftDragging = false;\n\t\t} else {\n\t\t\t// Decellerate camera movement if the camera stops moving\n\t\t\tif (!moving) {\n\t\t\t\tmove(screen, lastDirection, wasLeftDragging, false);\n\t\t\t\tcurrentVelocity -= velocity * velocityIncrease;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (currentAngularVelocity != 0) {\n\t\t// Clamp camera rotation\n\t\tif (currentAngularVelocity < 0) {\n\t\t\tcurrentAngularVelocity = 0;\n\t\t\twasLeftDragging = false;\n\t\t} else {\n\t\t\t// Decellerate camera rotation if the camera stops rotating\n\t\t\tif (!rotating) {\n\t\t\t\trotate(screen, lastRotation, wasLeftDragging, false);\n\t\t\t\tcurrentAngularVelocity -= angularVelocity * angularVelocityIncrease;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Attach the camera to the attached part, if there is anys\n\tif (!flying && attachment != nullptr) {\n\t\tVec3 vertical = Vec3(0, 1, 0);\n\t\tVec3 forward = getForwardDirection();\n\n\t\t// Sinus angle between camera direction and the xz plane\n\t\tdouble sinAlpha = vertical * forward;\n\n\t\tdouble dy = thirdPersonDistance * sinAlpha;\n\t\tdouble dz = sqrt(thirdPersonDistance * thirdPersonDistance - dy * dy);\n\n\t\tVec3 translationZ = normalize(-Vec3(forward.x, 0, forward.z)) * dz;\n\t\tVec3 translationY = Vec3(0, -dy, 0);\n\t\tVec3 translation = translationY + translationZ;\n\n\t\tthis->cframe.position = attachment->getCFrame().position + translation;\n\n\t\tflags |= ViewDirty;\n\t}\n\n\t// Update projection matrix\n\tif (flags & ProjectionDirty) {\n\t\tflags ^= ProjectionDirty;\n\n\t\tprojectionMatrix = perspective(fov, aspect, znear, zfar);\n\t\tinvertedProjectionMatrix = ~projectionMatrix;\n\t}\n\n\t// Update view matrix\n\tif (flags & ViewDirty) {\n\t\tflags ^= ViewDirty;\n\n\t\tviewMatrix = translate(getViewRotation(), -Vec3f(float(cframe.position.x), float(cframe.position.y), float(cframe.position.z)));\n\t\tinvertedViewMatrix = ~viewMatrix;\n\t}\n}\n\ndouble Camera::getRightOffsetAtZ1() const {\n\treturn tan(double(fov) / 2) * aspect;\n}\n\ndouble Camera::getTopOffsetAtZ1() const {\n\treturn tan(double(fov) / 2);\n}\n\n};\n"
  },
  {
    "path": "application/view/camera.h",
    "content": "#pragma once\n\n#include <Physics3D/math/rotation.h>\n#include <Physics3D/math/globalCFrame.h>\n\nnamespace P3D::Engine {\nstruct Event;\nclass MouseDragEvent;\nclass MouseScrollEvent;\nclass KeyReleaseEvent;\n};\n\nnamespace P3D::Application {\n\nstruct ExtendedPart;\nstruct Camera;\nclass Screen;\n\nstruct Camera {\nprivate:\n\n\tenum CameraFlags : char {\n\t\t// No flags\n\t\tNone = 0 << 0,\n\n\t\t// Whether the view matrix needs to be recalculated\n\t\tViewDirty = 1 << 0,\n\n\t\t// Whether the projection matrix needs to be recalculated\n\t\tProjectionDirty = 1 << 1\n\t};\n\n\tchar flags = None;\n\n\n\tdouble velocityIncrease = 0.5;\n\tdouble currentVelocity = 0;\n\tVec3 lastDirection = Vec3();\n\tbool moving = false;\n\n\tdouble angularVelocityIncrease = 0.5;\n\tdouble currentAngularVelocity = 0;\n\tVec3 lastRotation = Vec3();\n\tbool rotating = false;\n\n\tbool wasLeftDragging = false;\n\n\tbool onMouseScroll(Engine::MouseScrollEvent& event);\n\tbool onMouseDrag(Engine::MouseDragEvent& event);\n\tbool onKeyRelease(Engine::KeyReleaseEvent& event);\n\npublic:\n\tGlobalCFrame cframe;\n\tdouble velocity;\n\tdouble angularVelocity;\n\tbool flying;\n\n\tdouble thirdPersonDistance = 6.0;\n\n\tfloat fov;\n\tfloat znear;\n\tfloat zfar;\n\tfloat aspect;\n\n\tMat4f viewMatrix;\n\tMat4f invertedViewMatrix;\n\n\tMat4f projectionMatrix;\n\tMat4f invertedProjectionMatrix;\n\n\tMat4f orthoMatrix;\n\n\tExtendedPart* attachment = nullptr;\n\n\tvoid onUpdate();\n\tvoid onUpdate(float fov, float aspect, float znear, float zfar);\n\tvoid onUpdate(float aspect);\n\tvoid onEvent(Engine::Event& event);\n\n\tCamera(const Position& position, const Rotation& rotation);\n\tCamera();\n\n\tvoid setPosition(Position position);\n\tvoid setPosition(Fix<32> x, Fix<32> y, Fix<32> z);\n\n\tvoid setRotation(const Rotation& rotation);\n\tvoid setRotation(double alpha, double beta, double gamma);\n\tvoid setRotation(Vec3 rotation);\n\n\tvoid rotate(Screen& screen, double dalpha, double dbeta, double dgamma, bool leftDragging, bool accelerating = true);\n\tvoid rotate(Screen& screen, Vec3 delta, bool leftDragging, bool accelerating = true);\n\n\tvoid move(Screen& screen, double dx, double dy, double dz, bool leftDragging, bool accelerating = true);\n\tvoid move(Screen& screen, Vec3 delta, bool leftDragging, bool accelerating = true);\n\n\tMat4f getViewRotation();\n\n\tdouble getRightOffsetAtZ1() const;\n\tdouble getTopOffsetAtZ1() const;\n\n\tinline Vec3 getForwardDirection() const { return -cframe.rotation.getZ(); }\n\tinline Vec3 getBackwardDirection() const { return cframe.rotation.getZ(); }\n\tinline Vec3 getUpDirection() const { return cframe.rotation.getY(); }\n\tinline Vec3 getDownDirection() const { return -cframe.rotation.getY(); }\n\tinline Vec3 getLeftDirection() const { return -cframe.rotation.getX(); }\n\tinline Vec3 getRightDirection() const { return cframe.rotation.getX(); }\n};\n\n};"
  },
  {
    "path": "application/view/debugFrame.cpp",
    "content": "#include \"core.h\"\n\n#include \"debugFrame.h\"\n\n\n#include \"imgui/imgui.h\"\n#include \"../graphics/debug/visualDebug.h\"\n\nnamespace P3D::Application {\n\nvoid DebugFrame::onInit(Engine::Registry64& registry) {\n\t\n}\n\nvoid DebugFrame::onRender(Engine::Registry64& registry) {\n\tImGui::Begin(\"Debug\");\n\t\n\tusing namespace P3D::Debug;\n\tusing namespace P3D::Graphics::VisualDebug;\n\tImGui::SetNextTreeNodeOpen(true);\n\tif (ImGui::TreeNode(\"Vectors\")) {\n\t\tImGui::Checkbox(\"Info\", &vectorDebugEnabled[INFO_VEC]);\n\t\tImGui::Checkbox(\"Position\", &vectorDebugEnabled[POSITION]);\n\t\tImGui::Checkbox(\"Velocity\", &vectorDebugEnabled[VELOCITY]);\n\t\tImGui::Checkbox(\"Acceleration\", &vectorDebugEnabled[ACCELERATION]);\n\t\tImGui::Checkbox(\"Moment\", &vectorDebugEnabled[MOMENT]);\n\t\tImGui::Checkbox(\"Force\", &vectorDebugEnabled[FORCE]);\n\t\tImGui::Checkbox(\"Angular impulse\", &vectorDebugEnabled[ANGULAR_IMPULSE]);\n\t\tImGui::Checkbox(\"Impulse\", &vectorDebugEnabled[IMPULSE]);\n\n\t\tImGui::TreePop();\n\t}\n\n\tImGui::SetNextTreeNodeOpen(true);\n\tif (ImGui::TreeNode(\"Points\")) {\n\t\tImGui::Checkbox(\"Info\", &pointDebugEnabled[INFO_POINT]);\n\t\tImGui::Checkbox(\"Center of mass\", &pointDebugEnabled[CENTER_OF_MASS]);\n\t\tImGui::Checkbox(\"Intersections\", &pointDebugEnabled[INTERSECTION]);\n\n\t\tImGui::TreePop();\n\t}\n\n\tImGui::SetNextTreeNodeOpen(true);\n\tif (ImGui::TreeNode(\"Render\")) {\n\t\tImGui::Checkbox(\"Render pies\", &renderPiesEnabled);\n\t\tif (ImGui::Button(\"Switch collision sphere render mode\")) colissionSpheresMode = static_cast<SphereColissionRenderMode>((static_cast<int>(colissionSpheresMode) + 1) % 3);\n\n\t\tImGui::TreePop();\n\t}\n\n\tImGui::End();\n}\n\n\t\n}\n"
  },
  {
    "path": "application/view/debugFrame.h",
    "content": "#pragma once\n\n#include \"../engine/ecs/registry.h\"\n\nnamespace P3D::Application {\n\t\nstruct DebugFrame {\n\n\tstatic bool renderSpheres;\n\n\tstatic void onInit(Engine::Registry64& registry);\n\tstatic void onRender(Engine::Registry64& registry);\n\n};\n\t\n}\n"
  },
  {
    "path": "application/view/ecsFrame.cpp",
    "content": "#include \"core.h\"\n\n#include \"ecsFrame.h\"\n\n#define IMGUI_DEFINE_MATH_OPERATORS\n\n#include \"application.h\"\n#include \"screen.h\"\n#include \"imgui/imgui.h\"\n#include \"imgui/imgui_internal.h\"\n#include \"ecs/components.h\"\n#include \"../graphics/resource/textureResource.h\"\n#include \"../graphics/meshRegistry.h\"\n#include \"../util/resource/resourceManager.h\"\n#include \"graphics/gui/imgui/imguiExtension.h\"\n#include \"Physics3D/hardconstraints/fixedConstraint.h\"\n#include \"Physics3D/hardconstraints/motorConstraint.h\"\n#include \"Physics3D/softlinks/elasticLink.h\"\n#include \"Physics3D/softlinks/magneticLink.h\"\n#include \"Physics3D/softlinks/springLink.h\"\n#include \"picker/tools/alignmentLinkTool.h\"\n#include \"picker/tools/attachmentTool.h\"\n#include \"picker/tools/elasticLinkTool.h\"\n#include \"picker/tools/fixedConstraintTool.h\"\n#include \"picker/tools/magneticLinkTool.h\"\n#include \"picker/tools/motorConstraintTool.h\"\n#include \"picker/tools/selectionTool.h\"\n#include \"picker/tools/springLinkTool.h\"\n#include \"util/stringUtil.h\"\n\nnamespace P3D::Application {\n\nGraphics::TextureResource* folderIcon;\nGraphics::TextureResource* openFolderIcon;\nGraphics::TextureResource* entityIcon;\nGraphics::TextureResource* colliderIcon;\nGraphics::TextureResource* terrainIcon;\nGraphics::TextureResource* mainColliderIcon;\nGraphics::TextureResource* childColliderIcon;\nGraphics::TextureResource* attachmentsIcon;\nGraphics::TextureResource* hardConstraintsIcon;\nGraphics::TextureResource* softLinksIcon;\nGraphics::TextureResource* cframeIcon;\nGraphics::TextureResource* cubeClassIcon;\nGraphics::TextureResource* sphereClassIcon;\nGraphics::TextureResource* cylinderClassIcon;\nGraphics::TextureResource* cornerClassIcon;\nGraphics::TextureResource* wedgeClassIcon;\nGraphics::TextureResource* polygonClassIcon;\nGraphics::TextureResource* shownIcon;\nGraphics::TextureResource* hiddenIcon;\nGraphics::TextureResource* physicsIcon;\nGraphics::TextureResource* addIcon;\n\nstatic int nodeIndex = 0;\nstatic void* selectedNode = nullptr;\nstatic Engine::Registry64::entity_type selectedNodeEntity = Engine::Registry64::null_entity;\nstatic ImGuiTreeNodeFlags baseFlags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth;\nstatic ImGuiTreeNodeFlags leafFlags = baseFlags | ImGuiTreeNodeFlags_Leaf;\n\nstatic GLID getColliderIcon(IRef<Comp::Collider> collider) {\n\tif (collider.invalid())\n\t\treturn -1;\n\n\tIRef<const ShapeClass> shape = collider->part->hitbox.baseShape;\n\tif (shape.get() == &CubeClass::instance)\n\t\treturn cubeClassIcon->getID();\n\tif (shape.get() == &SphereClass::instance)\n\t\treturn sphereClassIcon->getID();\n\tif (shape.get() == &CornerClass::instance)\n\t\treturn cornerClassIcon->getID();\n\tif (shape.get() == &WedgeClass::instance)\n\t\treturn wedgeClassIcon->getID();\n\tif (shape.get() == &CylinderClass::instance)\n\t\treturn cylinderClassIcon->getID();\n\n\treturn polygonClassIcon->getID();\n}\n\nstatic GLID getMeshIcon(IRef<Graphics::Comp::Mesh> mesh) {\n\tusing namespace Graphics::MeshRegistry;\n\n\tif (mesh.invalid())\n\t\treturn -1;\n\n\tstd::size_t shape = mesh->id;\n\tif (shape == getID(&CubeClass::instance))\n\t\treturn cubeClassIcon->getID();\n\tif (shape == getID(&SphereClass::instance))\n\t\treturn sphereClassIcon->getID();\n\tif (shape == getID(&CornerClass::instance))\n\t\treturn cornerClassIcon->getID();\n\tif (shape == getID(&WedgeClass::instance))\n\t\treturn wedgeClassIcon->getID();\n\tif (shape == getID(&CylinderClass::instance))\n\t\treturn cylinderClassIcon->getID();\n\n\treturn polygonClassIcon->getID();\n}\n\nstatic void HeaderNode() {\n\tImGuiWindow* window = ImGui::GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn;\n\n\tImGuiContext& g = *GImGui;\n\n\tfloat arrowWidth = g.FontSize;\n\tfloat buttonSize = g.FontSize + g.Style.FramePadding.y * 2;\n\tfloat buttonMargin = g.Style.ItemInnerSpacing.x;\n\tfloat buttonPadding = 5.0;\n\n\tImVec2 pos = window->DC.CursorPos;\n\tImVec2 startPos = ImVec2(pos.x - window->DC.Indent.x + g.Style.WindowPadding.x, pos.y);\n\tImVec2 endPos = ImVec2(startPos.x + ImGui::GetContentRegionMax().x, startPos.y + buttonSize);\n\tImRect visibilityButton(startPos, ImVec2(startPos.x + buttonSize - buttonPadding * 2, startPos.y + buttonSize));\n\tImRect arrowButton(ImVec2(pos.x + visibilityButton.GetWidth() + buttonMargin, pos.y), ImVec2(pos.x + visibilityButton.GetWidth() + buttonMargin + arrowWidth, pos.y + buttonSize));\n\tImRect iconButton(ImVec2(arrowButton.Max.x + buttonMargin, pos.y), ImVec2(arrowButton.Max.x + buttonMargin + buttonSize, pos.y + buttonSize));\n\tImRect colliderButton(ImVec2(iconButton.Max.x + buttonMargin, pos.y), ImVec2(iconButton.Max.x + buttonMargin + buttonSize - buttonPadding * 2, pos.y + buttonSize));\n\tImRect mainButton(ImVec2(colliderButton.Max.x, pos.y), endPos);\n\tImVec2 textPos = ImVec2(mainButton.Min.x + buttonMargin * 3, pos.y + g.Style.FramePadding.y);\n\tImRect totalSize = ImRect(startPos, endPos);\n\n\t// Background\n\twindow->DrawList->AddRectFilled(totalSize.Min - ImVec2(0, GImGui->Style.ItemSpacing.y / 2), totalSize.Max + ImVec2(0, GImGui->Style.ItemSpacing.y / 2), ImGui::GetColorU32(ImGuiCol_TabUnfocusedActive));\n\n\t// Icons\n\tImGui::DrawIcon(shownIcon->getID(), visibilityButton.Min + ImVec2(0, buttonPadding), visibilityButton.Max - ImVec2(0, buttonPadding));\n\tImGui::DrawIcon(entityIcon->getID(), iconButton.Min + ImVec2(buttonPadding, buttonPadding), iconButton.Max - ImVec2(buttonPadding, buttonPadding));\n\tImGui::DrawIcon(physicsIcon->getID(), colliderButton.Min + ImVec2(0, buttonPadding), colliderButton.Max - ImVec2(0, buttonPadding));\n\n\t// Lines\n\tImGui::DrawLineBetween(visibilityButton, arrowButton, g.Style.ItemSpacing.y);\n\tImGui::DrawLineBetween(iconButton, colliderButton, g.Style.ItemSpacing.y);\n\tImGui::DrawLineBetween(colliderButton, mainButton, g.Style.ItemSpacing.y);\n\n\t// Text\n\tImGui::RenderText(textPos, \"Name\");\n\n\tImGui::ItemSize(totalSize, g.Style.FramePadding.y);\n\tImGui::ItemAdd(totalSize, 0);\n}\n\ntemplate <typename OnPressed>\nstatic bool IconTreeNode(ImU32 id, Engine::Registry64& registry, const char* label, ImGuiTreeNodeFlags flags, GLID mainIcon, bool selected, const OnPressed& onPressed, Engine::Registry64::entity_type entity = 0) {\n\tImGuiWindow* window = ImGui::GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\t// ID\n\tImGuiContext& g = *GImGui;\n\tImU32 mainId = id == 0 ? window->GetID(label) : id;\n\tImU32 arrowId = window->GetID(\"Arrow\");\n\tImU32 colliderId = window->GetID(\"Collider\");\n\tImU32 meshId = window->GetID(\"Mesh\");\n\n\t// Constants\n\tfloat arrowWidth = g.FontSize;\n\tfloat buttonSize = g.FontSize + g.Style.FramePadding.y * 2;\n\tfloat buttonMargin = g.Style.ItemInnerSpacing.x;\n\tfloat arrowOffset = std::abs(g.FontSize - arrowWidth) / 2.0f;\n\tfloat buttonPadding = 5.0;\n\n\t// Positions\n\tImVec2 pos = window->DC.CursorPos;\n\tImVec2 startPos = ImVec2(pos.x - window->DC.Indent.x + g.Style.WindowPadding.x, pos.y);\n\tImVec2 endPos = ImVec2(startPos.x + ImGui::GetContentRegionMax().x, startPos.y + buttonSize);\n\tImRect visibilityButton(startPos, ImVec2(startPos.x + buttonSize - buttonPadding * 2, startPos.y + buttonSize));\n\tImRect arrowButton(ImVec2(pos.x + visibilityButton.GetWidth() + buttonMargin, pos.y), ImVec2(pos.x + visibilityButton.GetWidth() + buttonMargin + arrowWidth, pos.y + buttonSize));\n\tImRect iconButton(ImVec2(arrowButton.Max.x + buttonMargin, pos.y), ImVec2(arrowButton.Max.x + buttonMargin + buttonSize, pos.y + buttonSize));\n\tImRect colliderButton(ImVec2(iconButton.Max.x + buttonMargin, pos.y), ImVec2(iconButton.Max.x + buttonMargin + buttonSize - buttonPadding * 2, pos.y + buttonSize));\n\tImRect mainButton(ImVec2(colliderButton.Max.x, pos.y), endPos);\n\tImVec2 textPos = ImVec2(mainButton.Min.x + buttonMargin * 3, pos.y + g.Style.FramePadding.y);\n\tImRect totalSize = ImRect(startPos, endPos);\n\n\t// General\n\tbool opened = ImGui::TreeNodeBehaviorIsOpen(mainId);\n\tbool leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0;\n\tbool even = nodeIndex++ % 2 == 0;\n\n\t// Get entity components\n\tauto mesh = registry.get<Graphics::Comp::Mesh>(entity);\n\tauto collider = registry.get<Comp::Collider>(entity);\n\n\t// Main button\n\tbool mainHovered, mainHeld;\n\tif (ImGui::ButtonBehavior(mainButton, mainId, &mainHovered, &mainHeld, ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick)) {\n\t\tif (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {\n\t\t\tif (!leaf)\n\t\t\t\twindow->DC.StateStorage->SetInt(mainId, opened ? 0 : 1);\n\t\t} else\n\t\t\tonPressed();\n\t}\n\tImGui::DrawButton(totalSize, even, selected, mainHeld, mainHovered);\n\tif (mainIcon == 0) {\n\t\tif (mesh.invalid())\n\t\t\tmainIcon = leaf ? entityIcon->getID() : opened ? openFolderIcon->getID() : folderIcon->getID();\n\t\telse\n\t\t\tmainIcon = getMeshIcon(mesh);\n\t}\n\tImGui::DrawIcon(mainIcon, iconButton.Min, iconButton.Max);\n\n\t// Visibility Button\n\tif (mesh.valid()) {\n\t\tbool visible = mesh->visible;\n\t\tbool visibilityHovered, visibilityHeld;\n\t\tif (ImGui::ButtonBehavior(visibilityButton, meshId, &visibilityHovered, &visibilityHeld, ImGuiButtonFlags_PressedOnClickRelease))\n\t\t\tmesh->visible = !mesh->visible;\n\n\t\tImGui::DrawButton(visibilityButton, true, selected, visibilityHeld, false);\n\t\tif (!visible)\n\t\t\tImGui::DrawIcon(hiddenIcon->getID(), visibilityButton.Min + ImVec2(0, buttonPadding), visibilityButton.Max - ImVec2(0, buttonPadding));\n\t\telse if (visibilityHovered)\n\t\t\tImGui::DrawIcon(shownIcon->getID(), visibilityButton.Min + ImVec2(0, buttonPadding), visibilityButton.Max - ImVec2(0, buttonPadding));\n\t}\n\n\t// Arrow button\n\tif (!leaf) {\n\t\tbool arrowHovered, arrowHeld;\n\t\tif (ImGui::ButtonBehavior(arrowButton, arrowId, &arrowHovered, &arrowHeld, ImGuiButtonFlags_PressedOnClickRelease)) {\n\t\t\tif (!leaf)\n\t\t\t\twindow->DC.StateStorage->SetInt(mainId, opened ? 0 : 1);\n\t\t}\n\t\tImGui::DrawButton(arrowButton, true, selected, arrowHeld, false);\n\t\tImGui::RenderArrow(window->DrawList, ImVec2(arrowButton.Min.x + arrowOffset, textPos.y), ImGui::GetColorU32(ImGuiCol_Text), opened ? ImGuiDir_Down : ImGuiDir_Right, 1.0f);\n\t}\n\n\t// Collider button\n\tif (collider.valid()) {\n\t\tbool colliderHovered, colliderHeld;\n\t\tif (ImGui::ButtonBehavior(colliderButton, colliderId, &colliderHovered, &colliderHeld, ImGuiButtonFlags_PressedOnClickRelease)) {\n\t\t\tif (entity != Engine::Registry64::null_entity) {\n\t\t\t\tif (collider.valid()) {\n\t\t\t\t\tstd::unique_lock<UpgradeableMutex> lock(worldMutex);\n\t\t\t\t\tif (collider->part->isTerrainPart()) {\n\t\t\t\t\t\tworld.removePart(collider->part);\n\t\t\t\t\t\tworld.addPart(collider->part);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tworld.removePart(collider->part);\n\t\t\t\t\t\tworld.addTerrainPart(collider->part);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tImGui::DrawButton(colliderButton, true, selected, colliderHeld, false);\n\t\tstd::string text;\n\t\tif (collider->part->isTerrainPart()) {\n\t\t\ttext = \"T\";\n\t\t} else if(collider->part->hasAttachedParts()) {\n\t\t\tif(collider->part->isMainPart()) {\n\t\t\t\ttext = \"M\";\n\t\t\t} else {\n\t\t\t\ttext = \"C\";\n\t\t\t}\n\t\t}\n\n\t\tImVec2 textSize = ImGui::CalcTextSize(text.c_str());\n\t\tImGui::RenderText(ImVec2(colliderButton.Min.x + (buttonSize - buttonPadding * 2 - textSize.x) / 2, textPos.y), text.c_str());\n\t}\n\n\t// Lines\n\tImGui::DrawLine(\n\t\tImVec2(visibilityButton.Max.x + buttonMargin / 2, visibilityButton.Min.y - g.Style.ItemSpacing.y / 2), \n\t\tImVec2(visibilityButton.Max.x + buttonMargin / 2, visibilityButton.Max.y + g.Style.ItemSpacing.y / 2)\n\t);\n\n\t// Text\n\tImGui::RenderText(textPos, label);\n\n\tImGui::ItemSize(totalSize, g.Style.FramePadding.y);\n\tImGui::ItemAdd(totalSize, mainId);\n\n\tif (opened)\n\t\tImGui::TreePush(label);\n\n\treturn opened;\n}\n\nstatic bool EntityTreeNode(ImU32 id, Engine::Registry64& registry,\n                           Engine::Registry64::entity_type entity,\n                           IRef<Comp::Collider> collider,\n                           ImGuiTreeNodeFlags flags,\n                           const char* label,\n                           GLID icon) {\n\n\tauto onPressed = [&]() {\n\t\tif (ImGui::GetIO().KeyCtrl)\n\t\t\tSelectionTool::toggle(entity);\n\t\telse {\n\t\t\tSelectionTool::selection.clear();\n\t\t\tSelectionTool::select(entity);\n\t\t}\n\n\t\tif (collider.valid())\n\t\t\tscreen.selectedPart = collider->part;\n\t};\n\n\tbool selected = SelectionTool::selection.contains(entity);\n\n\tbool result = IconTreeNode(id, registry, label, flags, icon, selected, onPressed, entity);\n\n\treturn result;\n}\n\nstatic bool ColliderMenuItem(const char* label, GLID icon, bool selected = false, bool enabled = true) {\n\tImGuiWindow* window = ImGui::GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\tImGuiContext& g = *GImGui;\n\tImVec2 pos = window->DC.CursorPos;\n\tImVec2 labelSize = ImGui::CalcTextSize(label, nullptr, true);\n\n\tImGuiSelectableFlags flags = ImGuiSelectableFlags_SelectOnRelease | ImGuiSelectableFlags_SetNavIdOnHover | (enabled ? 0 : ImGuiSelectableFlags_Disabled);\n\n\tfloat minWidth = window->DC.MenuColumns.DeclColumns(labelSize.x, 0, IM_FLOOR(g.FontSize * 1.20f)); // Feedback for next frame\n\tfloat extraWidth = ImMax(0.0f, ImGui::GetContentRegionAvail().x - minWidth);\n\n\tif (selected)\n\t\tImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetColorU32(ImGuiCol_TabActive));\n\tbool pressed = ImGui::Selectable(label, false, flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(minWidth, 0.0f));\n\tif (selected)\n\t\tImGui::PopStyleColor(1);\n\n\tImVec2 start = pos + ImVec2(window->DC.MenuColumns.Pos[2] + extraWidth, 0);\n\tImVec2 end = start + ImVec2(labelSize.y, labelSize.y);\n\tImGui::DrawIcon(icon, start, end);\n\n\treturn pressed;\n}\n\nvoid ECSFrame::renderEntity(Engine::Registry64& registry, const Engine::Registry64::entity_type& entity) {\n\tif (entity == selectedNodeEntity)\n\t\treturn;\n\n\tImGui::PushID(static_cast<int>(entity));\n\n\tauto children = registry.getChildren(entity);\n\tbool leaf = children.begin() == registry.end();\n\tauto collider = registry.get<Comp::Collider>(entity);\n\n\tstd::vector<HardPhysicalConnection*> hardConstraints;\n\tstd::vector<SoftLink*> softLinks;\n\tstd::vector<std::pair<Part*, Part*>> attachments;\n\tif(collider.valid()) {\n\t\tPhysical* colliderPhysical = collider->part->getPhysical();\n\t\tbool isFreePart = !collider->part->isTerrainPart();\n\n\t\tif(isFreePart) {\n\t\t\t// Collect hard constraints\n\t\t\tcolliderPhysical->forEachHardConstraint([&hardConstraints](Physical& parent, ConnectedPhysical& child) {\n\t\t\t\thardConstraints.push_back(&child.connectionToParent);\n\t\t\t});\n\n\t\t\t// Collect soft links\n\t\t\tfor(SoftLink* softLink : world.softLinks) {\n\t\t\t\tif(softLink->attachedPartA.part == collider->part || softLink->attachedPartB.part == collider->part)\n\t\t\t\t\tsoftLinks.push_back(softLink);\n\t\t\t}\n\n\t\t\t// Collect attachments\n\t\t\tRigidBody* rigidBody = &colliderPhysical->rigidBody;\n\t\t\tif(collider->part->isMainPart()) {\n\t\t\t\trigidBody->forEachAttachedPart([&attachments, &collider, &rigidBody](Part& attachment) {\n\t\t\t\t\tif(collider->part != &attachment) {\n\t\t\t\t\t\tattachments.emplace_back(rigidBody->mainPart, &attachment);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tattachments.emplace_back(collider->part, rigidBody->mainPart);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Entity node\n\tstd::string name = registry.getOr<Comp::Name>(entity, std::to_string(entity)).name;\n\tImU32 id = GImGui->CurrentWindow->GetID(name.c_str());\n\tbool expandable = !leaf || !hardConstraints.empty() || !softLinks.empty() || !attachments.empty();\n\tImGuiTreeNodeFlags flags = expandable ? baseFlags : leafFlags;\n\tbool open = EntityTreeNode(id, registry, entity, collider, flags, name.c_str(), 0);\n\n\t// Render popup\n\tif (ImGui::BeginPopupContextItem()) {\n\t\tif (collider.valid()) {\n\t\t\tif (ImGui::BeginMenu(\"Change collider shape\")) {\n\t\t\t\tstd::unique_lock<UpgradeableMutex> lock(worldMutex);\n\n\t\t\t\tDiagonalMat3 scale = collider->part->hitbox.scale;\n\t\t\t\tconst ShapeClass* shape = collider->part->getShape().baseShape.get();\n\n\t\t\t\tif (ColliderMenuItem(\"Box\", cubeClassIcon->getID(), shape == &CubeClass::instance))\n\t\t\t\t\tcollider->part->setShape(boxShape(scale[0], scale[1], scale[2]));\n\t\t\t\tif (ColliderMenuItem(\"Sphere\", sphereClassIcon->getID(), shape == &SphereClass::instance))\n\t\t\t\t\tcollider->part->setShape(sphereShape(scale[0]));\n\t\t\t\tif (ColliderMenuItem(\"Cylinder\", cylinderClassIcon->getID(), shape == &CylinderClass::instance))\n\t\t\t\t\tcollider->part->setShape(cylinderShape(scale[0], scale[1]));\n\t\t\t\tif (ColliderMenuItem(\"Corner\", cornerClassIcon->getID(), shape == &CornerClass::instance))\n\t\t\t\t\tcollider->part->setShape(cornerShape(scale[0], scale[1], scale[2]));\n\t\t\t\tif (ColliderMenuItem(\"Wedge\", wedgeClassIcon->getID(), shape == &WedgeClass::instance))\n\t\t\t\t\tcollider->part->setShape(wedgeShape(scale[0], scale[1], scale[2]));\n\n\t\t\t\tImGui::EndMenu();\n\t\t\t}\n\t\t}\n\n\t\t// Collapse / unfold\n\t\tif (!leaf) {\n\t\t\tif (open) {\n\t\t\t\tif (ImGui::MenuItem(\"Collapse\"))\n\t\t\t\t\tGImGui->CurrentWindow->DC.StateStorage->SetInt(id, 0);\n\t\t\t} else {\n\t\t\t\tif (ImGui::MenuItem(\"Expand\")) \n\t\t\t\t\tGImGui->CurrentWindow->DC.StateStorage->SetInt(id, 1);\n\t\t\t}\n\t\t}\n\n\t\t// Rename\n\t\tif (ImGui::BeginMenu(\"Rename\")) {\n\t\t\tstatic char buffer[20] = \"\";\n\t\t\tif (buffer[0] == '\\0')\n\t\t\t\tstrcpy(buffer, name.c_str());\n\n\t\t\tImGui::Text(\"Edit name:\");\n\t\t\tImGui::InputText(\"##edit\", buffer, IM_ARRAYSIZE(buffer));\n\t\t\tif (ImGui::Button(\"Apply\")) \n\t\t\t\tregistry.get<Comp::Name>(entity)->name = buffer;\n\t\t\t\n\t\t\tImGui::EndMenu();\n\t\t}\n\n\t\t// Add\n\t\tImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetColorU32(ImVec4(0.458f, 0.776f, 0.298f, 1.0f)));\n\t\tif (ImGui::MenuItem(\"Add\")) {\n\t\t\tauto newEntity = registry.create();\n\t\t\tSelectionTool::single(newEntity);\n\t\t}\n\t\tImGui::PopStyleColor();\n\n\t\t// Delete\n\t\tImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetColorU32(ImVec4(0.929f, 0.262f, 0.212f, 1.0f)));\n\t\tif (ImGui::MenuItem(\"Delete\")) {\n\t\t\tregistry.destroy(entity);\n\t\t}\n\t\tImGui::PopStyleColor();\n\n\t\tImGui::EndPopup();\n\t}\n\n\t// Render content\n\tif (open) {\n\t\t// Render attachments\n\t\tif (!attachments.empty()) {\n\t\t\tif (IconTreeNode(0, registry, \"Attachments\", baseFlags, attachmentsIcon->getID(), false, []() {})) {\n\t\t\t\trenderAttachments(registry, entity, *collider, attachments);\n\t\t\t\tImGui::TreePop();\n\t\t\t}\n\t\t}\n\n\t\t// Render hard constraints\n\t\tif (!hardConstraints.empty()) {\n\t\t\tif (IconTreeNode(0, registry, \"Hard Constraints\", baseFlags, hardConstraintsIcon->getID(), false, []() {})) {\n\t\t\t\trenderHardConstraints(registry, entity, *collider, hardConstraints);\n\t\t\t\tImGui::TreePop();\n\t\t\t}\n\t\t}\n\n\t\t// Render soft links\n\t\tif (!softLinks.empty()) {\n\t\t\tif (IconTreeNode(0, registry, \"Soft Links\", baseFlags, softLinksIcon->getID(), false, []() {})) {\n\t\t\t\trenderSoftLinks(registry, entity, *collider, softLinks);\n\t\t\t\tImGui::TreePop();\n\t\t\t}\n\t\t}\n\n\t\t// Render children\n\t\tif (!leaf) {\n\t\t\tfor (auto child : children)\n\t\t\t\trenderEntity(registry, child);\n\t\t}\n\n\t\tImGui::TreePop();\n\t}\n\n\t/*if (ImGui::BeginDragDropSource()) {\n\t\t// check sizeof later\n\t\tImGui::SetDragDropPayload(\"ECS_NODE\", id, sizeof(id));\n\n\t\tfloat buttonSize = GImGui->FontSize + GImGui->Style.FramePadding.y * 2;\n\n\t\tImGui::Image(texture, ImVec2(buttonSize, buttonSize));\n\t\tImGui::SameLine();\n\t\tImGui::SetCursorPos(ImVec2(ImGui::GetCursorPosX(), ImGui::GetCursorPosY() + 4));\n\t\tImGui::Text(\"Move %s\", name.c_str());\n\t\tImGui::EndDragDropSource();\n\t}\n\n\tif (ImGui::BeginDragDropTarget()) {\n\t\tif (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(\"ECS_NODE\")) {\n\t\t\t//Engine::Node* source = static_cast<Engine::Node*>(payload->Data);\n\t\t}\n\t\tImGui::EndDragDropTarget();\n\t}*/\n\tImGui::PopID();\n}\n\ntemplate <typename Link, typename Tool, typename Component, typename BaseLink>\nbool softLinkDispatch(Engine::Registry64& registry, const std::vector<BaseLink*>& links, std::size_t index) {\n\tBaseLink* baseLink = links[index];\n\n\tif (Link* link = dynamic_cast<Link*>(baseLink)) {\n\t\tstd::string name = Util::format(\"%s %d\", Util::decamel(Util::demangle(Util::typeName<Link>())).c_str(), index + 1);\n\n\t\tbool selected = selectedNode == link;\n\n\t\tauto onPressed = [&] {\n\t\t\tSelectionTool::selection.clear();\n\t\t\tselectedNodeEntity = registry.destroy(selectedNodeEntity);\n\t\t\tif (selectedNode != link) {\n\t\t\t\tEngine::Registry64::entity_type entity = registry.create();\n\t\t\t\tregistry.add<Comp::Name>(entity, name);\n\t\t\t\tregistry.add<Component>(entity, link);\n\n\t\t\t\tselectedNode = link;\n\t\t\t\tselectedNodeEntity = entity;\n\t\t\t\tSelectionTool::select(selectedNodeEntity);\n\t\t\t} else\n\t\t\t\tselectedNode = nullptr;\n\t\t};\n\n\t\tIconTreeNode(0, registry, name.c_str(), leafFlags, ResourceManager::get<Graphics::TextureResource>(Tool::getStaticName())->getID(), selected, onPressed);\n\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\ntemplate <typename Constraint, typename Tool, typename Component>\nbool hardConstraintDispatch(Engine::Registry64& registry, const std::vector<HardPhysicalConnection*>& constraints, std::size_t index) {\n\tHardPhysicalConnection* connection = constraints[index];\n\n\tif (Constraint* constraint = dynamic_cast<Constraint*>(connection->constraintWithParent.get())) {\n\t\tstd::string name = Util::format(\"%s %d\", Util::decamel(Util::demangle(Util::typeName<Constraint>())).c_str(), index + 1);\n\n\t\tbool selected = selectedNode == constraint;\n\n\t\tauto onPressed = [&] {\t\n\t\t\tSelectionTool::selection.clear();\n\t\t\tselectedNodeEntity = registry.destroy(selectedNodeEntity);\n\t\t\tif (selectedNode != constraint) {\n\t\t\t\tEngine::Registry64::entity_type entity = registry.create();\n\t\t\t\tregistry.add<Comp::Name>(entity, name);\n\t\t\t\tregistry.add<Component>(entity, connection);\n\n\t\t\t\tselectedNode = constraint;\n\t\t\t\tselectedNodeEntity = entity;\n\t\t\t\tSelectionTool::select(selectedNodeEntity);\n\t\t\t} else\n\t\t\t\tselectedNode = nullptr;\n\t\t};\n\n\t\tIconTreeNode(0, registry, name.c_str(), leafFlags, ResourceManager::get<Graphics::TextureResource>(Tool::getStaticName())->getID(), selected, onPressed);\n\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nvoid attachmentDispatch(Engine::Registry64& registry, const std::vector<std::pair<Part*, Part*>>& attachments, std::size_t index) {\n\tPart* from = attachments[index].first;\n\tPart* to = attachments[index].second;\n\tPart* childPart = to->isMainPart() ? from : to;\n\n\tstd::string name = Util::format(\"Attachment %d\", index + 1);\n\n\tbool selected = selectedNode == childPart;\n\n\tauto onPressed = [&] {\n\t\tSelectionTool::selection.clear();\n\t\tselectedNodeEntity = registry.destroy(selectedNodeEntity);\n\t\tif (selectedNode != childPart) {\n\t\t\tEngine::Registry64::entity_type entity = registry.create();\n\t\t\tregistry.add<Comp::Name>(entity, name);\n\t\t\tregistry.add<Comp::Attachment>(entity, from, to);\n\n\t\t\tselectedNode = childPart;\n\t\t\tselectedNodeEntity = entity;\n\t\t\tSelectionTool::select(selectedNodeEntity);\n\t\t} else\n\t\t\tselectedNode = nullptr;\n\t};\n\n\tIconTreeNode(0, registry, name.c_str(), leafFlags, ResourceManager::get<Graphics::TextureResource>(AttachmentTool::getStaticName())->getID(), selected, onPressed);\n}\n\nvoid ECSFrame::renderHardConstraints(Engine::Registry64& registry,\n                                     const Engine::Registry64::entity_type& entity,\n                                     const Comp::Collider& collider,\n                                     const std::vector<HardPhysicalConnection*>& hardConstraints) {\n\n\tfor (std::size_t index = 0; index < hardConstraints.size(); index++) {\n\t\tImGui::PushID(hardConstraints[index]);\n\n\t\tbool dispatched = false;\n\t\tdispatched |= hardConstraintDispatch<FixedConstraint, FixedConstraintTool, Comp::FixedConstraint>(registry, hardConstraints, index);\n\t\tdispatched |= hardConstraintDispatch<ConstantSpeedMotorConstraint, MotorConstraintTool, Comp::HardConstraint>(registry, hardConstraints, index);\n\n\t\tif (!dispatched) \n\t\t\tIconTreeNode(0, registry, \"Unknown hard constraint\", leafFlags, hardConstraintsIcon->getID(), selectedNode == hardConstraints[index], []() {});\n\n\t\tImGui::PopID();\n\t}\n}\n\nvoid ECSFrame::renderSoftLinks(Engine::Registry64& registry,\n                               const Engine::Registry64::entity_type& entity,\n                               const Comp::Collider& collider,\n                               const std::vector<SoftLink*>& softLinks) {\n\n\tfor (std::size_t index = 0; index < softLinks.size(); index++) {\n\t\tImGui::PushID(softLinks[index]);\n\n\t\tbool dispatched = false;\n\t\tdispatched |= softLinkDispatch<MagneticLink, MagneticLinkTool, Comp::MagneticLink>(registry, softLinks, index);\n\t\tdispatched |= softLinkDispatch<ElasticLink, ElasticLinkTool, Comp::ElasticLink>(registry, softLinks, index);\n\t\tdispatched |= softLinkDispatch<SpringLink, SpringLinkTool, Comp::SpringLink>(registry, softLinks, index);\n\t\tdispatched |= softLinkDispatch<AlignmentLink, AlignmentLinkTool, Comp::AlignmentLink>(registry, softLinks, index);\n\n\t\tif (!dispatched)\n\t\t\tIconTreeNode(0, registry, \"Unknown soft link\", leafFlags, softLinksIcon->getID(), selectedNode == softLinks[index], [] {});\n\t\t\t\n\t\tImGui::PopID();\n\t}\n}\n\nvoid ECSFrame::renderAttachments(Engine::Registry64& registry,\n                                 const Engine::Registry64::entity_type& entity,\n                                 const Comp::Collider& collider,\n                                 const std::vector<std::pair<Part*, Part*>>& attachments) {\n\n\tfor (std::size_t index = 0; index < attachments.size(); index++) {\n\t\tImGui::PushID(attachments[index].second);\n\n\t\tattachmentDispatch(registry, attachments, index);\n\n\t\tImGui::PopID();\n\t}\n}\n\nvoid ECSFrame::onInit(Engine::Registry64& registry) {\n\tfolderIcon = ResourceManager::add<Graphics::TextureResource>(\"folder\", \"../res/textures/icons/Folder.png\");\n\topenFolderIcon = ResourceManager::add<Graphics::TextureResource>(\"folder open\", \"../res/textures/icons/Folder Open.png\");\n\tentityIcon = ResourceManager::add<Graphics::TextureResource>(\"entity\", \"../res/textures/icons/Entity.png\");\n\tcolliderIcon = ResourceManager::add<Graphics::TextureResource>(\"collider\", \"../res/textures/icons/Collider.png\");\n\tterrainIcon = ResourceManager::add<Graphics::TextureResource>(\"terrain collider\", \"../res/textures/icons/Terrain Collider.png\");\n\tmainColliderIcon = ResourceManager::add<Graphics::TextureResource>(\"main collider\", \"../res/textures/icons/Main Collider.png\");\n\tchildColliderIcon = ResourceManager::add<Graphics::TextureResource>(\"child collider\", \"../res/textures/icons/Child Collider.png\");\n\thardConstraintsIcon = ResourceManager::add<Graphics::TextureResource>(\"hard constraints\", \"../res/textures/icons/Hard Constraints.png\");\n\tsoftLinksIcon = ResourceManager::add<Graphics::TextureResource>(\"soft constraints\", \"../res/textures/icons/Soft Constraints.png\");\n\tattachmentsIcon = ResourceManager::add<Graphics::TextureResource>(\"attachments\", \"../res/textures/icons/Attachments.png\");\n\tcframeIcon = ResourceManager::add<Graphics::TextureResource>(\"cframe\", \"../res/textures/icons/Axes.png\");\n\tcubeClassIcon = ResourceManager::add<Graphics::TextureResource>(\"cube\", \"../res/textures/icons/Cube.png\");\n\tsphereClassIcon = ResourceManager::add<Graphics::TextureResource>(\"sphere\", \"../res/textures/icons/Sphere.png\");\n\tcylinderClassIcon = ResourceManager::add<Graphics::TextureResource>(\"cylinder\", \"../res/textures/icons/Cylinder.png\");\n\tcornerClassIcon = ResourceManager::add<Graphics::TextureResource>(\"corner\", \"../res/textures/icons/Tetrahedron.png\");\n\twedgeClassIcon = ResourceManager::add<Graphics::TextureResource>(\"wedge\", \"../res/textures/icons/Wedge.png\");\n\tpolygonClassIcon = ResourceManager::add<Graphics::TextureResource>(\"polygon\", \"../res/textures/icons/Dodecahedron.png\");\n\tshownIcon = ResourceManager::add<Graphics::TextureResource>(\"shown\", \"../res/textures/icons/Eye.png\");\n\thiddenIcon = ResourceManager::add<Graphics::TextureResource>(\"hidden\", \"../res/textures/icons/Hidden.png\");\n\tphysicsIcon = ResourceManager::add<Graphics::TextureResource>(\"physics\", \"../res/textures/icons/Physics.png\");\n\taddIcon = ResourceManager::add<Graphics::TextureResource>(\"add\", \"../res/textures/icons/Add.png\");\n}\n\n\nvoid ECSFrame::onRender(Engine::Registry64& registry) {\n\tusing namespace Engine;\n\n\tImGui::Begin(\"Tree\");\n\n\n\tauto filter = [&registry](const Registry64::entity_set_iterator& iterator) {\n\t\treturn registry.getParent(*iterator) == 0;\n\t};\n\n\tnodeIndex = 0;\n\tHeaderNode();\n\tfor (auto entity : registry.filter(filter))\n\t\trenderEntity(registry, registry.getSelf(entity));\n\n\tImGui::End();\n}\n\n}\n"
  },
  {
    "path": "application/view/ecsFrame.h",
    "content": "#pragma once\n\n#include \"../engine/ecs/registry.h\"\n\nnamespace P3D {\n\tclass Part;\n\tclass SoftLink;\n\tstruct HardPhysicalConnection;\n\n\tnamespace Application::Comp {\n\t\tstruct Collider;\n\t}\n}\n\nnamespace P3D::Application {\n\n\tstruct ECSFrame {\n\tprivate:\n\t\tstatic void renderEntity(Engine::Registry64& registry, const Engine::Registry64::entity_type& entity);\n\t\tstatic void renderHardConstraints(Engine::Registry64& registry, const Engine::Registry64::entity_type& entity, const Comp::Collider& collider, const std::vector<HardPhysicalConnection*>& hardConstraints);\n\t\tstatic void renderSoftLinks(Engine::Registry64& registry, const Engine::Registry64::entity_type& entity, const Comp::Collider& collider, const std::vector<SoftLink*>& softLinks);\n\t\tstatic void renderAttachments(Engine::Registry64& registry, const Engine::Registry64::entity_type& entity, const Comp::Collider& collider, const std::vector<std::pair<Part*, Part*>>& attachments);\n\n\n\tpublic:\n\t\tstatic void onInit(Engine::Registry64& registry);\n\t\tstatic void onRender(Engine::Registry64& registry);\n\t};\n\n}\n"
  },
  {
    "path": "application/view/environmentFrame.cpp",
    "content": "#include \"core.h\"\n\n#include \"environmentFrame.h\"\n\n#include \"imgui/imgui.h\"\n#include \"shader/shaders.h\"\n\n// include this because we have a bit of code that uses it. \n#include \"../layer/skyboxLayer.h\"\n\n\nnamespace P3D::Application {\n\nfloat EnvironmentFrame::hdr = 1.0f;\nfloat EnvironmentFrame::gamma = 0.8f;\nfloat EnvironmentFrame::exposure = 0.8f;\nColor EnvironmentFrame::sunColor = Color(1);\n\nvoid EnvironmentFrame::onInit(Engine::Registry64& registry) {\n\t\n}\n\nvoid EnvironmentFrame::onRender(Engine::Registry64& registry) {\n\tImGui::Begin(\"Environment\");\n\t\n\tif (ImGui::SliderFloat(\"HDR\", &hdr, 0, 1)) {\n\t\tShaders::basicShader->updateHDR(hdr);\n\t\tShaders::instanceShader->updateHDR(hdr);\n\t}\n\n\tif (ImGui::SliderFloat(\"Gamma\", &gamma, 0, 3)) {\n\t\tShaders::basicShader->updateGamma(gamma);\n\t\tShaders::instanceShader->updateGamma(gamma);\n\t}\n\n\tif (ImGui::SliderFloat(\"Exposure\", &exposure, 0, 2)) {\n\t\tShaders::basicShader->updateExposure(exposure);\n\t\t;\n\t}\n\n\tif (ImGui::ColorEdit3(\"Sun color\", sunColor.data)) {\n\t\tShaders::basicShader->updateSunColor(sunColor);\n\t\tShaders::instanceShader->updateSunColor(sunColor);\n\t}\n\n\tImGui::End();\n\n\n\tImGui::Begin(\"Skybox\");\n\tImGui::Checkbox(\"New sky\", &useNewSky);\n\tImGui::Text(\"Time: %f\", time);\n\tImGui::Checkbox(\"Pauze\", &pauze);\n\tImGui::End();\n}\n}\n"
  },
  {
    "path": "application/view/environmentFrame.h",
    "content": "#pragma once\n\n#include \"../engine/ecs/registry.h\"\n#include \"../graphics/gui/color.h\"\n\nnamespace P3D::Application {\n\t\nstruct EnvironmentFrame {\n\n\tstatic float hdr;\n\tstatic float gamma;\n\tstatic float exposure;\n\tstatic Graphics::Color sunColor;\n\n\tstatic void onInit(Engine::Registry64& registry);\n\tstatic void onRender(Engine::Registry64& registry);\n\n};\n\t\n}\n"
  },
  {
    "path": "application/view/frames.cpp",
    "content": "#include \"core.h\"\n#include \"frames.h\"\n\n#include \"resourceFrame.h\"\n#include \"layerFrame.h\"\n#include \"ecsFrame.h\"\n#include \"debugFrame.h\"\n#include \"environmentFrame.h\"\n#include \"propertiesFrame.h\"\n#include \"toolbarFrame.h\"\n#include \"imgui/imgui.h\"\n\nnamespace P3D::Application {\n\n\nvoid Frames::onInit(Engine::Registry64& registry) {\n\tECSFrame::onInit(registry);\n\tPropertiesFrame::onInit(registry);\n\tLayerFrame::onInit(registry);\n\tResourceFrame::onInit(registry);\n\tEnvironmentFrame::onInit(registry);\n\tDebugFrame::onInit(registry);\n\tToolbarFrame::onInit(registry);\n}\n\nvoid Frames::onRender(Engine::Registry64& registry) {\n\tImGui::ShowDemoWindow();\n\n\tECSFrame::onRender(registry);\n\tPropertiesFrame::onRender(registry);\n\tLayerFrame::onRender(registry);\n\tResourceFrame::onRender(registry);\n\tEnvironmentFrame::onRender(registry);\n\tDebugFrame::onRender(registry);\n\tToolbarFrame::onRender(registry);\n}\n\n}\n"
  },
  {
    "path": "application/view/frames.h",
    "content": "#pragma once\n\n#include \"../engine/ecs/registry.h\"\n\nnamespace P3D::Application {\n\nstruct Frames {\n\t\n\tstatic void onInit(Engine::Registry64& registry);\n\tstatic void onRender(Engine::Registry64& registry);\n\n};\n\n};"
  },
  {
    "path": "application/view/layerFrame.cpp",
    "content": "#include \"core.h\"\n#include \"layerFrame.h\"\n\n#include \"screen.h\"\n#include \"application.h\"\n#include \"imgui/imgui.h\"\n\nnamespace P3D::Application {\n\nbool LayerFrame::doEvents;\nbool LayerFrame::noRender;\nbool LayerFrame::doUpdate;\nbool LayerFrame::isDisabled;\nEngine::Layer* LayerFrame::selectedLayer = nullptr;\n\t\nvoid LayerFrame::onInit(Engine::Registry64& registry) {\n\t\n}\n\nvoid LayerFrame::onRender(Engine::Registry64& registry) {\n\tImGui::Begin(\"Layers\");\n\t\n\tusing namespace Engine;\n\n\tImGui::Columns(2, 0, true);\n\tImGui::Separator();\n\tfor (Layer* layer : screen.layerStack) {\n\t\tif (ImGui::Selectable(layer->name.c_str(), selectedLayer == layer))\n\t\t\tselectedLayer = layer;\n\t}\n\n\tImGui::NextColumn();\n\n\tImGui::Text(\"Name: %s\", (selectedLayer) ? selectedLayer->name.c_str() : \"-\");\n\tif (selectedLayer) {\n\t\tImGui::SetNextTreeNodeOpen(true);\n\t\tif (ImGui::TreeNode(\"Flags\")) {\n\t\t\tchar& flags = selectedLayer->flags;\n\n\t\t\tdoEvents = !(flags & Layer::NoEvents);\n\t\t\tdoUpdate = !(flags & Layer::NoUpdate);\n\t\t\tnoRender = !(flags & Layer::NoRender);\n\t\t\tisDisabled = flags & Layer::Disabled;\n\n\t\t\tImGui::Checkbox(\"Disabled\", &isDisabled);\n\t\t\tImGui::Checkbox(\"Events\", &doEvents);\n\t\t\tImGui::Checkbox(\"Update\", &doUpdate);\n\t\t\tImGui::Checkbox(\"Render\", &noRender);\n\n\t\t\tflags = (isDisabled) ? flags | Layer::Disabled : flags & ~Layer::Disabled;\n\t\t\tflags = (doEvents) ? flags & ~Layer::NoEvents : flags | Layer::NoEvents;\n\t\t\tflags = (doUpdate) ? flags & ~Layer::NoUpdate : flags | Layer::NoUpdate;\n\t\t\tflags = (noRender) ? flags & ~Layer::NoRender : flags | Layer::NoRender;\n\n\t\t\tImGui::TreePop();\n\t\t}\n\t}\n\n\tImGui::Columns(1);\n\tImGui::Separator();\n\n\tImGui::End();\n}\n\n\t\n}\n"
  },
  {
    "path": "application/view/layerFrame.h",
    "content": "#pragma once\n\n#include \"../engine/ecs/registry.h\"\n\nnamespace P3D::Engine {\n\tclass Layer;\n}\n\nnamespace P3D::Application {\n\t\nstruct LayerFrame {\n\n\tstatic bool doEvents;\n\tstatic bool noRender;\n\tstatic bool doUpdate;\n\tstatic bool isDisabled;\n\tstatic Engine::Layer* selectedLayer;\n\n\tstatic void onInit(Engine::Registry64& registry);\n\tstatic void onRender(Engine::Registry64& registry);\n\n};\n\t\n}\n"
  },
  {
    "path": "application/view/propertiesFrame.cpp",
    "content": "#include \"core.h\"\n\n#include \"propertiesFrame.h\"\n\n#include \"screen.h\"\n#include \"application.h\"\n#include \"extendedPart.h\"\n#include \"ecs/components.h\"\n#include \"imgui/imgui.h\"\n#include \"picker/tools/selectionTool.h\"\n\n#include <Physics3D/misc/toString.h>\n#include <Physics3D/physical.h>\n#include \"Physics3D/hardconstraints/fixedConstraint.h\"\n\n#include \"../graphics/gui/imgui/imguiExtension.h\"\n#include \"../graphics/renderer.h\"\n\nnamespace P3D::Application {\n\nGraphics::TextureResource* materialIcon;\nGraphics::TextureResource* hitboxIcon;\nGraphics::TextureResource* lightIcon;\nGraphics::TextureResource* nameIcon;\n\nEngine::Registry64::component_type deletedComponentIndex = static_cast<Engine::Registry64::component_type>(-1);\nstd::string errorModalMessage = \"\";\nbool showErrorModal = false;\n\nbool _ecs_property_frame_start(Engine::Registry64& registry, Engine::Registry64::component_type index) {\n\tstd::string label((registry).getComponentName(index));\n\tbool open = ImGui::CollapsingHeader(label.c_str(), ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_AllowItemOverlap);\n\tImGui::SameLine(ImGui::GetColumnWidth() - 40.0f);\n\tImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.0, 0.0, 0.0, 0.0));\n\tImGui::PushStyleColor(ImGuiCol_ButtonActive, GImGui->Style.Colors[ImGuiCol_HeaderActive]);\n\tImGui::PushStyleColor(ImGuiCol_ButtonHovered, GImGui->Style.Colors[ImGuiCol_HeaderHovered]);\n\tImGui::AlignTextToFramePadding();\n\tstd::string buttonLabel = \"...##button_\" + label;\n\tif (ImGui::Button(buttonLabel.c_str())) {\n\t\tImGui::OpenPopup(\"ComponentSettings\");\n\t\tdeletedComponentIndex = index;\n\t}\n\n\tImGui::PopStyleColor(3);\n\tif (ImGui::IsItemHovered())\n\t\tImGui::SetTooltip(\"Settings\");\n\n\treturn open;\n}\n\nbool _ecs_property_frame_start2(Engine::Registry64& registry, Engine::Registry64::component_type index, GLID icon = 0) {\n\tImGuiWindow* window = ImGui::GetCurrentWindow();\n\tif (window->SkipItems)\n\t\treturn false;\n\n\t// ID\n\tImGuiContext& g = *GImGui;\n\tstd::string label((registry).getComponentName(index));\n\n\tImGui::PushID(index);\n\n\tImU32 mainId = window->GetID(label.c_str());\n\tImU32 arrowId = window->GetID(\"Arrow\");\n\tImU32 editId = window->GetID(\"Edit\");\n\n\t// Constants\n\tfloat arrowWidth = g.FontSize;\n\tfloat buttonSize = g.FontSize + g.Style.FramePadding.y;\n\tfloat buttonMargin = g.Style.ItemInnerSpacing.x;\n\tfloat arrowOffset = std::abs(g.FontSize - arrowWidth) / 2.0f;\n\tfloat buttonPadding = 10.0;\n\n\tImVec2 pos = window->DC.CursorPos;\n\tImVec2 startPos = ImVec2(pos.x - window->DC.Indent.x + g.Style.WindowPadding.x, pos.y + g.Style.ItemSpacing.y);\n\tImVec2 endPos = ImVec2(startPos.x + ImGui::GetContentRegionMax().x - g.Style.WindowPadding.x, startPos.y + buttonSize);\n\tImRect arrowButton(ImVec2(startPos.x + g.Style.WindowPadding.x, startPos.y), ImVec2(startPos.x + g.Style.WindowPadding.x + arrowWidth, startPos.y + buttonSize));\n\tImRect mainButton(ImVec2(arrowButton.Max.x + buttonPadding, startPos.y), endPos);\n\tImRect iconButton(ImVec2(mainButton.Min.x + buttonPadding, startPos.y), ImVec2(mainButton.Min.x + buttonPadding + buttonSize, startPos.y + buttonSize));\n\tImVec2 textPos = ImVec2(iconButton.Max.x + buttonPadding, startPos.y + g.Style.FramePadding.y / 2.0);\n\tImRect totalSize = ImRect(startPos, endPos);\n\tImRect bb = ImRect(ImVec2(startPos.x, startPos.y - g.Style.ItemSpacing.y), ImVec2(endPos.x, endPos.y + g.Style.ItemSpacing.y));\n\n\tImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.0, 0.0, 0.0, 0.0));\n\tImGui::PushStyleColor(ImGuiCol_ButtonActive, GImGui->Style.Colors[ImGuiCol_HeaderActive]);\n\tImGui::PushStyleColor(ImGuiCol_ButtonHovered, GImGui->Style.Colors[ImGuiCol_HeaderHovered]);\n\n\t// Main button\n\tbool opened = ImGui::TreeNodeBehaviorIsOpen(mainId, ImGuiTreeNodeFlags_DefaultOpen);\n\tbool mainHovered, mainHeld;\n\tif (ImGui::ButtonBehavior(mainButton, mainId, &mainHovered, &mainHeld, ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick)) {\n\t\tif (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {\n\t\t\t\twindow->DC.StateStorage->SetInt(mainId, opened ? 0 : 1);\n\t\t}\n\t}\n\tImGui::DrawButton(totalSize, false, false, mainHeld, mainHovered, 12);\n\n\t// Arrow button\n\tbool arrowHovered, arrowHeld;\n\tif (ImGui::ButtonBehavior(arrowButton, arrowId, &arrowHovered, &arrowHeld, ImGuiButtonFlags_PressedOnClickRelease)) {\n\t\twindow->DC.StateStorage->SetInt(mainId, opened ? 0 : 1);\n\t}\n\tImGui::DrawButton(arrowButton, true, false, arrowHeld, false, 12);\n\tImGui::RenderArrow(window->DrawList, ImVec2(arrowButton.Min.x + arrowOffset, textPos.y), ImGui::GetColorU32(ImGuiCol_Text), opened ? ImGuiDir_Down : ImGuiDir_Right, 1.0f);\n\n\t// Icon\n\tImGui::DrawIcon(icon, iconButton.Min, iconButton.Max);\n\n\t// Text\n\tImGui::RenderText(textPos, label.c_str());\n\tImGui::PopStyleColor(3);\n\n\tImGui::ItemSize(bb, g.Style.FramePadding.y);\n\tImGui::ItemAdd(bb, mainId);\n\n\t//if (opened)\n\t\tImGui::TreePush(label.c_str());\n\n\tImGui::PopID();\n\n\treturn opened;\n}\n\n#define ENTITY_DISPATCH_START(index) \\\n\tif ((index) == -1) \\\n\t\tcontinue\n\n#define ENTITY_DISPATCH(registry, entity, index, type, component) \\\n\telse if ((index) == (registry).getComponentIndex<type>()) \\\n\t\trenderEntity(registry, entity, index, intrusive_cast<type>(component))\n\n#define ENTITY_DISPATCH_END(registry, entity, index, component) \\\n\telse \\\n\t\trenderEntity(registry, entity, index, component)\n\n#define ECS_PROPERTY_FRAME_START(registry, index, icon) \\\n\tif (_ecs_property_frame_start2(registry, index, icon)) { \\\n\t\tImGui::Columns(2)\n\n#define ECS_PROPERTY_FRAME_END \\\n\t\tImGui::Columns(1); \\\n\t\tImGui::TreePop(); \\\n\t}\n\nvoid renderEntity(Engine::Registry64& registry, Engine::Registry64::entity_type entity, Engine::Registry64::component_type index, const IRef<RC>& component) {\n\tstd::string label(registry.getComponentName(index));\n\n\tImGui::CollapsingHeader(label.c_str(), ImGuiTreeNodeFlags_Leaf);\n}\n\nvoid renderEntity(Engine::Registry64& registry, Engine::Registry64::entity_type entity, Engine::Registry64::component_type index, const IRef<Comp::Collider>& component) {\n\tECS_PROPERTY_FRAME_START(registry, index, ResourceManager::get<Graphics::TextureResource>(\"collider\")->getID());\n\n\tExtendedPart* selectedPart = component->part;\n\tMotion motion = selectedPart->getMotion();\n\tVec3f velocity = motion.getVelocity();\n\tVec3f angularVelocity = motion.getAngularVelocity();\n\n\tfloat mass = static_cast<float>(selectedPart->getMass());\n\tfloat friction = static_cast<float>(selectedPart->getFriction());\n\tfloat density = static_cast<float>(selectedPart->getDensity());\n\tfloat bouncyness = static_cast<float>(selectedPart->getBouncyness());\n\tVec3f conveyorEffect = selectedPart->getConveyorEffect();\n\n\tTITLE(\"Part Info\", false);\n\tPROPERTY_IF_LOCK(\"Velocity:\", ImGui::DragVec3(\"##Velocity\", velocity.data, 0, nullptr, true), selectedPart->setVelocity(velocity););\n\tPROPERTY_IF_LOCK(\"Angular velocity:\",\n\t            ImGui::DragVec3(\"##AngularVelocity\", angularVelocity.data, 0, nullptr, true),\n\t            selectedPart->setAngularVelocity(angularVelocity););\n\tPROPERTY(\"Acceleration:\", ImGui::Text(str(motion.getAcceleration()).c_str()));\n\tPROPERTY(\"Angular acceleration:\", ImGui::Text(str(motion.getAngularAcceleration()).c_str()));\n\n\tPROPERTY_IF_LOCK(\"Mass:\", ImGui::DragFloat(\"##Mass\", &mass, 0.05f), selectedPart->setMass(mass););\n\n\tTITLE(\"Part Properties\", true);\n\tPROPERTY_IF_LOCK(\"Friction:\", ImGui::DragFloat(\"##Friction\", &friction, 0.05f), selectedPart->setFriction(friction););\n\tPROPERTY_IF_LOCK(\"Density:\", ImGui::DragFloat(\"##Density\", &density, 0.05f), selectedPart->setDensity(density););\n\tPROPERTY_IF_LOCK(\"Bouncyness:\", ImGui::DragFloat(\"##Bouncyness\", &bouncyness, 0.05f), selectedPart->setBouncyness(bouncyness););\n\tPROPERTY_IF_LOCK(\"Conveyor effect:\",\n\t            ImGui::DragVec3(\"##ConveyorEffect\", conveyorEffect.data, 0, nullptr, true),\n\t            selectedPart->setConveyorEffect(conveyorEffect););\n\n\tPROPERTY(\"Inertia:\", ImGui::Text(str(selectedPart->getInertia()).c_str()));\n\n\tPhysical* selectedPartPhys = selectedPart->getPhysical();\n\tif (selectedPartPhys != nullptr) {\n\t\tconst MotorizedPhysical* physical = selectedPartPhys->mainPhysical;\n\t\tMotion comMotion = physical->getMotionOfCenterOfMass();\n\n\t\tTITLE(\"Physical Info:\", true);\n\t\tPROPERTY(\"Total impulse:\", ImGui::Text(str(physical->getTotalImpulse()).c_str()));\n\t\tPROPERTY(\"Total angular momentum:\", ImGui::Text(str(physical->getTotalAngularMomentum()).c_str()));\n\t\tPROPERTY(\"COM Velocity:\", ImGui::Text(str(comMotion.getVelocity()).c_str()));\n\t\tPROPERTY(\"COM Acceleration:\", ImGui::Text(str(comMotion.getAcceleration()).c_str()));\n\t\tPROPERTY(\"COM Angular velocity:\", ImGui::Text(str(comMotion.getAngularVelocity()).c_str()));\n\t\tPROPERTY(\"COM Angular acceleration:\", ImGui::Text(str(comMotion.getAngularAcceleration()).c_str()));\n\t}\n\n\tstatic volatile ExtendedPart* sp = nullptr;\n\tif (sp != nullptr)\n\t\tsp = selectedPart;\n\n\tTITLE(\"Debug\", true);\n\n\tPROPERTY_IF(\n\t\t\"Debug part:\", \n\t\tImGui::Button(\"Debug\"), \n\t\tLog::debug(\"Debugging part %d\", reinterpret_cast<uint64_t>(sp)); P3D_DEBUGBREAK;\n\t);\n\n\tECS_PROPERTY_FRAME_END;\n}\n\nvoid renderEntity(Engine::Registry64& registry, Engine::Registry64::entity_type entity, Engine::Registry64::component_type index, const IRef<Comp::Name>& component) {\n\tECS_PROPERTY_FRAME_START(registry, index, nameIcon->getID());\n\n\tPROPERTY(\"Name:\", ImGui::Text(component->name.c_str()));\n\n\tECS_PROPERTY_FRAME_END;\n}\n\nvoid renderEntity(Engine::Registry64& registry, Engine::Registry64::entity_type entity, Engine::Registry64::component_type index, const IRef<Graphics::Comp::Mesh>& component) {\n\tusing namespace Graphics::Comp;\n\n\tECS_PROPERTY_FRAME_START(registry, index, ResourceManager::get<Graphics::TextureResource>(\"polygon\")->getID());\n\n\tbool normals = component->flags & Mesh::Flags_Normal;\n\tbool uvs = component->flags & Mesh::Flags_UV;\n\tbool tangents = component->flags & Mesh::Flags_Tangent;\n\tbool bitangents = component->flags & Mesh::Flags_Bitangent;\n\n\tPROPERTY(\"ID:\", ImGui::Text(str(component->id).c_str()));\n\tPROPERTY(\"Visible:\", ImGui::Checkbox(\"##Visible\", &component->visible));\n\n\tTITLE(\"Flags\", true);\n\tPROPERTY(\"Normals:\", ImGui::Checkbox(\"##Normals\", &normals));\n\tPROPERTY(\"UVs:\", ImGui::Checkbox(\"##UVs\", &uvs));\n\tPROPERTY(\"Tangents:\", ImGui::Checkbox(\"##Tangents\", &tangents));\n\tPROPERTY(\"Bitangents:\", ImGui::Checkbox(\"##Bitangents\", &bitangents));\n\n\tECS_PROPERTY_FRAME_END;\n}\n\nvoid renderEntity(Engine::Registry64& registry, Engine::Registry64::entity_type entity, Engine::Registry64::component_type index, const IRef<Graphics::Comp::Material>& component) {\n\tECS_PROPERTY_FRAME_START(registry, index, materialIcon->getID());\n\n\tPROPERTY(\"Albedo\", ImGui::ColorEdit4(\"##Albedo\", component->albedo.data, ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_AlphaBar));\n\tPROPERTY(\"Metalness\", ImGui::SliderFloat(\"##Metalness\", &component->metalness, 0, 1));\n\tPROPERTY(\"Roughness\", ImGui::SliderFloat(\"##Roughness\", &component->roughness, 0, 1));\n\tPROPERTY(\"Ambient occlusion\", ImGui::SliderFloat(\"##AO\", &component->ao, 0, 1));\n\n\tTITLE(\"Textures:\", true);\n\tfloat size = ImGui::GetTextLineHeightWithSpacing();\n\tif (component->has(Graphics::Comp::Material::Map_Albedo)) \n\t\tPROPERTY(\n\t\t\t\"Albedo\",\n\t\t\tImGui::Image(reinterpret_cast<ImTextureID>(component->get(Graphics::Comp::Material::Map_Albedo)->getID()), ImVec2(size, size))\n\t\t);\n\n\n\tif (component->has(Graphics::Comp::Material::Map_Normal))\n\t\tPROPERTY(\n\t\t\t\"Normal\",\n\t\t\tImGui::Image(reinterpret_cast<ImTextureID>(component->get(Graphics::Comp::Material::Map_Normal)->getID()), ImVec2(size, size))\n\t\t);\n\n\n\tif (component->has(Graphics::Comp::Material::Map_Metalness))\n\t\tPROPERTY(\n\t\t\t\"Metalness\",\n\t\t\tImGui::Image(reinterpret_cast<ImTextureID>(component->get(Graphics::Comp::Material::Map_Metalness)->getID()), ImVec2(size, size))\n\t\t);\n\n\n\tif (component->has(Graphics::Comp::Material::Map_Roughness))\n\t\tPROPERTY(\n\t\t\t\"Roughness\",\n\t\t\tImGui::Image(reinterpret_cast<ImTextureID>(component->get(Graphics::Comp::Material::Map_Roughness)->getID()), ImVec2(size, size))\n\t\t);\n\n\n\tif (component->has(Graphics::Comp::Material::Map_AO))\n\t\tPROPERTY(\"Ambient occlusion\",\n\t\t\tImGui::Image(reinterpret_cast<ImTextureID>(component->get(Graphics::Comp::Material::Map_AO)->getID()), ImVec2(size, size))\n\t\t);\n\n\n\tif (component->has(Graphics::Comp::Material::Map_Gloss))\n\t\tPROPERTY(\"Gloss\",\n\t\t\tImGui::Image(reinterpret_cast<ImTextureID>(component->get(Graphics::Comp::Material::Map_Gloss)->getID()), ImVec2(size, size))\n\t\t);\n\n\n\tif (component->has(Graphics::Comp::Material::Map_Specular))\n\t\tPROPERTY(\n\t\t\t\"Specular\",\n\t\t\tImGui::Image(reinterpret_cast<ImTextureID>(component->get(Graphics::Comp::Material::Map_Specular)->getID()), ImVec2(size, size))\n\t\t);\n\n\n\tif (component->has(Graphics::Comp::Material::Map_Displacement))\n\t\tPROPERTY(\n\t\t\t\"Displacement\",\n\t\t\tImGui::Image(reinterpret_cast<ImTextureID>(component->get(Graphics::Comp::Material::Map_Displacement)->getID()), ImVec2(size, size))\n\t\t);\n\t\n\n\tECS_PROPERTY_FRAME_END;\n}\n\nvoid renderEntity(Engine::Registry64& registry, Engine::Registry64::entity_type entity, Engine::Registry64::component_type index, const IRef<Comp::Light>& component) {\n\tECS_PROPERTY_FRAME_START(registry, index, lightIcon->getID());\n\n\tPROPERTY(\"Color\", ImGui::ColorEdit3(\"##Color\", component->color.data, ImGuiColorEditFlags_PickerHueWheel));\n\tPROPERTY(\"Intensity\", ImGui::DragFloat(\"##Intensity\", &component->intensity));\n\n\tTITLE(\"Attenuation\", true);\n\tPROPERTY(\"Constant\", ImGui::SliderFloat(\"##Constant\", &component->attenuation.constant, 0, 2));\n\tPROPERTY(\"Linear\", ImGui::SliderFloat(\"##Linear\", &component->attenuation.linear, 0, 2));\n\tPROPERTY(\"Exponent\", ImGui::SliderFloat(\"##Exponent\", &component->attenuation.exponent, 0, 2));\n\n\tECS_PROPERTY_FRAME_END;\n}\n\nvoid renderEntity(Engine::Registry64& registry, Engine::Registry64::entity_type entity, Engine::Registry64::component_type index, const IRef<Comp::Transform>& component) {\n\n\tECS_PROPERTY_FRAME_START(registry, index, ResourceManager::get<Graphics::TextureResource>(\"cframe\")->getID());\n\n\tVec3f position = castPositionToVec3f(component->getPosition());\n\tVec3f rotation = component->getRotation().asRotationVector();\n\tDiagonalMat3f scale = component->getScale();\n\tbool standalone = component->isRootPart();\n\n\tPROPERTY_DESC(\"Standalone\", \"Whether the transform and scale is coming from the part\", ImGui::Checkbox(\"##TransformHitbox\", &standalone));\n\n\tif (component->hasOffset()) {\n\t\tTITLE(\"Global CFrame\", true);\n\t}\n\n\tPROPERTY_IF_LOCK(\n\t\t\"Position:\",\n\t\tImGui::DragVec3(\"##TransformPosition\", position.data, 0.0f, nullptr, true),\n\t\tcomponent->setPosition(castVec3fToPosition(position));\n\t);\n\n\tfloat rotationSpeeds[] = { 0.02f, 0.02f, 0.02f };\n\tPROPERTY_IF_LOCK(\n\t\t\"Rotation:\",\n\t\tImGui::DragVec3(\"##TransformRotation\", rotation.data, 0.0f, rotationSpeeds, true),\n\t\tcomponent->setRotation(Rotation::fromRotationVector(rotation));\n\t);\n\n\tfloat min = 0.01f;\n\tfloat* mins[] = { &min, &min, &min };\n\tfloat scaleSpeeds[] = { 0.01f, 0.01f, 0.01f };\n\tPROPERTY_IF_LOCK(\n\t\t\"Scale:\", \n\t\tImGui::DragVec3(\"##TransformScale\", scale.data, 1.0f, scaleSpeeds, true, mins),\n\t\tcomponent->setScale(scale);\n\t);\n\n\tif (component->hasOffset()) {\n\t\tCFrame relativeCFrame = component->getOffsetCFrame();\n\t\tVec3f relativePosition = relativeCFrame.getPosition();\n\t\tVec3f relativeRotation = relativeCFrame.getRotation().asRotationVector();\n\n\t\tTITLE(\"Relative CFrame\", true);\n\t\tPROPERTY_IF_LOCK(\n\t\t\t\"Position:\",\n\t\t\tImGui::DragVec3(\"##TransformRelativePosition\", relativePosition.data, 0.0f, nullptr, true),\n\t\t\tcomponent->setPosition(castVec3fToPosition(relativePosition));\n\t\t);\n\n\t\tPROPERTY_IF_LOCK(\n\t\t\t\"Rotation:\",\n\t\t\tImGui::DragVec3(\"##TransformRelativeRotation\", relativeRotation.data, 0.0f, rotationSpeeds, true),\n\t\t\tcomponent->setRotation(Rotation::fromRotationVector(relativeRotation));\n\t\t);\n\t}\n\n\tECS_PROPERTY_FRAME_END;\n}\n\nvoid renderEntity(Engine::Registry64& registry, Engine::Registry64::entity_type entity, Engine::Registry64::component_type index, const IRef<Comp::Hitbox>& component) {\n\tECS_PROPERTY_FRAME_START(registry, index, hitboxIcon->getID());\n\n\tbool standalone = component->isPartAttached();\n\tShape shape = component->getShape();\n\tDiagonalMat3f scale = shape.scale;\n\n\tTITLE(\"Hitbox\", false);\n\tPROPERTY_DESC(\"Standalone\", \"Whether the hitbox is coming from the part\", ImGui::Checkbox(\"##HitboxStandalone\", &standalone));\n\tPROPERTY(\"Volume:\", ImGui::Text(str(shape.getVolume()).c_str()));\n\tPROPERTY(\"Center of mass:\", ImGui::Text(str(shape.getCenterOfMass()).c_str()));\n\n\tfloat min = 0.01f;\n\tfloat* mins[] = { &min, &min, &min };\n\tPROPERTY_IF_LOCK(\"Scale:\", ImGui::DragVec3(\"HitboxScale\", scale.data, 1, nullptr, true, mins), component->setScale(scale););\n\n\tTITLE(\"Bounding box\", true);\n\tPROPERTY(\"Width:\", ImGui::Text(str(shape.getWidth()).c_str()));\n\tPROPERTY(\"Height:\", ImGui::Text(str(shape.getHeight()).c_str()));\n\tPROPERTY(\"Depth:\", ImGui::Text(str(shape.getHeight()).c_str()));\n\tPROPERTY(\"Max radius:\", ImGui::Text(str(shape.getMaxRadius()).c_str()));\n\n\tECS_PROPERTY_FRAME_END;\n}\n\nvoid renderEntity(Engine::Registry64& registry, Engine::Registry64::entity_type entity, Engine::Registry64::component_type index, const IRef<Comp::Attachment>& component) {\n\tECS_PROPERTY_FRAME_START(registry, index, ResourceManager::get<Graphics::TextureResource>(\"attachments\")->getID());\n\n\tbool isAttachmentToMainPart = !component->isAttachmentToMainPart;\n\tVec3f attachmentPosition = component->attachment->position;\n\tVec3f attachmentRotation = component->attachment->rotation.asRotationVector();\n\tbool isEditingFrame = registry.has<Comp::Transform>(entity);\n\n\tPROPERTY(\n\t\t\"Is attachment to the main part:\",\n\t\tImGui::Checkbox(\"##ToMainPart\", &isAttachmentToMainPart);\n\t);\n\n\tif (isEditingFrame) {\n\t\tPROPERTY_DESC(\n\t\t\t\"Position:\", \n\t\t\t\"Use the tranform component to edit the position\", \n\t\t\tImGui::Text(\"(%f, %f, %f)\", attachmentPosition.x, attachmentPosition.y, attachmentPosition.z)\n\t\t);\n\t\tPROPERTY_DESC(\n\t\t\t\"Rotation:\",\n\t\t\t\"Use the tranform component to edit the rotation\",\n\t\t\tImGui::Text(\"(%f, %f, %f)\", attachmentRotation.x, attachmentRotation.y, attachmentRotation.z);\n\t\t);\n\t} else {\n\t\tPROPERTY_IF_LOCK(\n\t\t\t\"Position:\",\n\t\t\tImGui::DragVec3(\"##AttachmentPosition\", attachmentPosition.data, 0.0f, nullptr, true),\n\t\t\tcomponent->setAttachment(CFrame(attachmentPosition, Rotation::fromRotationVector(attachmentRotation)));\n\t\t);\n\n\t\tfloat rotationSpeeds[] = { 0.02f, 0.02f, 0.02f };\n\t\tPROPERTY_IF_LOCK(\n\t\t\t\"Rotation:\",\n\t\t\tImGui::DragVec3(\"##AttachmentRotation\", attachmentRotation.data, 0.0f, rotationSpeeds, true),\n\t\t\tcomponent->setAttachment(CFrame(attachmentPosition, Rotation::fromRotationVector(attachmentRotation)));\n\t\t);\n\n\t\tPROPERTY_IF(\n\t\t\t\"\",\n\t\t\tImGui::Button(\"Edit\"),\n\t\t\tregistry.add<Comp::Transform>(entity, component->getMainPart(), component->attachment)->addCallback([] () {Log::debug(\"Edit\"); });\n\t\t);\n\t}\n\n\tECS_PROPERTY_FRAME_END;\n}\n\nvoid renderSoftlink(Engine::Registry64& registry, Engine::Registry64::entity_type entity, Comp::SoftLink* component) {\n\tExtendedPart* partA = reinterpret_cast<ExtendedPart*>(component->link->attachedPartA.part);\n\tExtendedPart* partB = reinterpret_cast<ExtendedPart*>(component->link->attachedPartB.part);\n\tif (partA == nullptr || partB == nullptr)\n\t\treturn;\n\n\tVec3f positionA = component->getPositionA();\n\tVec3f positionB = component->getPositionB();\n\tIRef<Comp::Name> nameA = registry.get<Comp::Name>(partA->entity);\n\tIRef<Comp::Name> nameB = registry.get<Comp::Name>(partB->entity);\n\tIRef<Comp::Transform> transform = registry.get<Comp::Transform>(entity);\n\n\tbool isEditingFrame = transform.valid() && transform->isOffsetStoredRemote();\n\tbool isEditingFrameA = isEditingFrame && std::get<CFrame*>(transform->offset) == &component->link->attachedPartA.attachment;\n\tbool isEditingFrameB = isEditingFrame && std::get<CFrame*>(transform->offset) == &component->link->attachedPartB.attachment;\n\t\n\tTITLE(\"Attachment A\", false);\n\tPROPERTY(\"Part\", ImGui::Text(nameA.valid() ? nameA->name.c_str() : \"Part A\"));\n\tif (isEditingFrameA) {\n\t\tPROPERTY_DESC(\n\t\t\t\"Position:\",\n\t\t\t\"Use the tranform component to edit the position\",\n\t\t\tImGui::Text(\"(%f, %f, %f)\", positionA.x, positionA.y, positionA.z)\n\t\t);\n\t} else {\n\t\tPROPERTY_IF_LOCK(\"Position\", ImGui::DragVec3(\"##TransformPositionA\", positionA.data, 0, nullptr, true), component->setPositionA(positionA););\n\t\tPROPERTY_IF(\n\t\t\t\"\",\n\t\t\tImGui::Button(\"Edit##EditCFrameA\"),\n\t\t\tregistry.add<Comp::Transform>(entity, partA, &component->link->attachedPartA.attachment); SelectionTool::selection.recalculateSelection();\n\t\t);\n\t}\n\n\tTITLE(\"Attachment B\", true);\n\tPROPERTY(\"Part\", ImGui::Text(nameB.valid() ? nameB->name.c_str() : \"Part B\"));\n\tif (isEditingFrameB) {\n\t\tPROPERTY_DESC(\n\t\t\t\"Position:\",\n\t\t\t\"Use the tranform component to edit the position\",\n\t\t\tImGui::Text(\"(%f, %f, %f)\", positionB.x, positionB.y, positionB.z)\n\t\t);\n\t} else {\n\t\tPROPERTY_IF_LOCK(\"Position\", ImGui::DragVec3(\"##TransformPositionB\", positionB.data, 0, nullptr, true), component->setPositionB(positionB););\n\t\tPROPERTY_IF(\n\t\t\t\"\",\n\t\t\tImGui::Button(\"Edit##EditCFrameB\"),\n\t\t\tregistry.add<Comp::Transform>(entity, partB, &component->link->attachedPartB.attachment); SelectionTool::selection.recalculateSelection();\n\t\t);\n\t}\n}\n\nvoid renderEntity(Engine::Registry64& registry, Engine::Registry64::entity_type entity, Engine::Registry64::component_type index, const IRef<Comp::MagneticLink>& component) {\n\tECS_PROPERTY_FRAME_START(registry, index, ResourceManager::get<Graphics::TextureResource>(\"Magnetic Link\")->getID());\n\n\trenderSoftlink(registry, entity, component.get());\n\n\tMagneticLink* link = dynamic_cast<MagneticLink*>(component->link);\n\tfloat magneticStrength = static_cast<float>(link->magneticStrength);\n\n\tTITLE(\"Properties\", true);\n\tPROPERTY_IF_LOCK(\n\t\t\"Magnetic strength\",\n\t\tImGui::DragFloat(\"##MagneticStrength\", &magneticStrength, 0, 0.1f, true),\n\t\tlink->magneticStrength = static_cast<double>(magneticStrength);\n\t);\n\n\tECS_PROPERTY_FRAME_END;\n}\n\nvoid renderEntity(Engine::Registry64& registry, Engine::Registry64::entity_type entity, Engine::Registry64::component_type index, const IRef<Comp::ElasticLink>& component) {\n\tECS_PROPERTY_FRAME_START(registry, index, ResourceManager::get<Graphics::TextureResource>(\"Elastic Link\")->getID());\n\n\trenderSoftlink(registry, entity, component.get());\n\n\tElasticLink* link = dynamic_cast<ElasticLink*>(component->link);\n\tfloat restLenght = static_cast<float>(link->restLength);\n\tfloat stiffness = static_cast<float>(link->stiffness);\n\n\tTITLE(\"Properties\", true);\n\tPROPERTY_IF_LOCK(\"Length\", ImGui::DragFloat(\"##RestLength\", &restLenght, 0, 0.1f, true), link->restLength = static_cast<double>(restLenght););\n\tPROPERTY_IF_LOCK(\"Stiffness\", ImGui::DragFloat(\"##Stiffness\", &stiffness, 0, 0.1f, true), link->stiffness = static_cast<double>(stiffness););\n\n\tECS_PROPERTY_FRAME_END;\n}\n\nvoid renderEntity(Engine::Registry64& registry, Engine::Registry64::entity_type entity, Engine::Registry64::component_type index, const IRef<Comp::SpringLink>& component) {\n\tECS_PROPERTY_FRAME_START(registry, index, ResourceManager::get<Graphics::TextureResource>(\"Spring Link\")->getID());\n\n\trenderSoftlink(registry, entity, component.get());\n\n\tSpringLink* link = dynamic_cast<SpringLink*>(component->link);\n\tfloat restLenght = static_cast<float>(link->restLength);\n\tfloat stiffness = static_cast<float>(link->stiffness);\n\n\tTITLE(\"Properties\", true);\n\tPROPERTY_IF_LOCK(\"Length\", ImGui::DragFloat(\"##RestLength\", &restLenght, 0, 0.1f, true), link->restLength = static_cast<double>(restLenght););\n\tPROPERTY_IF_LOCK(\"Stiffness\", ImGui::DragFloat(\"##Stiffness\", &stiffness, 0, 0.1f, true), link->stiffness = static_cast<double>(stiffness););\n\n\tECS_PROPERTY_FRAME_END;\n}\n\nvoid renderEntity(Engine::Registry64& registry, Engine::Registry64::entity_type entity, Engine::Registry64::component_type index, const IRef<Comp::AlignmentLink>& component) {\n\tECS_PROPERTY_FRAME_START(registry, index, ResourceManager::get<Graphics::TextureResource>(\"Alignmnent Link\")->getID());\n\n\trenderSoftlink(registry, entity, component.get());\n\n\tAlignmentLink* link = dynamic_cast<AlignmentLink*>(component->link);\n\n\tECS_PROPERTY_FRAME_END;\n}\n\nvoid renderEntity(Engine::Registry64& registry, Engine::Registry64::entity_type entity, Engine::Registry64::component_type index, const IRef<Comp::FixedConstraint>& component) {\n\tECS_PROPERTY_FRAME_START(registry, index, ResourceManager::get<Graphics::TextureResource>(\"Fixed Constraint\")->getID());\n\n\tFixedConstraint* link = dynamic_cast<FixedConstraint*>(component->hardConstraint->constraintWithParent.get());\n\n\tCFrame* parentCFrame = component->getParentAttachment();\n\tVec3f parentPosition = parentCFrame->position;\n\tVec3f parentRotation = parentCFrame->rotation.asRotationVector();\n\n\tCFrame* childCFrame = component->getChildAttachment();\n\tVec3f childPosition = childCFrame->position;\n\tVec3f childRotation = childCFrame->rotation.asRotationVector();\n\n\t//IRef<Comp::Name> nameA = registry.get<Comp::Name>(component->hardConstraint->constraintWithParent->);\n\t//IRef<Comp::Name> nameB = registry.get<Comp::Name>(partB->entity);\n\n\tTITLE(\"Parent\", true);\n\tPROPERTY(\"Part\", ImGui::Text(\"Part A\"));\n\tPROPERTY_IF_LOCK(\n\t\t\"Position\",\n\t\tImGui::DragVec3(\"##ParentPosition\", parentPosition.data, 0, nullptr, true),\n\t\tparentCFrame->position = parentPosition;\n\t);\n\tPROPERTY_IF_LOCK(\n\t\t\"Rotation\",\n\t\tImGui::DragVec3(\"##ParentRotation\", parentRotation.data, 0, nullptr, true),\n\t\tparentCFrame->rotation = Rotation::fromRotationVector(parentRotation);\n\t);\n\n\tTITLE(\"Child\", true);\n\tPROPERTY(\"Part\", ImGui::Text(\"Part B\"));\n\tPROPERTY_IF_LOCK(\n\t\t\"Position\",\n\t\tImGui::DragVec3(\"##ChildPosition\", childPosition.data, 0, nullptr, true),\n\t\tchildCFrame->position = childPosition;\n\t);\n\tPROPERTY_IF_LOCK(\n\t\t\"Rotation\",\n\t\tImGui::DragVec3(\"##ChildRotation\", childRotation.data, 0, nullptr, true),\n\t\tchildCFrame->rotation = Rotation::fromRotationVector(childRotation);\n\t);\n\n\tECS_PROPERTY_FRAME_END;\n}\n\n\nvoid PropertiesFrame::onInit(Engine::Registry64& registry) {\n\tmaterialIcon = ResourceManager::add<Graphics::TextureResource>(\"material\", \"../res/textures/icons/Material.png\");\n\thitboxIcon = ResourceManager::add<Graphics::TextureResource>(\"hitbox\", \"../res/textures/icons/Hitbox.png\");\n\tlightIcon = ResourceManager::add<Graphics::TextureResource>(\"light\", \"../res/textures/icons/Light.png\");\n\tnameIcon = ResourceManager::add<Graphics::TextureResource>(\"name\", \"../res/textures/icons/Name.png\");\n}\n\nvoid PropertiesFrame::onRender(Engine::Registry64& registry) {\n\tImGui::Begin(\"Properties\");\n\n\tif (SelectionTool::selection.empty()) {\n\t\tstd::string label = \"Select an entity to see properties\";\n\t\tauto [wx, wy] = ImGui::GetContentRegionAvail();\n\t\tauto [tx, ty] = ImGui::CalcTextSize(label.c_str());\n\t\tauto [cx, cy] = ImGui::GetCursorPos();\n\t\tImVec2 cursor = ImVec2(cx + (wx - tx) / 2.0f, cy + (wy - ty) / 2.0f);\n\t\tImGui::SetCursorPos(cursor);\n\t\tImGui::Text(label.c_str());\n\n\t\tImGui::End();\n\t\treturn;\n\t}\n\n\tif (SelectionTool::selection.isMultiSelection()) {\n\t\tstd::string label = \"Multiple entities selected\";\n\t\tauto [wx, wy] = ImGui::GetContentRegionAvail();\n\t\tauto [tx, ty] = ImGui::CalcTextSize(label.c_str());\n\t\tauto [cx, cy] = ImGui::GetCursorPos();\n\t\tImVec2 cursor = ImVec2(cx + (wx - tx) / 2.0f, cy + (wy - ty) / 2.0f);\n\t\tImGui::SetCursorPos(cursor);\n\t\tImGui::Text(label.c_str());\n\n\t\tImGui::End();\n\t\treturn;\n\t}\n\n\t// Dispatch component frames\n\tEngine::Registry64::entity_type selectedEntity = SelectionTool::selection.first().value();\n\tauto allComponents = registry.getComponents(selectedEntity);\n\tfor (auto [index, components] : allComponents) {\n\t\tauto component = *components.begin();\n\t\tENTITY_DISPATCH_START(index);\n\t\tENTITY_DISPATCH(registry, selectedEntity, index, Comp::Name, component);\n\t\tENTITY_DISPATCH(registry, selectedEntity, index, Comp::Transform, component);\n\t\tENTITY_DISPATCH(registry, selectedEntity, index, Comp::Collider, component);\n\t\tENTITY_DISPATCH(registry, selectedEntity, index, Graphics::Comp::Mesh, component);\n\t\tENTITY_DISPATCH(registry, selectedEntity, index, Graphics::Comp::Material, component);\n\t\tENTITY_DISPATCH(registry, selectedEntity, index, Comp::Light, component);\n\t\tENTITY_DISPATCH(registry, selectedEntity, index, Comp::Hitbox, component);\n\t\tENTITY_DISPATCH(registry, selectedEntity, index, Comp::Attachment, component);\n\t\tENTITY_DISPATCH(registry, selectedEntity, index, Comp::MagneticLink, component);\n\t\tENTITY_DISPATCH(registry, selectedEntity, index, Comp::SpringLink, component);\n\t\tENTITY_DISPATCH(registry, selectedEntity, index, Comp::ElasticLink, component);\n\t\tENTITY_DISPATCH(registry, selectedEntity, index, Comp::AlignmentLink, component);\n\t\tENTITY_DISPATCH(registry, selectedEntity, index, Comp::FixedConstraint, component);\n\t\tENTITY_DISPATCH_END(registry, selectedEntity, index, component);\n\t}\n\n\t// Add new Component\n\tif (ImGui::Button(\"Add new component...\", ImVec2(-1, 0)))\n\t\tImGui::OpenPopup(\"Add component\");\n\tif (ImGui::BeginPopupModal(\"Add component\")) {\n\t\tstd::vector<const char*> components;\n\t\tfor (Engine::Registry64::component_type index = 0; index < Engine::Registry64::component_index<void>::index(); index++)\n\t\t\tcomponents.push_back(registry.getComponentName(index).data());\n\n\t\tstatic int item_current = 0;\n\t\tImGui::SetNextItemWidth(-1);\n\t\tImGui::ListBox(\"##ComponentsModal\", &item_current, components.data(), components.size(), 6);\n\n\t\tif (ImGui::Button(\"Cancel\", ImVec2(-1, 0)))\n\t\t\tImGui::CloseCurrentPopup();\n\n\t\tImGui::EndPopup();\n\t}\n\n\t// Component Settings\n\tif (ImGui::BeginPopup(\"ComponentSettings\")) {\n\t\tif (ImGui::MenuItem(\"Delete component\")) {\n\t\t\tif (deletedComponentIndex != static_cast<Engine::Registry64::component_type>(-1)) {\n\t\t\t\tif (deletedComponentIndex == registry.getComponentIndex<Comp::Transform>()) {\n\t\t\t\t\terrorModalMessage = \"This component can not be deleted.\";\n\t\t\t\t\tshowErrorModal = true;\n\t\t\t\t} else {\n\t\t\t\t\tregistry.remove(selectedEntity, deletedComponentIndex);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (ImGui::MenuItem(\"Component info\")) { }\n\t\tImGui::EndPopup();\n\t}\n\n\t// Error Modal\n\tif (showErrorModal)\n\t\tImGui::OpenPopup(\"Error##ErrorModal\");\n\n\tif (ImGui::BeginPopupModal(\"Error##ErrorModal\", 0, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {\n\t\tImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), errorModalMessage.c_str());\n\t\tif (ImGui::Button(\"Ok##ErrorModalClose\", ImVec2(-1, 0))) {\n\t\t\tImGui::CloseCurrentPopup();\n\t\t\tshowErrorModal = false;\n\t\t}\n\t\tImGui::EndPopup();\n\t}\n\n\tImGui::End();\n}\n\n}\n"
  },
  {
    "path": "application/view/propertiesFrame.h",
    "content": "#pragma once\n\n#include \"../engine/ecs/registry.h\"\n\nnamespace P3D::Application {\n\n\tstruct PropertiesFrame {\n\n\t\tstatic void onInit(Engine::Registry64& registry);\n\t\tstatic void onRender(Engine::Registry64& registry);\n\n\t};\n\n}\n"
  },
  {
    "path": "application/view/resourceFrame.cpp",
    "content": "#include \"core.h\"\n\n#include \"resourceFrame.h\"\n\n#include \"imgui/imgui.h\"\n#include \"shader/shaders.h\"\n#include \"../util/resource/resourceManager.h\"\n#include \"../graphics/gui/imgui/imguiExtension.h\"\n#include \"../graphics/resource/fontResource.h\"\n#include \"../graphics/resource/textureResource.h\"\n#include \"../graphics/texture.h\"\n#include \"../graphics/font.h\"\n\nnamespace P3D::Application {\n\nResource* ResourceFrame::selectedResource = nullptr;\n\t\nvoid ResourceFrame::renderTextureInfo(Texture* texture) {\n\tImGui::Text(\"ID: %d\", texture->getID());\n\tImGui::Text(\"Width: %d\", texture->getWidth());\n\tImGui::Text(\"Height: %d\", texture->getHeight());\n\tImGui::Text(\"Channels: %d\", texture->getChannels());\n\tImGui::Text(\"Unit: %d\", texture->getUnit());\n\n\tif (ImGui::TreeNodeEx(\"Preview\", ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_DefaultOpen)) {\n\t\tfloat cw = ImGui::GetColumnWidth();\n\t\tfloat ch = ImGui::GetWindowHeight();\n\t\tfloat tw = ch * texture->getAspect();\n\t\tfloat th = cw / texture->getAspect();\n\n\t\tImVec2 size;\n\t\tif (th > ch)\n\t\t\tsize = ImVec2(tw, ch);\n\t\telse\n\t\t\tsize = ImVec2(cw, th);\n\n\t\tVec4f c = Colors::ACCENT;\n\t\tImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing());\n\t\tImGui::Image((void*) (intptr_t) texture->getID(), size, ImVec2(0, 0), ImVec2(1, 1), ImVec4(1, 1, 1, 1), ImVec4(c.x, c.y, c.z, c.w));\n\n\t\tImGui::TreePop();\n\t}\n}\n\nvoid ResourceFrame::renderFontInfo(Font* font) {\n\tif (ImGui::TreeNode(\"Atlas\")) {\n\t\trenderTextureInfo(font->getAtlas().get());\n\t\tImGui::TreePop();\n\t}\n\n\tchar selectedCharacter = 0;\n\tif (ImGui::TreeNode(\"Characters\")) {\n\t\tfor (int i = 0; i < CHARACTER_COUNT; i++) {\n\t\t\tCharacter& character = font->getCharacter(i);\n\n\t\t\tfloat s = float(character.x) / font->getAtlasWidth();\n\t\t\tfloat t = float(character.y) / font->getAtlasHeight();\n\t\t\tfloat ds = float(character.width) / font->getAtlasWidth();\n\t\t\tfloat dt = float(character.height) / font->getAtlasHeight();\n\n\t\t\tImGui::ImageButton((void*) (intptr_t) font->getAtlas()->getID(), ImVec2(character.width / 2.0f, character.height / 2.0f), ImVec2(s, t), ImVec2(s + ds, t + dt));\n\t\t\tfloat last_button_x2 = ImGui::GetItemRectMax().x;\n\t\t\tfloat next_button_x2 = last_button_x2 + ImGui::GetStyle().ItemSpacing.x + character.width / 2.0f; // Expected position if next button was on same line\n\t\t\tif (i + 1 < CHARACTER_COUNT && next_button_x2 < ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x)\n\t\t\t\tImGui::SameLine();\n\t\t}\n\t\tif (ImGui::TreeNodeEx(\"Info\", ImGuiTreeNodeFlags_DefaultOpen)) {\n\t\t\tCharacter& c = font->getCharacter(selectedCharacter);\n\t\t\tImGui::Text(\"Character: %s\", std::string(1, static_cast<char>(selectedCharacter)).c_str());\n\t\t\tImGui::Text(\"ID: %d\", c.id);\n\t\t\tImGui::Text(\"Origin: (%d, %d)\", c.x, c.x);\n\t\t\tImGui::Text(\"Size: (%d, %d)\", c.width, c.height);\n\t\t\tImGui::Text(\"Bearing: (%d, %d)\", c.bx, c.by);\n\t\t\tImGui::Text(\"Advance: %d\", c.advance);\n\t\t\tImGui::TreePop();\n\t\t}\n\t\tImGui::TreePop();\n\t}\n}\n\nvoid renderPropertyEditor(ShaderResource* shader, Property& property) {\n\tImGui::PushID(&property);\n\tstd::string name(property.name);\n\tstd::string uniform(property.uniform);\n\n\tauto renderVectorProperty = [&] (const char** labels, float* data, float* speed, float** min, float** max) -> bool {\n\t\tfor (std::size_t i = 0; i < property.defaults.size(); i++) {\n\t\t\tProperty::Default& def = property.defaults.at(i);\n\t\t\t*(data + i) = def.value;\n\t\t\t*(speed + i) = def.step.value_or(0.1f);\n\t\t\t*(min + i) = def.range.has_value() ? &def.range->min : nullptr;\n\t\t\t*(max + i) = def.range.has_value() ? &def.range->max : nullptr;\n\t\t}\n\n\t\tPROPERTY_DESC_IF(name.c_str(), uniform.c_str(), ImGui::DragVecN(\"\", labels, data, property.defaults.size(), 0.0f, speed, false, min, max),\n\t\t\tfor (std::size_t i = 0; i < property.defaults.size(); i++) \n\t\t\t\tproperty.defaults.at(i).value = data[i];\n\t\t\treturn true;\n\t\t);\n\n\t\treturn false;\n\t};\n\n\tauto renderMatrixProperty = [&] (const char** labels, float* data, float* speed, float** min, float** max) -> bool {\t\n\t\tfor (std::size_t i = 0; i < property.defaults.size(); i++) {\n\t\t\tProperty::Default& def = property.defaults.at(i);\n\t\t\t*(data + i) = def.value;\n\t\t\t*(speed + i) = def.step.value_or(0.1f);\n\t\t\t*(min + i) = def.range.has_value() ? &def.range->min : nullptr;\n\t\t\t*(max + i) = def.range.has_value() ? &def.range->max : nullptr;\n\t\t}\n\n\t\tstd::size_t size = 2;\n\t\tif (property.defaults.size() == 9)\n\t\t\tsize = 3;\n\t\telse if (property.defaults.size() == 16)\n\t\t\tsize = 4;\n\t\t\n\t\tbool result = false;\n\t\tPROPERTY_DESC_IF(name.c_str(), uniform.c_str(), ImGui::DragVecN(\"\", labels, data, size, 0.0f, speed, false, min, max),\n\t\t\tfor (std::size_t i = 0; i < property.defaults.size(); i++)\n\t\t\t\tproperty.defaults.at(i).value = data[i];\n\n\t\t\tresult = true;\n\t\t);\n\t\t\n\t\tfor (std::size_t j = 1; j < size; j++) {\n\t\t\tstd::size_t offset = j * size;\n\t\t\tPROPERTY_IF(\"\", ImGui::DragVecN(\"\", labels + offset, data + offset, size, 0.0f, speed, false, min + offset, max + offset),\n\t\t\t\tfor (std::size_t i = 0; i < property.defaults.size(); i++)\n\t\t\t\t\tproperty.defaults.at(i).value = data[i];\n\t\t\t);\n\n\t\t\tresult = true;\n\t\t}\n\n\t\treturn result;\n\t};\n\t\n\tswitch (property.type) {\n\t\tcase Property::Type::None: \n\t\t\tbreak;\n\t\tcase Property::Type::Bool: {\n\t\t\tProperty::Default& def = property.defaults[0];\n\t\t\tbool value = def.value != 0.0f;\n\t\t\tPROPERTY_DESC_IF(name.c_str(), uniform.c_str(), ImGui::Checkbox(\"\", &value),\n\t\t\t\tdef.value = value ? 1.0f : 0.0f;\n\t\t\t\tshader->bind();\n\t\t\t\tshader->setUniform(uniform, value);\n\t\t\t);\n\t\t\t\t\n\t\t\tbreak;\n\t\t} case Property::Type::Int: {\n\t\t\tProperty::Default& def = property.defaults[0];\n\t\t\tif (def.range.has_value()) {\n\t\t\t\tint value = static_cast<int>(def.value);\n\t\t\t\tPROPERTY_DESC_IF(name.c_str(), uniform.c_str(), ImGui::DragInt(\"\", &value, 1.0f, static_cast<int>(def.range->min), static_cast<int>(def.range->max)),\n\t\t\t\t\tdef.value = static_cast<float>(value);\n\t\t\t\t\tshader->bind();\n\t\t\t\t\tshader->setUniform(uniform, value);\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tint value = static_cast<int>(def.value);\n\t\t\t\tPROPERTY_DESC_IF(name.c_str(), uniform.c_str(), ImGui::InputInt(\"\", &value),\n\t\t\t\t\tdef.value = static_cast<float>(value);\n\t\t\t\t\tshader->bind();\n\t\t\t\t\tshader->setUniform(uniform, value);\n\t\t\t\t);\n\t\t\t}\n\t\t} break;\n\t\tcase Property::Type::Float: {\n\t\t\tProperty::Default& def = property.defaults[0];\n\t\t\tif (def.range.has_value()) {\n\t\t\t\tPROPERTY_DESC_IF(name.c_str(), uniform.c_str(), ImGui::DragFloat(\"\", &def.value, 1.0f, def.range->min, def.range->max),\n\t\t\t\t\tshader->bind();\n\t\t\t\t\tshader->setUniform(uniform, def.value);\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tPROPERTY_DESC_IF(name.c_str(), uniform.c_str(), ImGui::InputFloat(\"\", &def.value),\n\t\t\t\t\tshader->bind();\n\t\t\t\t\tshader->setUniform(uniform, def.value);\n\t\t\t\t);\n\t\t\t}\n\t\t} break;\n\t\tcase Property::Type::Vec2: {\n\t\t\tfloat data[2], speed[2], *min[2], *max[2];\n\t\t\tconst char* labels[2] { \"X\", \"Y\" };\n\t\t\trenderVectorProperty(labels, data, speed, min, max);\n\t\t\tshader->bind();\n\t\t\tshader->setUniform(uniform, Vec2f { data[0], data[1] });\n\t\t} break;\n\t\tcase Property::Type::Vec3: {\n\t\t\tfloat data[3], speed[3], *min[3], *max[3];\n\t\t\tconst char* labels[3] { \"X\", \"Y\", \"Z\" };\n\t\t\trenderVectorProperty(labels, data, speed, min, max);\n\t\t\tshader->bind();\n\t\t\tshader->setUniform(uniform, Vec3f { data[0], data[1], data[2] });\n\t\t} break;\n\t\tcase Property::Type::Vec4: {\n\t\t\tfloat data[4], speed[4], *min[4], *max[4];\n\t\t\tconst char* labels[4] { \"X\", \"Y\", \"Z\", \"W\" };\n\t\t\trenderVectorProperty(labels, data, speed, min, max);\n\t\t\tshader->bind();\n\t\t\tshader->setUniform(uniform, Vec4f { data[0], data[1], data[2], data[3] });\n\t\t} break;\n\t\tcase Property::Type::Mat2: {\n\t\t\tfloat data[4], speed[4], *min[4], *max[4];\n\t\t\tconst char* labels[4] { \"00\", \"01\", \"10\", \"11\" };\n\t\t\trenderMatrixProperty(labels, data, speed, min, max);\n\t\t\tshader->bind();\n\t\t\tshader->setUniform(uniform, Mat2f {\n\t\t\t\tdata[0], data[1], \n\t\t\t\tdata[2], data[3] });\n\t\t} break;\n\t\tcase Property::Type::Mat3: {\n\t\t\tfloat data[9], speed[9], *min[9], *max[9];\n\t\t\tconst char* labels[9] { \"00\", \"01\", \"02\", \"10\", \"11\", \"12\", \"20\", \"21\", \"22\" };\n\t\t\trenderMatrixProperty(labels, data, speed, min, max);\n\t\t\tshader->bind();\n\t\t\tshader->setUniform(uniform, Mat3f { \n\t\t\t\tdata[0], data[1], data[2],\n\t\t\t\tdata[3], data[4], data[5],\n\t\t\t\tdata[6], data[7], data[8] });\n\t\t} break;\n\t\tcase Property::Type::Mat4: {\n\t\t\tfloat data[16], speed[16], *min[16], *max[16];\n\t\t\tconst char* labels[16] { \"00\", \"01\", \"02\", \"03\", \"10\", \"11\", \"12\", \"13\", \"20\", \"21\", \"22\", \"23\", \"30\", \"31\", \"32\", \"33\" };\n\t\t\trenderMatrixProperty(labels, data, speed, min, max);\n\t\t\tshader->bind();\n\t\t\tshader->setUniform(uniform, Mat3f {\n\t\t\t\tdata[0], data[1], data[2], data[3],\n\t\t\t\tdata[4], data[5], data[6], data[7],\n\t\t\t\tdata[8], data[9], data[10], data[11],\n\t\t\t\tdata[12], data[13], data[14], data[15] });\n\t\t} break;\n\t\tcase Property::Type::Col3: {\n\t\t\tfloat data[3], speed[3], *min[3], *max[3];\n\t\t\tconst char* labels[3] { \"R\", \"G\", \"B\" };\n\t\t\trenderVectorProperty(labels, data, speed, min, max);\n\t\t\tshader->bind();\n\t\t\tshader->setUniform(uniform, Vec3f { data[0], data[1], data[2] });\n\t\t} break;\n\t\tcase Property::Type::Col4: {\n\t\t\tfloat data[4], speed[4], *min[4], *max[4];\n\t\t\tconst char* labels[4] { \"R\", \"G\", \"B\", \"A\" };\n\t\t\trenderVectorProperty(labels, data, speed, min, max);\n\t\t\tshader->bind();\n\t\t\tshader->setUniform(uniform, Vec4f { data[0], data[1], data[2], data[3] });\n\t\t} break;\n\t}\n\t\n\tImGui::PopID();\n}\n\t\nvoid ResourceFrame::renderShaderInfo(ShaderResource* shader) {\n\tImGui::BeginChild(\"Shaders\");\n\n\tPROPERTY_FRAME_START(\"Properties\");\n\n\tfor (Property& property : shader->properties)\n\t\trenderPropertyEditor(shader, property);\n\n\tPROPERTY_FRAME_END;\n\t\n\t/*PROPERTY_FRAME_START(\"Code\");\n\tif (ImGui::BeginTabBar(\"##tabs\")) {\n\t\tfor (const auto& [id, stage] : shader->stages) {\n\t\t\tif (ImGui::BeginTabItem(Shader::getStageName(id).c_str())) {\n\t\t\t\tstd::string code(stage.view);\n\t\t\t\tImGui::TextWrapped(\"%s\", code.c_str());\n\t\t\t}\n\t\t}\n\n\t\tImGui::EndTabBar();\n\t}\n\tPROPERTY_FRAME_END;*/\n\t\n\tImGui::EndChild();\n}\n\nvoid ResourceFrame::onInit(Engine::Registry64& registry) {\n}\n\nvoid ResourceFrame::onRender(Engine::Registry64& registry) {\n\tImGui::Begin(\"Resources\");\n\t\n\tImGui::Columns(2, 0, true);\n\tImGui::Separator();\n\n\tauto map = ResourceManager::getResourceMap();\n\tfor (auto& [name, resources] : map) {\n\t\tif (ImGui::TreeNodeEx(name.c_str(), ImGuiTreeNodeFlags_SpanFullWidth)) {\n\t\t\tfor (Resource* resource : resources) {\n\t\t\t\tif (ImGui::Selectable(resource->getName().c_str(), resource == selectedResource))\n\t\t\t\t\tselectedResource = resource;\n\t\t\t}\n\t\t\tImGui::TreePop();\n\t\t}\n\t}\n\n\tImGui::NextColumn();\n\n\tif (selectedResource) {\n\t\tImGui::Text(\"Name: %s\", selectedResource->getName().c_str());\n\t\tImGui::Text(\"Path: %s\", selectedResource->getPath().c_str());\n\t\tImGui::Text(\"Type: %s\", selectedResource->getTypeName().c_str());\n\t\tswitch (selectedResource->getType()) {\n\t\t\tcase ResourceType::Texture:\n\t\t\t\trenderTextureInfo(static_cast<TextureResource*>(selectedResource));\n\t\t\t\tbreak;\n\t\t\tcase ResourceType::Font:\n\t\t\t\trenderFontInfo(static_cast<FontResource*>(selectedResource));\n\t\t\t\tbreak;\n\t\t\tcase ResourceType::Shader:\n\t\t\t\trenderShaderInfo(static_cast<ShaderResource*>(selectedResource));\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tImGui::Text(\"Visual respresentation not supported.\");\n\t\t\t\tbreak;\n\t\t}\n\t} else {\n\t\tImGui::Text(\"No resource selected.\");\n\t}\n\n\tImGui::Columns(1);\n\tImGui::Separator();\n\t\n\tImGui::End();\n}\n\t\n}\n"
  },
  {
    "path": "application/view/resourceFrame.h",
    "content": "#pragma once\n\n#include \"../engine/ecs/registry.h\"\n\nnamespace P3D::Graphics {\n\tclass Texture;\n\tclass Font;\n\tstruct ShaderStage;\n\tclass ShaderResource;\n}\n\nclass Resource;\n\nnamespace P3D::Application {\n\t\nstruct ResourceFrame {\nprivate:\n\tstatic void renderTextureInfo(Graphics::Texture* texture);\n\tstatic void renderFontInfo(Graphics::Font* font);\n\tstatic void renderShaderInfo(Graphics::ShaderResource* shader);\n\t\npublic:\n\tstatic Resource* selectedResource;\n\n\tstatic void onInit(Engine::Registry64& registry);\n\tstatic void onRender(Engine::Registry64& registry);\n\n};\n\t\n}\n"
  },
  {
    "path": "application/view/screen.cpp",
    "content": "#include \"core.h\"\n\n#include \"screen.h\"\n\n#include <GL/glew.h>\n#include <GLFW/glfw3.h>\n\n#include \"../graphics/renderer.h\"\n#include \"../graphics/glfwUtils.h\"\n#include \"../graphics/texture.h\"\n#include \"shader/shaders.h\"\n\n#include \"../graphics/mesh/primitive.h\"\n#include \"../graphics/debug/visualDebug.h\"\n#include \"../graphics/buffers/frameBuffer.h\"\n#include \"../engine/options/keyboardOptions.h\"\n#include \"../input/standardInputHandler.h\"\n#include \"../worlds.h\"\n#include \"../engine/event/windowEvent.h\"\n#include \"../util/resource/resourceManager.h\"\n#include \"layer/skyboxLayer.h\"\n#include \"layer/modelLayer.h\"\n#include \"layer/constraintLayer.h\"\n#include \"layer/testLayer.h\"\n#include \"layer/pickerLayer.h\"\n#include \"layer/postprocessLayer.h\"\n#include \"layer/guiLayer.h\"\n#include \"layer/debugLayer.h\"\n#include \"layer/debugOverlay.h\"\n#include \"layer/imguiLayer.h\"\n#include \"layer/shadowLayer.h\"\n#include \"layer/cameraLayer.h\"\n#include \"ecs/components.h\"\n#include \"../util/systemVariables.h\"\n#include \"frames.h\"\n#include \"imgui/imgui.h\"\n\nstruct GLFWwindow;\n\nnamespace P3D::Application {\n\nbool initGLFW() {\n\t// Set window hints\n\t//Renderer::setGLFWMultisampleSamples(4);\n\n\t// Initialize GLFW\n\tif (!Graphics::GLFW::init()) {\n\t\tLog::error(\"GLFW failed to initialize\");\n\t\treturn false;\n\t}\n\n\t//Renderer::enableMultisampling();\n\n\tLog::info(\"Initialized GLFW\");\n\n\treturn true;\n}\n\nbool initGLEW() {\n\t// Init GLEW after creating a valid rendering context\n\tif (!Graphics::Renderer::initGLEW()) {\n\t\tterminateGLFW();\n\n\t\tLog::error(\"GLEW Failed to initialize!\");\n\n\t\treturn false;\n\t}\n\n\tLog::info(\"Initialized GLEW\");\n\treturn true;\n}\n\nvoid terminateGLFW() {\n\tLog::info(\"Closing GLFW\");\n\tGLFW::terminate();\n\tLog::info(\"Closed GLFW\");\n}\n\nScreen::Screen() {\n\t\n};\n\nScreen::Screen(int width, int height, PlayerWorld* world, UpgradeableMutex* worldMutex) : world(world), worldMutex(worldMutex) {\n\tusing namespace Graphics;\n\n\t// Init registry component order\n\tregistry.init<Comp::Name, Comp::Transform, Comp::Collider>();\n\t\n\t// Create a windowed mode window and its OpenGL context \n\tGLFWwindow* context = GLFW::createContext(width, height, \"Physics3D\");\n\n\tif (!GLFW::validContext(context)) {\n\t\tLog::fatal(\"Invalid rendering context\");\n\t\tterminateGLFW();\n\t\texit(-1);\n\t}\n\n\t// Make the window's context current \n\tGLFW::setCurrentContext(context);\n\t\n\t// already set using application resources on windows\n#ifndef _WIN32\n\tGraphics::GLFW::setWindowIconFromPath(\"../res/textures/logo128.png\");\n#endif\n\n\tLog::info(\"OpenGL vendor: (%s)\", Renderer::getVendor());\n\tLog::info(\"OpenGL renderer: (%s)\", Renderer::getRenderer());\n\tLog::info(\"OpenGL version: (%s)\", Renderer::getVersion());\n\tLog::info(\"OpenGL shader version: (%s)\", Renderer::getShaderVersion());\n\n\tSystemVariables::set(\"OPENGL_SHADER_VERSION\", Renderer::parseShaderVersion(Renderer::getShaderVersion()));\n\tSystemVariables::set(\"MAX_TEXTURE_IMAGE_UNITS\", Renderer::getMaxTextureUnits());\n\n\tLog::info(\"OpenGL maximum texture units: %d\", Renderer::getMaxTextureUnits());\n}\n\n\n// Handler\nStandardInputHandler* handler = nullptr;\n\n// Layers\nImGuiLayer imguiLayer;\nCameraLayer cameraLayer;\nSkyboxLayer skyboxLayer;\nModelLayer modelLayer;\nConstraintLayer constraintLayer;\nShadowLayer shadowLayer;\nPickerLayer pickerLayer;\nPostprocessLayer postprocessLayer;\nGuiLayer guiLayer;\nDebugLayer debugLayer;\nTestLayer testLayer;\nDebugOverlay debugOverlay;\n\nbool USE_IMGUI = true;\n\nvoid Screen::onInit(bool quickBoot) {\n\t// Log init\n\tLog::setLogLevel(Log::Level::INFO);\n\n\t// Properties init\n\tproperties = Util::PropertiesParser::read(\"../res/.properties\");\n\n\t// load options from properties\n\tEngine::KeyboardOptions::load(properties);\n\n\t// InputHandler init\n\thandler = new StandardInputHandler(GLFW::getCurrentContext(), *this);\n\n\t// Screen size init\n\tdimension = GLFW::getWindowSize();\n\n\t// Framebuffer init\n\tquad = new Quad();\n\tscreenFrameBuffer = std::make_shared<FrameBuffer>(dimension.x, dimension.y);\n\n\t// GShader init\n\tShaders::onInit();\n\n\t// Layer creation\n\tif(USE_IMGUI) imguiLayer = ImGuiLayer(this);\n\tcameraLayer = CameraLayer(this);\n\tif(!quickBoot) skyboxLayer = SkyboxLayer(this);\n\tmodelLayer = ModelLayer(this);\n\tconstraintLayer = ConstraintLayer(this, Engine::Layer::NoUpdate | Engine::Layer::NoEvents);\n\tshadowLayer = ShadowLayer(this);\n\tif(USE_IMGUI) debugLayer = DebugLayer(this);\n\tpickerLayer = PickerLayer(this);\n\tpostprocessLayer = PostprocessLayer(this);\n\tif(USE_IMGUI) guiLayer = GuiLayer(this);\n\t//testLayer = TestLayer(this);\n\tif(USE_IMGUI) debugOverlay = DebugOverlay(this);\n\n\tif(!quickBoot) layerStack.pushLayer(&skyboxLayer);\n\tlayerStack.pushLayer(&constraintLayer);\n\tlayerStack.pushLayer(&modelLayer);\n\tlayerStack.pushLayer(&shadowLayer);\n\tif(USE_IMGUI) layerStack.pushLayer(&debugLayer);\n\tlayerStack.pushLayer(&pickerLayer);\n\tlayerStack.pushLayer(&postprocessLayer);\n\tif(USE_IMGUI) layerStack.pushLayer(&guiLayer);\n\tif(USE_IMGUI) layerStack.pushLayer(&debugOverlay);\n\t//layerStack.pushLayer(&testLayer);\n\tlayerStack.pushLayer(&cameraLayer);\n\tif(USE_IMGUI) layerStack.pushLayer(&imguiLayer);\n\n\t// Layer init\n\tlayerStack.onInit(registry);\n\n\t// Resize\n\tEngine::FrameBufferResizeEvent event(dimension.x, dimension.y);\n\thandler->onFrameBufferResize(event);\n\n\t// Init frames\n\tif(USE_IMGUI) Frames::onInit(registry);\n}\n\nvoid Screen::onUpdate() {\n\t// Update layers\n\tlayerStack.onUpdate(registry);\n}\n\nvoid Screen::onEvent(Engine::Event& event) {\n\tusing namespace Engine;\n\n\t/*// Consume ImGui events\n\tif (event.inCategory(EventCategoryKeyboard | EventCategoryMouseButton) || ImGui::IsAnyItemHovered() || ImGui::IsAnyItemActive()) {\n\t\tImGuiIO& io = ImGui::GetIO();\n\t\tif (io.WantCaptureKeyboard || io.WantTextInput | io.WantCaptureMouse) {\n\t\t\tevent.handled = true;\n\t\t\treturn;\n\t\t}\n\t}*/\n\n\tlayerStack.onEvent(registry, event);\n}\n\nvoid Screen::onRender() {\n\tusing namespace Graphics;\n\tusing namespace Renderer;\n\n\t// Reset screen framebuffer\n\tdefaultSettings(screenFrameBuffer->getID());\n\n\tif (USE_IMGUI)\n\t\timguiLayer.begin();\n\n\t// Render layers\n\tlayerStack.onRender(registry);\n\n\tif (USE_IMGUI)\n\t\timguiLayer.end();\n\n\tif (!USE_IMGUI) {\n\t\t// Blit screen framebuffer to main framebuffer\n\t\tglBindFramebuffer(GL_READ_FRAMEBUFFER, screenFrameBuffer->getID());\n\t\tglBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);\n\t\tglBlitFramebuffer(0, 0, screenFrameBuffer->dimension.x, screenFrameBuffer->dimension.y, 0, 0, dimension.x, dimension.y, GL_COLOR_BUFFER_BIT, GL_LINEAR);\n\t}\n\n\tgraphicsMeasure.mark(GraphicsProcess::FINALIZE);\n\n\t// Finalize\n\tGLFW::swapInterval(1);\n\tGLFW::swapBuffers();\n\tGLFW::pollEvents();\n\n\tgraphicsMeasure.mark(GraphicsProcess::OTHER);\n}\n\nvoid Screen::onClose() {\n\tscreenFrameBuffer->close();\n\n\tlayerStack.onClose(registry);\n\n\tResourceManager::close();\n\n\tShaders::onClose();\n\n\tEngine::KeyboardOptions::save(properties);\n\n\tUtil::PropertiesParser::write(\"../res/.properties\", properties);\n\n\tterminateGLFW();\n}\n\nbool Screen::shouldClose() {\n\treturn GLFW::isWindowClosed();\n}\n\n};"
  },
  {
    "path": "application/view/screen.h",
    "content": "#pragma once\n\n#include \"../eventHandler.h\"\n#include \"../util/properties.h\"\n#include \"../graphics/extendedTriangleMesh.h\"\n#include \"../engine/event/event.h\"\n#include \"../engine/layer/layerStack.h\"\n#include \"../engine/ecs/registry.h\"\n#include \"camera.h\"\n\nnamespace P3D {\nclass UpgradeableMutex;\n};\n\nnamespace P3D::Graphics {\nstruct Quad;\nclass FrameBuffer;\nclass HDRFrameBuffer;\nclass IndexedMesh;\n};\n\nnamespace P3D::Application {\n\nclass StandardInputHandler;\nclass PlayerWorld;\n\nbool initGLEW();\nbool initGLFW();\nvoid terminateGLFW();\n\nclass Screen {\npublic:\n\tEngine::Registry64 registry;\n\n\tPlayerWorld* world;\n\tUpgradeableMutex* worldMutex;\n\tVec2i dimension;\n\n\tCamera camera;\n\tEngine::LayerStack layerStack;\n\tEventHandler eventHandler;\n\tUtil::Properties properties;\t\n\t\n\tSRef<Graphics::FrameBuffer> screenFrameBuffer = nullptr;\n\tGraphics::Quad* quad = nullptr;\n\n\tExtendedPart* selectedPart = nullptr;\n\n\tScreen();\n\tScreen(int width, int height, PlayerWorld* world, UpgradeableMutex* worldMutex);\n\n\tvoid onInit(bool quickBoot);\n\tvoid onUpdate();\n\tvoid onEvent(Engine::Event& event);\n\tvoid onRender();\n\tvoid onClose();\n\n\tbool shouldClose();\n};\n\nextern StandardInputHandler* handler;\n\n};"
  },
  {
    "path": "application/view/toolbarFrame.cpp",
    "content": "#include \"core.h\"\n#include \"toolbarFrame.h\"\n\n#include \"../layer/pickerLayer.h\"\n#include \"../engine/tool/toolManager.h\"\n#include \"../graphics/gui/imgui/imguiExtension.h\"\n#include \"../input/standardInputHandler.h\"\n#include \"../engine/options/keyboardOptions.h\"\n#include \"application.h\"\n#include \"screen.h\"\n#include \"picker/tools/toolSpacing.h\"\n\nnamespace P3D::Application {\n\nvoid ToolbarFrame::onInit(Engine::Registry64& registry) {\n\tstd::string path = \"../res/textures/icons/\";\n\tResourceManager::add<Graphics::TextureResource>(\"play\", path + \"Play.png\");\n\tResourceManager::add<Graphics::TextureResource>(\"pause\", path + \"Pause.png\");\n\tResourceManager::add<Graphics::TextureResource>(\"tick\", path + \"Tick.png\");\n\tResourceManager::add<Graphics::TextureResource>(\"reset\", path + \"Reset.png\");\n}\n\nvoid ToolbarFrame::onRender(Engine::Registry64& registry) {\n\tImGui::BeginToolbar(\"Toolbar\");\n\t\n\tfor (Engine::ToolManager& toolManager : PickerLayer::toolManagers) {\n\t\tfor (Engine::Tool* tool : toolManager) {\n\t\t\tbool selected = toolManager.isSelected(tool);\n\t\t\tif (dynamic_cast<ToolSpacing*>(tool) != nullptr) {\n\t\t\t\tImGui::SameLine();\n\t\t\t\tImGui::BulletText(\"\");\n\t\t\t} else if (ImGui::ToolBarButton(tool, selected)) {\n\t\t\t\tif (selected)\n\t\t\t\t\ttoolManager.deselectTool();\n\t\t\t\telse\n\t\t\t\t\ttoolManager.selectTool(tool);\n\t\t\t}\n\t\t}\n\t}\n\n\tImGui::ToolBarSpacing();\n\t\n\n\tif (ImGui::ToolBarButton(\"Play / Pause\", \"Play / Pause the simulation\", isPaused() ? \"play\" : \"pause\")) {\n\t\tEngine::KeyPressEvent event(Engine::KeyboardOptions::Tick::pause);\n\t\thandler->onEvent(event);\n\t}\n\n\tif (ImGui::ToolBarButton(\"Tick\", \"Run one tick of the simulation\", \"tick\")) {\n\t\tEngine::KeyPressEvent event(Engine::KeyboardOptions::Tick::run);\n\t\thandler->onEvent(event);\n\t}\n\n\n\tImGui::EndToolBar();\n}\n\t\n}\n\n\n"
  },
  {
    "path": "application/view/toolbarFrame.h",
    "content": "#pragma once\n\n#include \"../engine/ecs/registry.h\"\n\nnamespace P3D::Application {\n\nstruct ToolbarFrame {\n\n\tstatic void onInit(Engine::Registry64& registry);\n\tstatic void onRender(Engine::Registry64& registry);\n\n};\n\n}\n"
  },
  {
    "path": "application/view.natvis",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?> \n<AutoVisualizer xmlns=\"http://schemas.microsoft.com/vstudio/debugger/natvis/2010\">\n  <Type Name=\"Camera\">\n    <DisplayString>position={cframe.position}, rotation={cframe.rotation}, aspect={aspect, g}</DisplayString>\n    <Expand>\n      <Item Name=\"position\">cframe.position</Item>\n      <Item Name=\"rotation\">cframe.rotation</Item>\n      <Item Name=\"aspect\">aspect</Item>\n      <Item Name=\"field of view\">fov</Item>\n      <Item Name=\"znear\">znear</Item>\n      <Item Name=\"zfar\">zfar</Item>\n      <Item Name=\"movement speed\">speed</Item>\n      <Item Name=\"rotation speed\">rspeed</Item>\n      <Item Name=\"flying\">flying</Item>\n      <Item Name=\"attachement\">attachment</Item>\n    </Expand>\n  </Type>\n\n  <Type Name=\"Texture\">\n    <DisplayString>id={id}, dimension=({width}, {height}), unit={unit}, channels={channels}</DisplayString>\n    <Expand>\n      <Item Name=\"id\">id</Item> \n      <Item Name=\"unit\">unit</Item>\n      <Item Name=\"width\">width</Item>\n      <Item Name=\"height\">height</Item>\n      <Item Name=\"format\">format</Item>\n      <Item Name=\"channels\">channels</Item>\n    </Expand>\n  </Type>\n\n  <Type Name=\"Attenuation\">\n    <DisplayString>{constant, g}, {linear, g}, {exponent,g}</DisplayString>\n  </Type>\n\n  <Type Name=\"Light\">\n    <DisplayString>position={position}, color={color}, intensity={intensity,g}, attenuation={attenuation}</DisplayString>\n  </Type>\n\n  <Type Name=\"Material\">\n    <DisplayString>amb={ambient}, dif={diffuse}, spec={specular}, refl={reflectance,g}}}</DisplayString>\n  </Type>\n</AutoVisualizer>"
  },
  {
    "path": "application/worldBuilder.cpp",
    "content": "#include \"core.h\"\n\n#include \"worldBuilder.h\"\n\n#include \"application.h\"\n#include <Physics3D/math/mathUtil.h>\n#include <Physics3D/geometry/shape.h>\n#include <Physics3D/geometry/shapeCreation.h>\n\n#include \"../graphics/gui/gui.h\"\n\n#include \"../util/resource/resourceLoader.h\"\n#include \"../util/resource/resourceManager.h\"\n#include \"../graphics/resource/textureResource.h\"\n#include <Physics3D/math/constants.h>\n#include \"view/screen.h\"\n#include \"ecs/components.h\"\n\n#include <Physics3D/constraints/ballConstraint.h>\n#include <Physics3D/constraints/hingeConstraint.h>\n\nnamespace P3D::Application {\n\nnamespace WorldBuilder {\n\nShape wedge;\nShape treeTrunk;\nShape icosahedron;\nShape triangle;\nShape arrow;\nPartProperties basicProperties{1.0, 0.7, 0.3};\n\n\nvoid init() {\n\twedge = polyhedronShape(ShapeLibrary::wedge);\n\ttreeTrunk = polyhedronShape(ShapeLibrary::createPrism(7, 0.5, 11.0).rotated(Rotation::Predefined::X_270));\n\ticosahedron = polyhedronShape(ShapeLibrary::icosahedron);\n\ttriangle = polyhedronShape(ShapeLibrary::trianglePyramid);\n\n\tVec2f inbetweenPoints[3]{Vec2f(0.0f, 0.03f), Vec2f(0.7f, 0.03f), Vec2f(0.7f, 0.06f)};\n\tarrow = polyhedronShape(ShapeLibrary::createRevolvedShape(0.0f, inbetweenPoints, 3, 1.0f, 50));\n}\n\nvoid createDominoAt(const GlobalCFrame& cframe) {\n\tExtendedPart* domino = new ExtendedPart(boxShape(0.2, 1.4, 0.6), cframe, { 1, 0.7, 0.3 });\n\tworld.addPart(domino);\n}\n\nvoid makeDominoStrip(int dominoCount, Position dominoStart, Vec3 dominoOffset) {\n\tfor (int i = 0; i < dominoCount; i++) {\n\t\tcreateDominoAt(GlobalCFrame(dominoStart + dominoOffset * i));\n\t}\n}\n\nvoid makeDominoTower(int floors, int circumference, Position origin) {\n\tdouble radius = circumference / 4.4;\n\tRotation sideways = Rotation::fromEulerAngles(PI / 2, 0.0, 0.0);\n\tfor (int floor = 0; floor < floors; floor++) {\n\t\tfor (int j = 0; j < circumference; j++) {\n\t\t\tdouble angle = (2 * PI * (j + (floor % 2) / 2.0)) / circumference;\n\t\t\tVec3 pos = Vec3(std::cos(angle) * radius, floor * 0.7 + 0.30, std::sin(angle) * radius);\n\t\t\tcreateDominoAt(GlobalCFrame(origin + pos, Rotation::rotY(-angle) * sideways));\n\t\t}\n\t}\n}\n\n\nvoid buildFloor(double width, double depth, int folder) {\n\tExtendedPart* floorExtendedPart = new ExtendedPart(boxShape(width, 1.0, depth), GlobalCFrame(0.0, 0.0, 0.0), { 2.0, 1.0, 0.3 }, \"Floor\", folder);\n\tscreen.registry.getOrAdd<Graphics::Comp::Material>(floorExtendedPart->entity);// ->set(Comp::Material::ALBEDO, ResourceManager::get<Graphics::TextureResource>(\"floorMaterial\"));\n\tworld.addTerrainPart(floorExtendedPart);\n}\nvoid buildFloorAndWalls(double width, double depth, double wallHeight, int folder) {\n\tauto floorWallFolder = screen.registry.create(folder);\n\tscreen.registry.add<Comp::Name>(floorWallFolder, \"Floor and walls\");\n\t\n\tbuildFloor(width, depth, floorWallFolder);\n\n\tPartProperties wallProperties { 2.0, 1.0, 0.3 };\n\tworld.addTerrainPart(new ExtendedPart(boxShape(0.7, wallHeight, depth), GlobalCFrame(width / 2, wallHeight / 2, 0.0), wallProperties, \"Wall\", floorWallFolder));\n\tworld.addTerrainPart(new ExtendedPart(boxShape(width, wallHeight, 0.7), GlobalCFrame(0.0, wallHeight / 2, depth / 2), wallProperties, \"Wall\", floorWallFolder));\n\tworld.addTerrainPart(new ExtendedPart(boxShape(0.7, wallHeight, depth), GlobalCFrame(-width / 2, wallHeight / 2, 0.0), wallProperties, \"Wall\", floorWallFolder));\n\tworld.addTerrainPart(new ExtendedPart(boxShape(width, wallHeight, 0.7), GlobalCFrame(0.0, wallHeight / 2, -depth / 2), wallProperties, \"Wall\", floorWallFolder));\n}\n\nSpiderFactory::SpiderFactory(double spiderSize, int legCount) : spiderSize(spiderSize), legCount(legCount), bodyShape(polyhedronShape(ShapeLibrary::createPointyPrism(legCount, 0.5f, 0.2f, 0.1f, 0.1f))) {}\n\nvoid SpiderFactory::buildSpider(const GlobalCFrame& spiderPosition, int folder) {\n\t//ExtendedPart* spiderBody = createUniquePart(screen, createPointyPrism(legCount, 0.5, 0.2, 0.1, 0.1), spiderPosition, 1.0, 0.0, \"SpiderBody\");\n\n\tauto spiderID = screen.registry.create();\n\tscreen.registry.add<Comp::Name>(spiderID, \"Spider\");\n\n\tif (folder != 0)\n\t\tscreen.registry.setParent(spiderID, folder);\n\t\n\tExtendedPart* spiderBody = new ExtendedPart(bodyShape, spiderPosition, { 1.0, 0.5, 0.3 }, \"Body\", spiderID);\n\tscreen.registry.getOrAdd<Graphics::Comp::Material>(spiderBody->entity)->albedo = Graphics::Color(0.6f, 0.6f, 0.6f, 1.0f);\n\n\t//PartFactory legFactory(BoundingBox(0.05, 0.5, 0.05).toShape(), screen, \"SpiderLeg\");\n\n\tCFrame topOfLeg(Vec3(0.0, 0.25, 0.0), Rotation::fromEulerAngles(0.2, 0.0, 0.0));\n\n\tworld.addPart(spiderBody);\n\n\tfor (int i = 0; i < legCount; i++) {\n\t\tExtendedPart* leg = new ExtendedPart(boxShape(0.05, 0.5, 0.05), GlobalCFrame(), { 1.0, 0.5, 0.3 }, \"LegPart \" + std::to_string(i), spiderID);\n\t\tscreen.registry.getOrAdd<Graphics::Comp::Material>(leg->entity)->albedo = Graphics::Color(0.4f, 0.4f, 0.4f, 1.0f);\n\n\t\tdouble angle = i * PI * 2 / legCount;\n\n\t\tCFrame attachPointOnBody(Rotation::rotY(angle) * Vec3(0.5, 0.0, 0.0), Rotation::rotY(angle + PI / 2));\n\t\tCFrame attach = attachPointOnBody.localToGlobal(~topOfLeg);\n\n\t\tspiderBody->attach(leg, attach);\n\t}\n}\n\n\nHollowBoxParts buildHollowBox(Bounds box, double wallThickness) {\n\tdouble width = static_cast<double>(box.getWidth());\n\tdouble height = static_cast<double>(box.getHeight());\n\tdouble depth = static_cast<double>(box.getDepth());\n\n\tShape XPlate = boxShape(wallThickness, height - wallThickness * 2, depth);\n\tShape YPlate = boxShape(width, wallThickness, depth);\n\tShape ZPlate = boxShape(width - wallThickness * 2, height - wallThickness * 2, wallThickness);\n\n\tauto hollowBoxFolder = screen.registry.create();\n\tscreen.registry.add<Comp::Name>(hollowBoxFolder, \"Hollow Box\");\n\t\n\tExtendedPart* bottom = new ExtendedPart(YPlate, GlobalCFrame(box.getCenter() - Vec3(0, height / 2 - wallThickness / 2, 0)), { 1.0, 0.2, 0.3 }, \"BottomPlate\", hollowBoxFolder);\n\tExtendedPart* top = new ExtendedPart(YPlate, bottom, CFrame(0, height - wallThickness, 0), { 1.0, 0.2, 0.3 }, \"TopPlate\");\n\tExtendedPart* left = new ExtendedPart(XPlate, bottom, CFrame(width / 2 - wallThickness / 2, height / 2 - wallThickness / 2, 0), { 1.0, 0.2, 0.3 }, \"LeftPlate\", hollowBoxFolder);\n\tExtendedPart* right = new ExtendedPart(XPlate, bottom, CFrame(-width / 2 + wallThickness / 2, height / 2 - wallThickness / 2, 0), { 1.0, 0.2, 0.3 }, \"RightPlate\", hollowBoxFolder);\n\tExtendedPart* front = new ExtendedPart(ZPlate, bottom, CFrame(0, height / 2 - wallThickness / 2, depth / 2 - wallThickness / 2), { 1.0, 0.2, 0.3 }, \"FrontPlate\", hollowBoxFolder);\n\tExtendedPart* back = new ExtendedPart(ZPlate, bottom, CFrame(0, height / 2 - wallThickness / 2, -depth / 2 + wallThickness / 2), { 1.0, 0.2, 0.3 }, \"BackPlate\", hollowBoxFolder);\n\n\treturn HollowBoxParts { bottom, top, left, right, front, back };\n}\n\ndouble getYOffset(double x, double z) {\n\tdouble regimeYOffset = -10 * cos(x / 30.0 + z / 20.0) - 7 * sin(-x / 25.0 + z / 17.0 + 2.4) + 2 * sin(x / 4.0 + z / 7.0) + sin(x / 9.0 - z / 3.0) + sin(-x / 3.0 + z / 5.0);\n\tdouble distFromOriginSq = x * x + z * z;\n\tif (distFromOriginSq < 5000.0) {\n\t\tdouble factor = distFromOriginSq / 5000.0;\n\t\treturn regimeYOffset * factor + (1 - factor) * -5;\n\t} else {\n\t\treturn regimeYOffset;\n\t}\n}\n\nvoid buildTree(Position treePos, int treeFolder) {\n\tGlobalCFrame trunkCFrame(treePos, Rotation::fromEulerAngles(fRand(-0.1, 0.1), fRand(-3.1415, 3.1415), fRand(-0.1, 0.1)));\n\n\tExtendedPart* trunk = new ExtendedPart(treeTrunk, trunkCFrame, { 1.0, 1.0, 0.3 }, \"Trunk\", treeFolder);\n\tscreen.registry.getOrAdd<Graphics::Comp::Material>(trunk->entity)->albedo = Graphics::Color::get<0x654321>();\n\tworld.addTerrainPart(trunk);\n\n\tPosition treeTop = trunkCFrame.localToGlobal(Vec3(0.0, 5.5, 0.0));\n\n\tauto leavesFolder = screen.registry.create(treeFolder);\n\tscreen.registry.add<Comp::Name>(leavesFolder, \"Leaves\");\n\n\tfor (int j = 0; j < 15; j++) {\n\t\tGlobalCFrame leavesCFrame(treeTop + Vec3(fRand(-1.0, 1.0), fRand(-1.0, 1.0), fRand(-1.0, 1.0)), Rotation::fromEulerAngles(fRand(0.0, 3.1415), fRand(0.0, 3.1415), fRand(0.0, 3.1415)));\n\t\tExtendedPart* leaves = new ExtendedPart(icosahedron.scaled(2.1, 1.9, 1.7), leavesCFrame, { 1.0, 1.0, 0.3 }, \"Leaf\", leavesFolder);\n\n\t\tscreen.registry.getOrAdd<Graphics::Comp::Material>(leaves->entity)->albedo = Graphics::Color(fRand(-0.2, 0.2), 0.6 + fRand(-0.2, 0.2), 0.0, 1.0);\n\n\t\tworld.addTerrainPart(leaves);\n\t}\n}\n\nvoid buildConveyor(double width, double length, const GlobalCFrame& cframe, double speed, int folder) {\n\tauto conveyorFolder = screen.registry.create(folder);\n\tscreen.registry.add<Comp::Name>(conveyorFolder, \"Conveyor\");\n\t\n\tExtendedPart* conveyor = new ExtendedPart(boxShape(width, 0.3, length), cframe, { 1.0, 0.8, 0.0, Vec3(0.0, 0.0, speed) }, \"Conveyor\", conveyorFolder);\n\tscreen.registry.getOrAdd<Graphics::Comp::Material>(conveyor->entity)->albedo = Graphics::Color(0.2f, 0.2f, 0.2f, 1.0f);\n\tworld.addTerrainPart(conveyor);\n\tExtendedPart* leftWall = new ExtendedPart(boxShape(0.2, 0.6, length), cframe.localToGlobal(CFrame(-width / 2 - 0.1, 0.1, 0.0)), { 1.0, 0.4, 0.3, Vec3(0.0, 0.0, 0.0) }, \"Left Wall\", conveyorFolder);\n\tworld.addTerrainPart(leftWall);\n\tExtendedPart* rightWall = new ExtendedPart(boxShape(0.2, 0.6, length), cframe.localToGlobal(CFrame(width / 2 + 0.1, 0.1, 0.0)), { 1.0, 0.4, 0.3, Vec3(0.0, 0.0, 0.0) }, \"Right Wall\", conveyorFolder);\n\tworld.addTerrainPart(rightWall);\n}\n\nvoid buildTrebuchet(const GlobalCFrame& cframe, double baseWidth, double baseLength, double wheelRadius, double wheelThickness, double armLength, double armThickness, int folder) {\n\tPartProperties wheelproperties;\n\twheelproperties.friction = 2.0;\n\twheelproperties.bouncyness = 0.2;\n\twheelproperties.density = 1.0;\n\tExtendedPart* base = new ExtendedPart(boxShape(baseWidth, 0.2, baseLength), cframe, {1.0, 0.8, 0.0}, \"Base\", folder);\n\tExtendedPart* FLWheel = new ExtendedPart(cylinderShape(wheelRadius, wheelThickness), cframe, wheelproperties, \"FLWheel\", folder); FLWheel->setColor(Graphics::Colors::BLACK);\n\tExtendedPart* FRWheel = new ExtendedPart(cylinderShape(wheelRadius, wheelThickness), cframe, wheelproperties, \"FRWheel\", folder); FRWheel->setColor(Graphics::Colors::BLACK);\n\tExtendedPart* BLWheel = new ExtendedPart(cylinderShape(wheelRadius, wheelThickness), cframe, wheelproperties, \"BLWheel\", folder); BLWheel->setColor(Graphics::Colors::BLACK);\n\tExtendedPart* BRWheel = new ExtendedPart(cylinderShape(wheelRadius, wheelThickness), cframe, wheelproperties, \"BRWheel\", folder); BRWheel->setColor(Graphics::Colors::BLACK);\n\tExtendedPart* arm = new ExtendedPart(boxShape(armThickness, armThickness, armLength), cframe, {1.0, 0.8, 0.0}, \"Arm\", folder);\n\tExtendedPart* weight = new ExtendedPart(boxShape(armThickness * 4, armThickness * 4, armThickness * 4), cframe, {1.0, 0.8, 0.0}, \"Weight\", folder); weight->setColor(Graphics::Colors::GRAY);\n\tarm->attach(weight, CFrame(0.0, 0.0, armLength / 2));\n\t\n\t\n\tConstraintGroup cg;\n\n\tcg.add(base, FLWheel, new HingeConstraint(Vec3(baseWidth / 2, 0.0, baseLength / 2), Vec3(1.0, 0.0, 0.0), Vec3(0.0, 0.0, -wheelThickness / 2 * 1.1), Vec3(0.0, 0.0, 1.0)));\n\tcg.add(base, FRWheel, new HingeConstraint(Vec3(-baseWidth / 2, 0.0, baseLength / 2), Vec3(-1.0, 0.0, 0.0), Vec3(0.0, 0.0, -wheelThickness / 2 * 1.1), Vec3(0.0, 0.0, 1.0)));\n\tcg.add(base, BLWheel, new HingeConstraint(Vec3(baseWidth / 2, 0.0, -baseLength / 2), Vec3(1.0, 0.0, 0.0), Vec3(0.0, 0.0, -wheelThickness / 2 * 1.1), Vec3(0.0, 0.0, 1.0)));\n\tcg.add(base, BRWheel, new HingeConstraint(Vec3(-baseWidth / 2, 0.0, -baseLength / 2), Vec3(-1.0, 0.0, 0.0), Vec3(0.0, 0.0, -wheelThickness / 2 * 1.1), Vec3(0.0, 0.0, 1.0)));\n\tcg.add(base, arm, new HingeConstraint(Vec3(0.0, armLength * 1.5, 0.0), Vec3(1.0, 0.0, 0.0), Vec3(0.0, 0.0, armLength * 0.2), Vec3(1.0, 0.0, 0.0)));\n\n\tworld.constraints.push_back(cg);\n\n\tworld.addPart(FLWheel);\n\tworld.addPart(FRWheel);\n\tworld.addPart(BLWheel);\n\tworld.addPart(BRWheel);\n\tworld.addPart(base);\n\tworld.addPart(arm);\n}\n\nstd::array<ExtendedPart*, 3> produceAxes(const GlobalCFrame& cf, const PartProperties& properties, double scale) {\n\tExtendedPart* zAxis = new ExtendedPart(arrow.scaled(scale, scale, scale), cf.extendLocal(Vec3(0.0, 0.0, 0.5 * scale)), properties, \"zAxis\");\n\tExtendedPart* xAxis = new ExtendedPart(arrow.scaled(scale, scale, scale), zAxis, CFrame(0.5 * scale, 0.0, -0.5 * scale, Rotation::Predefined::Y_90), properties, \"xAxis\");\n\tExtendedPart* yAxis = new ExtendedPart(arrow.scaled(scale, scale, scale), zAxis, CFrame(0.0, 0.5 * scale, -0.5 * scale, Rotation::Predefined::X_270), properties, \"yAxis\");\n\txAxis->setColor(Graphics::Color(1.0f, 0.0f, 0.0f, 1.0f));\n\tyAxis->setColor(Graphics::Color(0.0f, 1.0f, 0.0f, 1.0f));\n\tzAxis->setColor(Graphics::Color(0.0f, 0.0f, 1.0f, 1.0f));\n\treturn std::array<ExtendedPart*, 3>{xAxis, yAxis, zAxis};\n}\n\nvoid attachAxes(ExtendedPart* part, double scale) {\n\tExtendedPart* xAxis = new ExtendedPart(arrow.scaled(scale, scale, scale), part, CFrame(0.5 * scale, 0.0, 0.0, Rotation::Predefined::Y_90), part->properties, \"xAxis\");\n\tExtendedPart* yAxis = new ExtendedPart(arrow.scaled(scale, scale, scale), part, CFrame(0.0, 0.5 * scale, 0.0, Rotation::Predefined::X_270), part->properties, \"yAxis\");\n\tExtendedPart* zAxis = new ExtendedPart(arrow.scaled(scale, scale, scale), part, CFrame(0.0, 0.0, 0.5 * scale), part->properties, \"zAxis\");\n\n\txAxis->setColor(Graphics::Color(1.0f, 0.0f, 0.0f, 1.0f));\n\tyAxis->setColor(Graphics::Color(0.0f, 1.0f, 0.0f, 1.0f));\n\tzAxis->setColor(Graphics::Color(0.0f, 0.0f, 1.0f, 1.0f));\n}\n\nvoid buildTerrain(double width, double depth, int folder) {\n\tLog::subject s(\"Terrain\");\n\tLog::info(\"Starting terrain building!\");\n\n\tint maxProgress = 10;\n\tint lastProgress = 0;\n\n\tauto groundFolder = screen.registry.create(folder);\n\tscreen.registry.add<Comp::Name>(groundFolder, \"Ground\");\n\t\n\tLog::info(\"0%%\");\n\tfor (double x = -width / 2; x < width / 2; x += 3.0) {\n\t\tfor (double z = -depth / 2; z < depth / 2; z += 3.0) {\n\t\t\tdouble yOffset = getYOffset(x, z);\n\t\t\tPosition pos((x / 3.0 + fRand(0.0, 1.0)) * 3.0, fRand(0.0, 1.0) + yOffset, (z / 3.0 + fRand(0.0, 1.0)) * 3.0);\n\t\t\tGlobalCFrame cf(pos, Rotation::fromEulerAngles(fRand(0.0, 3.1415), fRand(0.0, 3.1415), fRand(0.0, 3.1415)));\n\t\t\tExtendedPart* newPart = new ExtendedPart(icosahedron.scaled(4.0, 4.0, 4.0), cf, { 1.0, 1.0, 0.3 }, \"Ground\", groundFolder);\n\t\t\tscreen.registry.getOrAdd<Graphics::Comp::Material>(newPart->entity)->albedo = Graphics::Color(0.0, yOffset / 40.0 + 0.5, 0.0, 1.0);\n\t\t\tworld.addTerrainPart(newPart);\n\t\t}\n\n\t\tdouble progress = (x + width / 2) / width;\n\t\tint progressToInt = static_cast<int>(progress * maxProgress);\n\n\t\tif (progressToInt > lastProgress) \n\t\t\tLog::info(\"%d%%\", int(progressToInt * 100.0 / maxProgress));\n\t\t\n\t\tlastProgress = progressToInt;\n\t}\n\tLog::info(\"100%%\");\n\n\tauto treeFolder = screen.registry.create(folder);\n\tscreen.registry.add<Comp::Name>(treeFolder, \"Tree\");\n\t\n\tLog::info(\"Finished terrain, adding trees!\");\n\tfor (int i = 0; i < width * depth / 70; i++) {\n\t\tdouble x = fRand(-width / 2, width / 2);\n\t\tdouble z = fRand(-depth / 2, depth / 2);\n\n\t\tif (std::abs(x) < 30.0 && std::abs(z) < 30.0) continue;\n\n\t\tPosition treePos(x, getYOffset(x, z) + 8.0, z);\n\n\t\tbuildTree(treePos, treeFolder);\n\t}\n\t\n\tLog::info(\"Optimizing terrain! (This will take around 1.5x the time it took to build the world)\");\n\tworld.optimizeLayers();\n}\n\nvoid buildCar(const GlobalCFrame& location, int folder) {\n\tPartProperties carProperties { 1.0, 0.7, 0.3 };\n\tPartProperties wheelProperties { 1.0, 2.0, 0.7 };\n\n\tauto carFolder = screen.registry.create(folder);\n\tscreen.registry.add<Comp::Name>(carFolder, \"Car\");\n\n\tExtendedPart* carBody = new ExtendedPart(boxShape(2.0, 0.1, 1.0), location, carProperties, \"CarBody\", carFolder);\n\tExtendedPart* carLeftPanel = new ExtendedPart(boxShape(2.0, 0.4, 0.1), carBody, CFrame(0.0, 0.25, -0.5), carProperties, \"CarLeftSide\", carFolder);\n\tExtendedPart* carRightPanel = new ExtendedPart(boxShape(2.0, 0.4, 0.1), carBody, CFrame(0.0, 0.25, 0.5), carProperties, \"CarRightSide\", carFolder);\n\tExtendedPart* carLeftWindow = new ExtendedPart(boxShape(1.4, 0.8, 0.05), carLeftPanel, CFrame(-0.3, 0.6, 0.0), carProperties, \"WindowLeft\", carFolder);\n\tExtendedPart* carWedgeLeft = new ExtendedPart(wedge.scaled(0.6, 0.8, 0.1), carLeftWindow, CFrame(1.0, 0.0, 0.0), carProperties, \"WedgeLeft\", carFolder);\n\tExtendedPart* carRightWindow = new ExtendedPart(boxShape(1.4, 0.8, 0.05), carRightPanel, CFrame(-0.3, 0.6, 0.0), carProperties, \"WindowRight\", carFolder);\n\tExtendedPart* carWedgeRight = new ExtendedPart(wedge.scaled(0.6, 0.8, 0.1), carRightWindow, CFrame(1.0, 0.0, 0.0), carProperties, \"WedgeRight\", carFolder);\n\tExtendedPart* carFrontPanel = new ExtendedPart(boxShape(0.1, 0.4, 1.0), carBody, CFrame(1.0, 0.25, 0.0), carProperties, \"FrontPanel\", carFolder);\n\tExtendedPart* carTrunkPanel = new ExtendedPart(boxShape(0.1, 1.2, 1.0), carBody, CFrame(-1.0, 0.65, 0.0), carProperties, \"TrunkPanel\", carFolder);\n\tExtendedPart* carRoof = new ExtendedPart(boxShape(1.4, 0.1, 1.0), carBody, CFrame(-0.3, 1.25, 0.0), carProperties, \"Roof\", carFolder);\n\n\tExtendedPart* carWindshield = new ExtendedPart(boxShape(1.0, 0.05, 1.0), carBody, CFrame(Vec3(0.7, 0.85, 0.0), Rotation::fromEulerAngles(0.0, 0.0, -0.91)), carProperties, \"Windshield\", carFolder);\n\tExtendedPart* wheel1 = new ExtendedPart(sphereShape(0.25), location.localToGlobal(CFrame(0.8, 0.0, 0.8)), wheelProperties, \"Wheel\", carFolder);\n\tExtendedPart* wheel2 = new ExtendedPart(sphereShape(0.25), location.localToGlobal(CFrame(0.8, 0.0, -0.8)), wheelProperties, \"Wheel\", carFolder);\n\tExtendedPart* wheel3 = new ExtendedPart(sphereShape(0.25), location.localToGlobal(CFrame(-0.8, 0.0, 0.8)), wheelProperties, \"Wheel\", carFolder);\n\tExtendedPart* wheel4 = new ExtendedPart(sphereShape(0.25), location.localToGlobal(CFrame(-0.8, 0.0, -0.8)), wheelProperties, \"Wheel\", carFolder);\n\n\tscreen.registry.getOrAdd<Graphics::Comp::Material>(carLeftWindow->entity)->albedo = Graphics::Color(0.7f, 0.7f, 1.0f, 0.5f);\n\tscreen.registry.getOrAdd<Graphics::Comp::Material>(carRightWindow->entity)->albedo = Graphics::Color(0.7f, 0.7f, 1.0f, 0.5f);\n\tscreen.registry.getOrAdd<Graphics::Comp::Material>(carWindshield->entity)->albedo = Graphics::Color(0.7f, 0.7f, 1.0f, 0.5f);\n\n\tworld.addPart(carBody);\n\n\tworld.addPart(wheel1);\n\tworld.addPart(wheel2);\n\tworld.addPart(wheel3);\n\tworld.addPart(wheel4);\n\n\tConstraintGroup car;\n\tcar.add(carBody, wheel1, new BallConstraint(Vec3(0.8, 0.0, 0.8), Vec3(0,0,0)));\n\tcar.add(carBody, wheel2, new BallConstraint(Vec3(0.8, 0.0, -0.8), Vec3(0,0,0)));\n\tcar.add(carBody, wheel3, new BallConstraint(Vec3(-0.8, 0.0, 0.8), Vec3(0,0,0)));\n\tcar.add(carBody, wheel4, new BallConstraint(Vec3(-0.8, 0.0, -0.8), Vec3(0,0,0)));\n\tworld.constraints.push_back(std::move(car));\n}\n}\n\n};"
  },
  {
    "path": "application/worldBuilder.h",
    "content": "#pragma once\n\n#include \"worlds.h\"\n#include \"extendedPart.h\"\n\n#include \"../graphics/debug/guiDebug.h\"\n#include <Physics3D/geometry/shape.h>\n#include <Physics3D/geometry/shapeLibrary.h>\n#include <Physics3D/geometry/convexShapeBuilder.h>\n\n#include <array>\n\nnamespace P3D::Application {\n\nnamespace WorldBuilder {\nextern Shape wedge;\nextern Shape treeTrunk;\nextern Shape icosahedron;\nextern Shape triangle;\nextern Shape arrow;\nextern PartProperties basicProperties;\n\nvoid init();\n\nvoid createDominoAt(const GlobalCFrame& cframe);\nvoid makeDominoStrip(int dominoCount, Position dominoStart, Vec3 dominoOffset);\nvoid makeDominoTower(int floors, int circumference, Position origin);\nvoid buildTerrain(double width, double depth, int folder = 0);\nvoid buildCar(const GlobalCFrame& location, int folder = 0);\nvoid buildFloor(double width, double depth, int folder = 0);\nvoid buildFloorAndWalls(double width, double depth, double wallHeight, int folder = 0);\nvoid buildConveyor(double width, double length, const GlobalCFrame& cframe, double speed, int folder = 0);\nvoid buildTrebuchet(const GlobalCFrame& cframe, double baseWidth, double baseLength, double wheelRadius, double wheelThickness, double armLength, double armThickness, int folder);\n\nstd::array<ExtendedPart*, 3> produceAxes(const GlobalCFrame & cf, const PartProperties& properties, double scale = 1.0);\nvoid attachAxes(ExtendedPart* part, double scale = 1.0);\n\nstruct HollowBoxParts {\n\tExtendedPart* bottom;\n\tExtendedPart* top;\n\tExtendedPart* left;\n\tExtendedPart* right;\n\tExtendedPart* front;\n\tExtendedPart* back;\n};\n\nHollowBoxParts buildHollowBox(Bounds box, double wallThickness);\n\nstruct SpiderFactory {\n\tShape bodyShape;\n\tdouble spiderSize;\n\tint legCount;\n\n\tSpiderFactory(double spiderSize, int legCount);\n\n\tvoid buildSpider(const GlobalCFrame& spiderPosition, int folder = 0);\n};\n}\n\n};"
  },
  {
    "path": "application/worlds.cpp",
    "content": "#include \"core.h\"\n\n#include \"worlds.h\"\n\n#include \"application.h\"\n#include \"view/screen.h\"\n#include \"input/standardInputHandler.h\"\n#include <Physics3D/misc/debug.h>\n#include \"../engine/options/keyboardOptions.h\"\n#include <Physics3D/externalforces/magnetForce.h>\n#include \"input/playerController.h\"\n\n#include \"ecs/components.h\"\n\nnamespace P3D::Application {\n\n\nPlayerWorld::PlayerWorld(double deltaT) : World<ExtendedPart>(deltaT) {\n\tthis->addExternalForce(new PlayerController());\n}\n\nvoid PlayerWorld::onPartAdded(ExtendedPart* part) {\n\tscreen.registry.add<Comp::Collider>(part->entity, part);\n}\n\nvoid PlayerWorld::onPartRemoved(ExtendedPart* part) {\n\tscreen.registry.remove<Comp::Collider>(part->entity);\n\tscreen.registry.get<Comp::Transform>(part->entity)->setRoot(Comp::Transform::ScaledCFrame { part->getCFrame(), part->hitbox.scale });\n}\n\n};"
  },
  {
    "path": "application/worlds.h",
    "content": "#pragma once\n\n#include \"extendedPart.h\"\n#include <Physics3D/math/position.h>\n#include <Physics3D/world.h>\n\nnamespace P3D::Application {\n\nclass PlayerWorld : public World<ExtendedPart> {\npublic:\n\tPlayerWorld(double deltaT);\n\n\tvoid onPartAdded(ExtendedPart* part) override;\n\tvoid onPartRemoved(ExtendedPart* part) override;\n};\n\n};"
  },
  {
    "path": "benchmarks/basicWorld.cpp",
    "content": "#include \"worldBenchmark.h\"\n\n#include <Physics3D/world.h>\n#include <Physics3D/geometry/shapeLibrary.h>\n#include <Physics3D/math/linalg/commonMatrices.h>\n\n#include <Physics3D/geometry/shapeCreation.h>\n\nnamespace P3D {\nclass BasicWorldBenchmark : public WorldBenchmark {\npublic:\n\tBasicWorldBenchmark() : WorldBenchmark(\"basicWorld\", 1000) {}\n\n\tvoid init() {\n\t\tcreateFloor(50, 50, 10);\n\t\t//Polyhedron cube = ShapeLibrary::createCube(0.9);\n\n\t\tfor(int x = -5; x < 5; x++) {\n\t\t\tfor(int y = 0; y < 5; y++) {\n\t\t\t\tfor(int z = -5; z < 5; z++) {\n\t\t\t\t\tworld.addPart(new Part(boxShape(0.9, 0.9, 0.9), GlobalCFrame(x, y + 1.0, z), {1.0, 0.7, 0.5}));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n} basicWorld;\n};\n\n"
  },
  {
    "path": "benchmarks/benchmark.cpp",
    "content": "#include \"benchmark.h\"\n\n#include <chrono>\n#include <vector>\n#include <iostream>\n#include <string>\n#include <sstream>\n\n#include \"../util/terminalColor.h\"\n#include \"../util/parseCPUIDArgs.h\"\n\nstd::vector<Benchmark*>* knownBenchmarks = nullptr;\n\nBenchmark::Benchmark(const char* name) : name(name) {\n\tif(knownBenchmarks == nullptr) { knownBenchmarks = new std::vector<Benchmark*>(); }\n\tknownBenchmarks->push_back(this);\n}\n\nBenchmark* getBenchFor(std::string id) {\n\tif(id.length() == 0) return nullptr;\n\tif(id[0] >= '0' && id[0] <= '9') {\n\t\treturn (*knownBenchmarks)[std::stoi(id)];\n\t} else {\n\t\tfor(Benchmark* b : *knownBenchmarks) {\n\t\t\tif(id == b->name) {\n\t\t\t\treturn b;\n\t\t\t}\n\t\t}\n\t}\n\treturn nullptr;\n}\n\nstd::vector<std::string> split(std::string str, char splitChar) {\n\tstd::vector<std::string> substrings;\n\n\tint lastIndex = 0;\n\tint index = 0;\n\twhile(index < str.length()) {\n\t\twhile(str[index] != splitChar) {\n\t\t\tindex++;\n\t\t}\n\t\tsubstrings.push_back(str.substr(lastIndex, index - lastIndex));\n\t\tindex++;\n\t\tlastIndex = index;\n\t}\n\treturn substrings;\n}\n\nstatic void runBenchmark(Benchmark* bench) {\n\tsetColor(TerminalColor::CYAN);\n\n\tauto createStart = std::chrono::high_resolution_clock::now();\n\tbench->init();\n\tauto createFinish = std::chrono::high_resolution_clock::now();\n\tstd::cout << bench->name << \": \";\n\tstd::cout.flush();\n\tsetColor(TerminalColor::YELLOW);\n\tstd::cout << '(' << (createFinish - createStart).count() / 1000000.0 << \"ms)\";\n\tstd::cout.flush();\n\tauto runStart = std::chrono::high_resolution_clock::now();\n\tbench->run();\n\tauto runFinish = std::chrono::high_resolution_clock::now();\n\tdouble deltaTimeMS = (runFinish - runStart).count() / 1000000.0;\n\tsetColor(TerminalColor::GREEN);\n\tstd::cout << \"  (\" << deltaTimeMS << \"ms)\\n\";\n\tstd::cout.flush();\n\tbench->printResults(deltaTimeMS);\n}\n\nstatic void runBenchmarks(const std::vector<std::string>& benchmarks) {\n\tsetColor(TerminalColor::CYAN);\n\tstd::cout << \"[NAME]\";\n\tsetColor(TerminalColor::YELLOW);\n\tstd::cout << \" [INITIALIZATION]\";\n\tsetColor(TerminalColor::GREEN);\n\tstd::cout << \" [RUNTIME]\\n\";\n\tsetColor(TerminalColor::WHITE);\n\n\tfor(const std::string& c : benchmarks) {\n\t\tBenchmark* b = getBenchFor(c);\n\t\tif(b != nullptr) {\n\t\t\trunBenchmark(b);\n\t\t}\n\t}\n}\n\nint main(int argc, const char** args) {\n\tUtil::ParsedArgs pa(argc, args);\n\tstd::cout << Util::printAndParseCPUIDArgs(pa).c_str() << \"\\n\";\n\n\tif(pa.argCount() >= 1) {\n\t\trunBenchmarks(pa.args());\n\t} else {\n\t\tsetColor(TerminalColor::WHITE);\n\t\tstd::cout << \"The following benchmarks are available:\\n\";\n\t\tsetColor(TerminalColor::CYAN);\n\n\t\tfor(std::size_t i = 0; i < knownBenchmarks->size(); i++) {\n\t\t\tstd::cout << i << \") \" << (*knownBenchmarks)[i]->name << \"\\n\";\n\t\t}\n\n\t\tsetColor(TerminalColor::WHITE);\n\t\tstd::cout << \"Run> \";\n\t\tsetColor(TerminalColor::GREEN);\n\t\tstd::string cmd;\n\t\tstd::cin >> cmd;\n\t\tif(cmd.empty()) {\n\t\t\tsetColor(TerminalColor::WHITE);\n\t\t\treturn 0;\n\t\t}\n\t\tcmd.append(\";\");\n\n\t\tstd::vector<std::string> commands = split(cmd, ';');\n\n\t\trunBenchmarks(commands);\n\t}\n\n\treturn 0;\n}\n"
  },
  {
    "path": "benchmarks/benchmark.h",
    "content": "#pragma once\n\nclass Benchmark {\npublic:\n\tconst char* name;\n\tBenchmark(const char* name);\n\tvirtual ~Benchmark() {}\n\tvirtual void init() {}\n\tvirtual void run() = 0;\n\tvirtual void printResults(double timeTaken) {}\n};\n"
  },
  {
    "path": "benchmarks/benchmarks.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <VCProjectVersion>16.0</VCProjectVersion>\n    <ProjectGuid>{CA5FECF4-EDD2-4387-9967-66B047052B0B}</ProjectGuid>\n    <RootNamespace>benchmarks</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n    <ProjectName>benchmarks</ProjectName>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup />\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n      <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>\n      <AdditionalIncludeDirectories>$(SolutionDir)include;$(SolutionDir)</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>_MBCS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <AdditionalLibraryDirectories>$(OutDir)</AdditionalLibraryDirectories>\n      <AdditionalDependencies>graphics.lib;util.lib;Physics3D.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n      <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <AdditionalIncludeDirectories>$(SolutionDir)include;$(SolutionDir)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <AdditionalDependencies>graphics.lib;util.lib;Physics3D.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalLibraryDirectories>$(OutDir)</AdditionalLibraryDirectories>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"basicWorld.cpp\" />\n    <ClCompile Include=\"benchmark.cpp\" />\n    <ClCompile Include=\"complexObjectBenchmark.cpp\" />\n    <ClCompile Include=\"ecsBenchmark.cpp\" />\n    <ClCompile Include=\"getBoundsPerformance.cpp\" />\n    <ClCompile Include=\"manyCubesBenchmark.cpp\" />\n    <ClCompile Include=\"threadResponseTime.cpp\" />\n    <ClCompile Include=\"worldBenchmark.cpp\" />\n    <ClCompile Include=\"rotationBenchmark.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"benchmark.h\" />\n    <ClInclude Include=\"worldBenchmark.h\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "benchmarks/complexObjectBenchmark.cpp",
    "content": "#include \"worldBenchmark.h\"\n\n#include <Physics3D/world.h>\n#include <Physics3D/geometry/shapeLibrary.h>\n#include <Physics3D/geometry/shapeCreation.h>\n#include <Physics3D/math/linalg/commonMatrices.h>\n\nnamespace P3D {\nclass ComplexObjectBenchmark : public WorldBenchmark {\npublic:\n\tComplexObjectBenchmark() : WorldBenchmark(\"complexObject\", 10000) {}\n\n\tvoid init() {\n\t\tcreateFloor(50, 50, 10);\n\t\tPolyhedron object = ShapeLibrary::icosahedron;\n\t\tworld.addPart(new Part(polyhedronShape(ShapeLibrary::createSphere(1.0, 7)), GlobalCFrame(0, 2.0, 0), basicProperties));\n\t}\n} complexObjectBench;\n};\n"
  },
  {
    "path": "benchmarks/ecsBenchmark.cpp",
    "content": "#include \"benchmark.h\"\n#include \"../engine/ecs/registry.h\"\n#include \"../util/log.h\"\n\nnamespace P3D::Engine {\nclass ECSGetFromRegistryBenchmark : public Benchmark {\npublic:\n\tECSGetFromRegistryBenchmark() : Benchmark(\"ecsGetFromRegistryBenchmark\") {}\n\n\tRegistry64 registry;\n\tstd::vector<int> v{1, 2, 3, 4, 5, 6};\n\tint errors = 0;\n\t\n\tstruct A : public RC {\n\t\tint i; \n\t\t\n\t\tA(int i) : i(i) {}\n\t};\n\n\tvoid init() override {\n\t\tint amount = 1000000;\n\t\tfor(int i = 0; i < amount; i++) {\n\t\t\tauto id = registry.create();\n\t\t\tregistry.add<A>(id, i);\n\t\t}\n\t}\n\n\tvoid run() override {\n\t\tint i = 0;\n\t\tauto view = registry.view<A>();\n\t\tfor(auto entity : view) {\n\t\t\tauto& comp = *registry.get<A>(entity);\n\t\t\tif(comp.i != i)\n\t\t\t\terrors++;\n\t\t\ti++;\n\t\t}\n\t}\n\n\tvoid printResults(double timeTaken) override {\n\t\tLog::error(\"Amount of errors: %d\\n\", errors);\n\t}\n\n} ecsGetFromRegistryBenchmark;\n\nclass ECSGetFromViewConjunctionBenchmark : public Benchmark {\npublic:\n\tECSGetFromViewConjunctionBenchmark() : Benchmark(\"ecsGetFromViewConjunctionBenchmark\") {}\n\n\tRegistry64 registry;\n\tint errors = 0;\n\n\tstruct A : public RC { int i; A(int i) : i(i) {} };\n\n\tvoid init() override {\n\t\tint amount = 1000000;\n\t\tfor(int i = 0; i < amount; i++) {\n\t\t\tauto id = registry.create();\n\t\t\tregistry.add<A>(id, i);\n\t\t}\n\t}\n\n\tvoid run() override {\n\t\tint i = 0;\n\t\tauto view = registry.view<Registry64::conj<A>>();\n\t\tfor(auto entity : view) {\n\t\t\tauto comp = view.get<A>(entity);\n\t\t\tif(comp->i != i)\n\t\t\t\terrors++;\n\t\t\ti++;\n\t\t}\n\t}\n\n\tvoid printResults(double timeTaken) override {\n\t\tLog::error(\"Amount of errors: %d\\n\", errors);\n\t}\n\n} ecsGetFromViewConjunctionBenchmark;\n\n/*class ECSGetFromViewDisjunctionBenchmark : public Benchmark {\npublic:\n\tECSGetFromViewDisjunctionBenchmark() : Benchmark(\"ecsGetFromViewDisjunctionBenchmark\") {}\n\n\tRegistry64 registry;\n\tint errors = 0;\n\n\tstruct A : public RefCountable { int i; A(int i) : i(i) {} };\n\n\tvoid init() override {\n\t\tint amount = 1000000;\n\t\tfor (int i = 0; i < amount; i++) {\n\t\t\tauto id = registry.create();\n\t\t\tregistry.add<A>(id, i);\n\t\t}\n\t}\n\n\tvoid run() override {\n\t\tint i = 0;\n\t\tauto view = registry.view(Registry64::disjunction<A>());\n\t\tfor (auto entity : view) {\n\t\t\tauto comp = view.get<A>(entity);\n\t\t\tif (comp->i != i)\n\t\t\t\terrors++;\n\t\t\ti++;\n\t\t}\n\t}\n\n\tvoid printResults(double timeTaken) override {\n\t\tLog::error(\"Amount of errors: %d\\n\", errors);\n\t}\n\n} ecsGetFromViewDisjunctionBenchmark;*/\n};"
  },
  {
    "path": "benchmarks/getBoundsPerformance.cpp",
    "content": "#include \"benchmark.h\"\n\n#include <Physics3D/geometry/polyhedron.h>\n#include <Physics3D/geometry/shapeLibrary.h>\n#include <Physics3D/math/linalg/trigonometry.h>\n\nnamespace P3D {\nclass GetBounds : public Benchmark {\n\tPolyhedron poly;\n\tdouble result = 0;\npublic:\n\tGetBounds() : Benchmark(\"getBounds\") {}\n\n\tvoid init() override { this->poly = ShapeLibrary::createSphere(1.0, 2); }\n\tvoid run() override {\n\t\tMat3f m = rotationMatrixfromEulerAngles(0.1f, 0.05f, 0.7f);\n\t\tfor(size_t i = 0; i < 10000000; i++) {\n\t\t\t//Mat3 m = rotationMatrixfromEulerAngles(0.1 * (i%5), 0.2 * (i%6), 0.3 * (i%7));\n\n\t\t\tBoundingBox r = this->poly.getBounds(m);\n\t\t\tresult += r.min.x + r.min.y + r.min.z + r.max.x + r.max.y + r.max.z;\n\t\t}\n\t}\n} getBounds;\n};\n\n\n\n"
  },
  {
    "path": "benchmarks/manyCubesBenchmark.cpp",
    "content": "\n#include <Physics3D/geometry/shapeLibrary.h>\n#include <Physics3D/geometry/shape.h>\n#include <Physics3D/geometry/shapeCreation.h>\n#include \"worldBenchmark.h\"\n#include <Physics3D/math/linalg/commonMatrices.h>\n#include <Physics3D/math/linalg/trigonometry.h>\n\nnamespace P3D {\nclass ManyCubesBenchmark : public WorldBenchmark {\npublic:\n\tManyCubesBenchmark() : WorldBenchmark(\"manyCubes\", 10000) {}\n\n\tvoid init() {\n\t\tcreateFloor(50, 50, 10);\n\n\t\tint minX = -5;\n\t\tint maxX = 5;\n\t\tint minY = -5;\n\t\tint maxY = 5;\n\t\tint minZ = -5;\n\t\tint maxZ = 5;\n\n\t\tGlobalCFrame ref(0, 15, 0, Rotation::fromEulerAngles(3.1415 / 4, 3.1415 / 4, 0.0));\n\n\t\t//Part* newCube = new Part(boxShape(1.0, 1.0, 1.0), ref.localToGlobal(CFrame(0,0,0)), {1.0, 0.2, 0.5});\n\t\t//world.addPart(newCube);\n\n\t\tfor(double x = minX; x < maxX; x += 1.01) {\n\t\t\tfor(double y = minY; y < maxY; y += 1.01) {\n\t\t\t\tfor(double z = minZ; z < maxZ; z += 1.01) {\n\t\t\t\t\tPart* newCube = new Part(polyhedronShape(ShapeLibrary::createBox(1.0, 1.0, 1.0)), ref.localToGlobal(CFrame(x, y, z)), {1.0, 0.2, 0.5});\n\t\t\t\t\tworld.addPart(newCube);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n} manyCubesBench;\n};\n"
  },
  {
    "path": "benchmarks/rotationBenchmark.cpp",
    "content": "#include \"benchmark.h\"\n\n#include <Physics3D/math/rotation.h>\n#include <random>\n\nnamespace P3D {\nstatic double randomDouble() {\n\treturn double(rand()) / RAND_MAX;\n}\n\n#define ROTATION_BENCH_SIZE 10000000\n\nclass RotationLocalToGlobalVecCPU : public Benchmark {\n\tRotation rot;\n\tVec3 curValue;\npublic:\n\tRotationLocalToGlobalVecCPU() : Benchmark(\"rotationL2GVecCPU\") {}\n\n\tvoid init() override {\n\t\tthis->rot = Rotation::fromEulerAngles(randomDouble(), randomDouble(), randomDouble());\n\t\tcurValue = Vec3(randomDouble(), randomDouble(), randomDouble());\n\t}\n\tvoid run() override {\n\t\tfor(int round = 0; round < ROTATION_BENCH_SIZE * 100; round++) {\n\t\t\tcurValue = rot.localToGlobal(curValue);\n\t\t}\n\t}\n} rotationLocalToGlobalVecCPU;\n\nclass RotationLocalToGlobalMatCPU : public Benchmark {\n\tRotation rot;\n\tSymmetricMat3 curValue;\npublic:\n\tRotationLocalToGlobalMatCPU() : Benchmark(\"rotationL2GMatCPU\") {}\n\n\tvoid init() override {\n\t\tthis->rot = Rotation::fromEulerAngles(randomDouble(), randomDouble(), randomDouble());\n\t\tcurValue = SymmetricMat3{randomDouble(), randomDouble(), randomDouble(), randomDouble(), randomDouble(), randomDouble()};\n\t}\n\tvoid run() override {\n\t\tfor(int round = 0; round < ROTATION_BENCH_SIZE * 100; round++) {\n\t\t\tcurValue = rot.localToGlobal(curValue);\n\t\t}\n\t}\n} rotationLocalToGlobalMatCPU;\n\nclass RotationLocalToGlobalRotCPU : public Benchmark {\n\tRotation rot;\n\tRotation curValue;\npublic:\n\tRotationLocalToGlobalRotCPU() : Benchmark(\"rotationL2GRotCPU\") {}\n\n\tvoid init() override {\n\t\tthis->rot = Rotation::fromEulerAngles(randomDouble(), randomDouble(), randomDouble());\n\t\tcurValue = Rotation::fromEulerAngles(randomDouble(), randomDouble(), randomDouble());\n\t}\n\tvoid run() override {\n\t\tfor(int round = 0; round < ROTATION_BENCH_SIZE * 100; round++) {\n\t\t\tcurValue = rot.localToGlobal(curValue);\n\t\t}\n\t}\n} rotationLocalToGlobalRotCPU;\n\n\n\nclass RotationLocalToGlobalVecMem : public Benchmark {\n\tRotation* rot = nullptr;\n\tVec3 curValue;\npublic:\n\tRotationLocalToGlobalVecMem() : Benchmark(\"rotationL2GVecMem\") {}\n\n\tvoid init() override {\n\t\tif(rot == nullptr) this->rot = new Rotation[ROTATION_BENCH_SIZE];\n\t\tfor(int round = 0; round < ROTATION_BENCH_SIZE; round++) {\n\t\t\tthis->rot[round] = Rotation::fromEulerAngles(randomDouble(), randomDouble(), randomDouble());\n\t\t}\n\t\tcurValue = Vec3(randomDouble(), randomDouble(), randomDouble());\n\t}\n\t~RotationLocalToGlobalVecMem() {\n\t\tdelete[] rot;\n\t}\n\tvoid run() override {\n\t\tfor(int round = 0; round < ROTATION_BENCH_SIZE; round++) {\n\t\t\tcurValue = rot[round].localToGlobal(curValue);\n\t\t}\n\t}\n} rotationLocalToGlobalVecMem;\n\nclass RotationLocalToGlobalMatMem : public Benchmark {\n\tRotation* rot = nullptr;\n\tSymmetricMat3 curValue;\npublic:\n\tRotationLocalToGlobalMatMem() : Benchmark(\"rotationL2GMatMem\") {}\n\n\tvoid init() override {\n\t\tif(rot == nullptr) this->rot = new Rotation[ROTATION_BENCH_SIZE];\n\t\tfor(int round = 0; round < ROTATION_BENCH_SIZE; round++) {\n\t\t\tthis->rot[round] = Rotation::fromEulerAngles(randomDouble(), randomDouble(), randomDouble());\n\t\t}\n\t\tcurValue = SymmetricMat3{randomDouble(), randomDouble(), randomDouble(), randomDouble(), randomDouble(), randomDouble()};\n\t}\n\t~RotationLocalToGlobalMatMem() {\n\t\tdelete[] rot;\n\t}\n\tvoid run() override {\n\t\tfor(int round = 0; round < ROTATION_BENCH_SIZE; round++) {\n\t\t\tcurValue = rot[round].localToGlobal(curValue);\n\t\t}\n\t}\n} rotationLocalToGlobalMatMem;\n\nclass RotationLocalToGlobalRotMem : public Benchmark {\n\tRotation* rot = nullptr;\n\tRotation curValue;\npublic:\n\tRotationLocalToGlobalRotMem() : Benchmark(\"rotationL2GRotMem\") {}\n\n\tvoid init() override {\n\t\tif(rot == nullptr) this->rot = new Rotation[ROTATION_BENCH_SIZE];\n\t\tfor(int round = 0; round < ROTATION_BENCH_SIZE; round++) {\n\t\t\tthis->rot[round] = Rotation::fromEulerAngles(randomDouble(), randomDouble(), randomDouble());\n\t\t}\n\t\tcurValue = Rotation::fromEulerAngles(randomDouble(), randomDouble(), randomDouble());\n\t}\n\t~RotationLocalToGlobalRotMem() {\n\t\tdelete[] rot;\n\t}\n\tvoid run() override {\n\t\tfor(int round = 0; round < ROTATION_BENCH_SIZE; round++) {\n\t\t\tcurValue = rot[round].localToGlobal(curValue);\n\t\t}\n\t}\n} rotationLocalToGlobalRotMem;\n};\n"
  },
  {
    "path": "benchmarks/threadResponseTime.cpp",
    "content": "#include \"benchmark.h\"\n\n#include <iostream>\n#include <chrono>\n#include <mutex>\n#include <thread>\n#include <vector>\n\n#include <Physics3D/threading/threadPool.h>\n\nusing namespace std::chrono;\n\nnamespace P3D {\nclass ThreadCreateBenchmark : public Benchmark {\npublic:\n\tThreadCreateBenchmark() : Benchmark(\"threadCreateResponseTime\") {}\n\n\tvirtual void init() override {}\n\n\tvirtual void run() override {\n\t\tdecltype(high_resolution_clock::now()) start;\n\n\t\tstd::mutex coutMutex;\n\n\t\tstd::cout << \"\\n\";\n\t\tauto work = [&start, &coutMutex]() {\n\t\t\tauto response = high_resolution_clock::now();\n\n\t\t\tnanoseconds delay = response - start;\n\n\t\t\tcoutMutex.lock();\n\t\t\tstd::cout << delay.count() / 1000 << \" microseconds\\n\";\n\t\t\tcoutMutex.unlock();\n\t\t\tstd::this_thread::sleep_for(milliseconds(1000));\n\t\t};\n\n\t\tstd::vector<std::thread> threads(std::thread::hardware_concurrency() - 1);\n\n\t\tfor(int iter = 0; iter < 5; iter++) {\n\t\t\tstd::cout << \"Run \" << iter << \"\\n\";\n\t\t\tstart = high_resolution_clock::now();\n\t\t\tfor(std::thread& t : threads) t = std::thread(work);\n\t\t\twork();\n\t\t\tfor(std::thread& t : threads) t.join();\n\t\t}\n\t}\n\n\tvirtual void printResults(double timeTaken) override {}\n\n} threadCreate;\n\nclass ThreadPoolBenchmark : public Benchmark {\npublic:\n\tThreadPoolBenchmark() : Benchmark(\"threadPoolResponseTime\") {}\n\n\tvirtual void init() override {}\n\n\tvirtual void run() override {\n\t\tdecltype(high_resolution_clock::now()) start;\n\n\t\tstd::mutex coutMutex;\n\n\t\tstd::cout << \"\\n\";\n\t\tauto work = [&start, &coutMutex]() {\n\t\t\tauto response = high_resolution_clock::now();\n\n\t\t\tnanoseconds delay = response - start;\n\n\t\t\tcoutMutex.lock();\n\t\t\tstd::cout << delay.count() / 1000 << \" microseconds\\n\";\n\t\t\tcoutMutex.unlock();\n\t\t\tstd::this_thread::sleep_for(milliseconds(1000));\n\t\t};\n\n\t\tstd::vector<std::thread> threads(std::thread::hardware_concurrency() - 1);\n\n\t\tThreadPool threadPool;\n\n\t\tfor(int iter = 0; iter < 5; iter++) {\n\t\t\tstd::cout << \"Run \" << iter << \"\\n\";\n\t\t\tstart = high_resolution_clock::now();\n\t\t\tthreadPool.doInParallel(work);\n\t\t}\n\t}\n\n\tvirtual void printResults(double timeTaken) override {}\n\n} threadPool;\n};\n\n"
  },
  {
    "path": "benchmarks/worldBenchmark.cpp",
    "content": "#include \"worldBenchmark.h\"\n\n#include \"../util/log.h\"\n#include \"../util/terminalColor.h\"\n#include <iostream>\n#include <sstream>\n#include <cstddef>\n#include <Physics3D/externalforces/directionalGravity.h>\n\n#include <Physics3D/geometry/shape.h>\n#include <Physics3D/geometry/shapeCreation.h>\n#include <Physics3D/math/linalg/commonMatrices.h>\n\n#include <Physics3D/geometry/shapeLibrary.h>\n#include <Physics3D/boundstree/filters/outOfBoundsFilter.h>\n#include <Physics3D/misc/physicsProfiler.h>\n\n#include <Physics3D/world.h>\n#include <Physics3D/worldIteration.h>\n\nnamespace P3D {\nWorldBenchmark::WorldBenchmark(const char* name, int tickCount) : Benchmark(name), world(0.005), tickCount(tickCount) {\n\tworld.addExternalForce(new DirectionalGravity(Vec3(0, -10, 0)));\n}\n\nvoid WorldBenchmark::run() {\n\tworld.isValid();\n\tPart& partToTrack = *world.physicals[0]->getMainPart();\n\tfor(int i = 0; i < tickCount; i++) {\n\t\tif(i % (tickCount / 8) == 0) {\n\t\t\tLog::print(\"Tick %d\\n\", i);\n\t\t\tPosition pos = partToTrack.getCFrame().getPosition();\n\t\t\tLog::print(\"Location of object: %.5f %.5f %.5f\\n\", double(pos.x), double(pos.y), double(pos.z));\n\n\t\t\tstd::size_t partsOutOfBounds = 0;\n\t\t\tworld.forEachPartFiltered(OutOfBoundsFilter(Bounds(Position(-100.0, -100.0, -100.0), Position(100.0, 100.0, 100.0))), [&partsOutOfBounds](const Part&) {\n\t\t\t\tpartsOutOfBounds++;\n\t\t\t});\n\n\t\t\tLog::print(\"%d/%d parts out of bounds!\\n\", partsOutOfBounds, world.getPartCount());\n\t\t}\n\n\t\tphysicsMeasure.mark(PhysicsProcess::OTHER);\n\n\t\tworld.tick();\n\n\t\tphysicsMeasure.end();\n\n\t\tGJKCollidesIterationStatistics.nextTally();\n\t\tGJKNoCollidesIterationStatistics.nextTally();\n\t\tEPAIterationStatistics.nextTally();\n\t}\n\tworld.isValid();\n}\n\nstatic const std::size_t LABEL_LENGTH = 23;\nstatic const std::size_t COUNT_LENGTH = 11;\nstatic const std::size_t FRACTION_LENGTH = 6;\nstatic const std::size_t BAR_LENGTH = 36;\n\nvoid printToLength(std::string text, std::size_t length) {\n\tstd::cout << text;\n\tsetColor(TerminalColor::BLACK);\n\tfor(std::size_t i = text.size(); i < length; i++) {\n\t\tstd::cout << ' ';\n\t}\n}\n\nstatic TerminalColor colors[]{\n\tTerminalColor::BLUE,\n\tTerminalColor::RED,\n\tTerminalColor::YELLOW,\n\tTerminalColor::MAGENTA,\n\tTerminalColor::GREEN,\n\tTerminalColor::CYAN,\n\tTerminalColor::WHITE,\n\t/*Log::RED,\n\tLog::GREEN,\n\tLog::BLUE,\n\tLog::YELLOW,\n\tLog::MAGENTA,\n\tLog::AQUA,\n\tLog::WHITE,*/\n};\n\nTerminalColor getColor(std::size_t i) {\n\t//return (colors[i] >= 0x7) ? colors[i] : colors[i] | (Log::WHITE << 4);\n\treturn colors[i % 7];\n}\n\n/*int getBGColor(std::size_t i) {\n\treturn colors[i % 7] << 4 | colors[i % 7];\n}*/\n\ntemplate<typename T>\nvoid printBreakdown(const T* values, const char** labels, std::size_t N, std::string unit) {\n\n\tT total = values[0];\n\tT max = values[0];\n\n\tfor(std::size_t i = 1; i < N; i++) {\n\t\ttotal += values[i];\n\t\tmax = (values[i] > max) ? values[i] : max;\n\t}\n\n\tfor(std::size_t i = 0; i < N; i++) {\n\t\tT v = values[i];\n\t\tdouble fractionOfTotal = total != 0 ? double(v) / total : 0.0;\n\t\tdouble fractionOfMax = total != 0 ? double(v) / max : 0.0;\n\n\t\tsetColor(getColor(i));\n\n\t\tprintToLength(labels[i] + std::string(\":\"), LABEL_LENGTH);\n\n\t\tstd::stringstream ss;\n\t\tss.precision(5);\n\t\tss << std::fixed;\n\t\tss << v;\n\t\tss << unit;\n\n\t\tsetColor(getColor(i));\n\t\tprintToLength(ss.str(), COUNT_LENGTH);\n\n\t\tstd::stringstream ss2;\n\t\tss2.precision(2);\n\t\tss2 << std::fixed;\n\t\tss2 << (fractionOfTotal * 100);\n\t\tss2 << \"%\";\n\n\t\tsetColor(getColor(i));\n\t\tprintToLength(ss2.str(), FRACTION_LENGTH);\n\n\t\tsetColor(TerminalColor::BLACK);\n\t\tstd::cout << ' ';\n\t\tsetColor(TerminalColor::WHITE, TerminalColor::WHITE);\n\t\tstd::cout << ' ';\n\n\t\tstd::size_t thisBarLength = static_cast<std::size_t>(std::ceil(BAR_LENGTH * fractionOfMax));\n\n\t\tsetColor(getColor(i), getColor(i));\n\t\tfor(std::size_t i = 0; i < thisBarLength; i++) {\n\t\t\tstd::cout << '=';\n\t\t}\n\t\tsetColor(TerminalColor::BLACK);\n\t\tstd::cout << '|';\n\n\t\tstd::cout << '\\n';\n\t}\n\n}\n\nvoid WorldBenchmark::printResults(double timeTakenMillis) {\n\tdouble tickTime = (timeTakenMillis) / tickCount;\n\tLog::print(\"%d ticks at %f ticks per second\\n\", tickCount, 1000 / tickTime);\n\n\tauto physicsBreakdown = physicsMeasure.history.avg();\n\n\tdouble millis[physicsMeasure.size()];\n\n\tfor(std::size_t i = 0; i < physicsMeasure.size(); i++) {\n\t\tmillis[i] = physicsBreakdown[i].count() / 1000000.0;\n\t}\n\n\tsetColor(TerminalColor::WHITE);\n\tstd::cout << \"\\n\";\n\tsetColor(TerminalColor::MAGENTA);\n\tstd::cout << \"[Physics Profiler]\\n\";\n\tprintBreakdown(millis, physicsMeasure.labels, physicsMeasure.size(), \"ms\");\n\n\tsetColor(TerminalColor::WHITE);\n\tstd::cout << \"\\n\";\n\tsetColor(TerminalColor::MAGENTA);\n\tstd::cout << \"[Intersection Statistics]\\n\";\n\tprintBreakdown(intersectionStatistics.history.avg().values, intersectionStatistics.labels, intersectionStatistics.size(), \"\");\n\tsetColor(TerminalColor::WHITE);\n}\n\n\nvoid WorldBenchmark::createFloor(double w, double h, double wallHeight) {\n\tworld.addTerrainPart(new Part(boxShape(w, 1.0, h), GlobalCFrame(0.0, 0.0, 0.0), basicProperties));\n\tworld.addTerrainPart(new Part(boxShape(0.8, wallHeight, h), GlobalCFrame(w, wallHeight / 2, 0.0), basicProperties));\n\tworld.addTerrainPart(new Part(boxShape(0.8, wallHeight, h), GlobalCFrame(-w, wallHeight / 2, 0.0), basicProperties));\n\tworld.addTerrainPart(new Part(boxShape(w, wallHeight, 0.8), GlobalCFrame(0.0, wallHeight / 2, h), basicProperties));\n\tworld.addTerrainPart(new Part(boxShape(w, wallHeight, 0.8), GlobalCFrame(0.0, wallHeight / 2, -h), basicProperties));\n}\n};\n"
  },
  {
    "path": "benchmarks/worldBenchmark.h",
    "content": "#pragma once\n\n#include \"benchmark.h\"\n#include <Physics3D/world.h>\n\nnamespace P3D {\nstatic const PartProperties basicProperties{1.0, 0.7, 0.5};\nclass WorldBenchmark : public Benchmark {\nprotected:\n\tWorldPrototype world;\n\tint tickCount;\n\npublic:\n\tWorldBenchmark(const char* name, int tickCount);\n\n\tvirtual void run() override;\n\tvirtual void printResults(double timeTaken) override;\n\n\tvoid createFloor(double w, double h, double wallHeight);\n};\n};\n"
  },
  {
    "path": "engine/core.cpp",
    "content": "#include \"core.h\""
  },
  {
    "path": "engine/core.h",
    "content": "#pragma once\n\n#include <unordered_map>\n#include <type_traits>\n#include <functional>\n#include <algorithm>\n#include <cstdint>\n#include <utility>\n#include <string>\n#include <vector>\n#include <queue>\n#include <cmath>\n#include <map>\n#include <set>\n\n#include <Physics3D/math/linalg/vec.h>\n#include <Physics3D/math/fix.h>\n#include <Physics3D/math/linalg/mat.h>\n#include <Physics3D/math/linalg/trigonometry.h>\n#include <Physics3D/math/position.h>\n#include <Physics3D/datastructures/smartPointers.h>\n\n#include \"../util/log.h\"\n"
  },
  {
    "path": "engine/ecs/registry.h",
    "content": "#pragma once\n\n#include <set>\n#include <queue>\n#include <vector>\n#include <cstdint>\n#include <type_traits>\n#include <unordered_map>\n#include \"../util/typetraits.h\"\n#include \"../util/iteratorUtils.h\"\n#include \"../util/stringUtil.h\"\n#include \"../Physics3D/datastructures/smartPointers.h\"\n\nnamespace P3D::Engine {\n\ntemplate <typename, typename = void>\nstruct registry_traits;\n\ntemplate <typename Type>\nstruct registry_traits<Type, std::enable_if_t<std::is_enum_v<Type>>> : registry_traits<std::underlying_type_t<Type>> {};\n\n\n/**\n * entity = 8 parent bits, 8 self bits\n */\ntemplate <>\nstruct registry_traits<std::uint16_t> {\n\tusing representation_type = std::uint16_t;\n\tusing entity_type = std::uint8_t;\n\tusing component_type = std::uint16_t;\n\n\tstatic constexpr entity_type entity_mask = 0xFF;\n\tstatic constexpr std::size_t parent_shift = 8u;\n};\n\n/**\n * entity = 16 parent bits, 16 self bits\n */\ntemplate <>\nstruct registry_traits<std::uint32_t> {\n\tusing representation_type = std::uint32_t;\n\tusing entity_type = std::uint16_t;\n\tusing component_type = std::uint16_t;\n\n\tstatic constexpr entity_type entity_mask = 0xFFFF;\n\tstatic constexpr std::size_t parent_shift = 16u;\n};\n\n/**\n * entity = 32 parent bits, 32 self bits\n */\ntemplate <>\nstruct registry_traits<std::uint64_t> {\n\tusing representation_type = std::uint64_t;\n\tusing entity_type = std::uint32_t;\n\tusing component_type = std::uint16_t;\n\n\tstatic constexpr entity_type entity_mask = 0xFFFFFFFF;\n\tstatic constexpr std::size_t parent_shift = 32u;\n};\n\ntemplate <typename Entity>\nclass Registry {\n\n\t//-------------------------------------------------------------------------------------//\n\t// Contructor                                                                          //\n\t//-------------------------------------------------------------------------------------//\n\npublic:\n\tRegistry() = default;\n\t~Registry() = default;\n\tRegistry(Registry&&) = delete;\n\tRegistry(const Registry&) = delete;\n\tRegistry& operator=(const Registry&) = delete;\n\tRegistry& operator=(Registry&&) = delete;\n\n\t//-------------------------------------------------------------------------------------//\n\t// Types                                                                               //\n\t//-------------------------------------------------------------------------------------//\n\npublic:\n\tusing registry_type = Registry<Entity>;\n\tusing traits_type = registry_traits<Entity>;\n\tusing entity_type = typename traits_type::entity_type;\n\tusing component_type = typename traits_type::component_type;\n\tusing representation_type = typename traits_type::representation_type;\n\n\n\t//-------------------------------------------------------------------------------------//\n\t// Member types                                                                        //\n\t//-------------------------------------------------------------------------------------//\n\nprivate:\n\tstruct entity_compare {\n\t\tbool operator()(const representation_type& left, const representation_type& right) const noexcept {\n\t\t\treturn self(left) < self(right);\n\t\t}\n\t};\n\npublic:\n\tusing entity_set = std::set<representation_type, entity_compare>;\n\tusing entity_queue = std::queue<entity_type>;\n\tusing entity_map = std::unordered_multimap<entity_type, IRef<RC>>;\n\tusing type_map = std::unordered_map<component_type, std::string>;\n\tusing component_vector = std::vector<entity_map*>;\n\n\tusing component_vector_iterator = decltype(std::declval<component_vector>().begin());\n\tusing component_map_iterator = decltype(std::declval<entity_map>().begin());\n\tusing entity_set_iterator = decltype(std::declval<entity_set>().begin());\n\n\t// Null entity\n\tinline static entity_type null_entity = static_cast<entity_type>(0u);\n\n\n\t//-------------------------------------------------------------------------------------//\n\t// Members                                                                             //\n\t//-------------------------------------------------------------------------------------//\n\nprivate:\n\tentity_set entities;\n\tcomponent_vector components;\n\ttype_map type_mapping;\n\n\tentity_queue id_queue;\n\tentity_type id_counter = null_entity;\n\n\tconstexpr entity_type nextID() noexcept {\n\t\treturn ++id_counter;\n\t}\n\n\n\t//-------------------------------------------------------------------------------------//\n\t// Helper structs                                                                      //\n\t//-------------------------------------------------------------------------------------//\n\nprivate:\n\ttemplate <typename Type>\n\tstruct type_index {\n\t\tstatic Type next() noexcept {\n\t\t\tstatic Type value{};\n\t\t\treturn value++;\n\t\t}\n\t};\n\npublic:\n\ttemplate <typename Component = void>\n\tstruct component_index {\n\t\tusing traits_type = registry_traits<Entity>;\n\t\tusing component_type = typename traits_type::component_type;\n\n\t\tstatic component_type index() {\n\t\t\tstatic const component_type value = type_index<component_type>::next();\n\t\t\treturn value;\n\t\t}\n\t};\n\nprivate:\n\tstatic constexpr entity_type self(const representation_type& entity) noexcept {\n\t\treturn static_cast<entity_type>(entity & traits_type::entity_mask);\n\t}\n\n\tstatic constexpr entity_type parent(const representation_type& entity) noexcept {\n\t\treturn static_cast<entity_type>(entity >> traits_type::parent_shift) & traits_type::entity_mask;\n\t}\n\n\tstatic constexpr representation_type merge(const entity_type& parent, const entity_type& entity) noexcept {\n\t\treturn (static_cast<representation_type>(parent) << traits_type::parent_shift) | static_cast<representation_type>(entity);\n\t}\n\n\n\t//-------------------------------------------------------------------------------------//\n\t// View iterators                                                                      //\n\t//-------------------------------------------------------------------------------------//\n\npublic:\n\tstruct component_iterator : component_map_iterator {\n\tpublic:\n\t\tcomponent_iterator() = default;\n\n\t\texplicit component_iterator(component_map_iterator&& iterator) : component_map_iterator(std::move(iterator)) {}\n\n\t\tauto& operator*() const {\n\t\t\treturn component_map_iterator::operator*().first;\n\t\t}\n\t};\n\n\n\t//-------------------------------------------------------------------------------------//\n\t// View types                                                                          //\n\t//-------------------------------------------------------------------------------------//\n\nprivate:\n\ttemplate <typename Type>\n\tstruct type {};\n\npublic:\n\tstruct no_type {\n\t\ttemplate <typename Component>\n\t\tstatic IRef<Component> get(Registry<Entity>* registry, const entity_type& entity) {\n\t\t\treturn registry->get<Component>(entity);\n\t\t}\n\n\t\ttemplate <typename Component>\n\t\tstatic auto getAll(Registry<Entity>* registry, const entity_type& entity) {\n\t\t\treturn registry->getAll<Component>(entity);\n\t\t}\n\t};\n\n\ttemplate <typename Component>\n\tstruct only {\n\t\ttemplate <typename UnsafeComponent>\n\t\tstatic IRef<UnsafeComponent> get(Registry<Entity>* registry, const entity_type& entity) {\n\t\t\tif (std::is_same_v<UnsafeComponent, Component>) {\n\t\t\t\tcomponent_type index = registry->getComponentIndex<Component>();\n\t\t\t\tentity_map* map = registry->components[index];\n\n\t\t\t\tauto component_iterator = map->find(entity);\n\t\t\t\treturn intrusive_cast<UnsafeComponent>(component_iterator->second);\n\t\t\t} else {\n\t\t\t\treturn registry->get<UnsafeComponent>(entity);\n\t\t\t}\n\t\t}\n\n\t\ttemplate <typename UnsafeComponent>\n\t\tstatic auto getAll(Registry<Entity>* registry, const entity_type& entity) {\n\t\t\treturn registry->getAll<UnsafeComponent>(entity);\n\t\t}\n\t};\n\n\ttemplate <typename... Components>\n\tstruct conj {\n\t\ttemplate <typename Component>\n\t\tstatic IRef<Component> get(Registry<Entity>* registry, const entity_type& entity) {\n\t\t\tif (is_part_of<Component, Components...>) {\n\t\t\t\tcomponent_type index = registry->getComponentIndex<Component>();\n\t\t\t\tentity_map* map = registry->components[index];\n\n\t\t\t\tauto component_iterator = map->find(entity);\n\t\t\t\treturn intrusive_cast<Component>(component_iterator->second);\n\t\t\t} else {\n\t\t\t\treturn registry->get<Component>(entity);\n\t\t\t}\n\n\t\t}\n\n\t\ttemplate <typename Component>\n\t\tstatic auto getAll(Registry<Entity>* registry, const entity_type& entity) {\n\t\t\treturn registry->getAll<Component>(entity);\n\t\t}\n\t};\n\n\ttemplate <typename... Components>\n\tstruct disj {\n\t\ttemplate <typename Component>\n\t\tstatic IRef<Component> get(Registry<Entity>* registry, const entity_type& entity) {\n\t\t\treturn registry->get<Component>(entity);\n\t\t}\n\n\t\ttemplate <typename Component>\n\t\tstatic auto getAll(Registry<Entity>* registry, const entity_type& entity) {\n\t\t\treturn registry->getAll<Component>(entity);\n\t\t}\n\t};\n\n\ttemplate <typename ComponentA, typename ComponentB>\n\tstruct exor {};\n\n\ttemplate <typename T>\n\tstruct neg;\n\n\n\t//-------------------------------------------------------------------------------------//\n\t// Basic view                                                                          //\n\t//-------------------------------------------------------------------------------------//\n\npublic:\n\ttemplate <typename ViewType, typename BeginType, typename EndType = iterator_end>\n\tclass basic_view {\n\tprivate:\n\t\tRegistry<Entity>* registry;\n\t\tBeginType start;\n\t\tEndType stop;\n\n\tpublic:\n\t\tbasic_view() = default;\n\n\t\tbasic_view(Registry<Entity>* registry, const BeginType& start, const EndType& stop)\n\t\t\t: registry(registry)\n\t\t\t, start(start)\n\t\t\t, stop(stop) {}\n\n\t\tBeginType begin() const {\n\t\t\treturn start;\n\t\t}\n\n\t\tEndType end() const {\n\t\t\treturn stop;\n\t\t}\n\n\t\ttemplate <typename Component>\n\t\tIRef<Component> get(const entity_type& entity) {\n\t\t\treturn ViewType::template get<Component>(this->registry, entity);\n\t\t}\n\n\t\ttemplate <typename Component>\n\t\tauto getAll(const entity_type& entity) {\n\t\t\treturn ViewType::template getAll<Component>(this->registry, entity);\n\t\t}\n\t};\n\n\tentity_set_iterator begin() noexcept {\n\t\treturn entities.begin();\n\t}\n\n\tentity_set_iterator end() noexcept {\n\t\treturn entities.end();\n\t}\n\n\n\t//-------------------------------------------------------------------------------------//\n\t// Views helper Functions                                                              //\n\t//-------------------------------------------------------------------------------------//\n\nprivate:\n\ttemplate <typename... Components>\n\tstd::enable_if_t<sizeof...(Components) == 0> init() {}\n\n\ttemplate <typename... Components>\n\tstd::enable_if_t<sizeof...(Components) == 0> extract_smallest_component(component_type& smallest_component,\n\t                                                                        std::size_t& smallest_size,\n\t                                                                        std::vector<component_type>& other_components) {}\n\n\ttemplate <typename Component, typename... Components>\n\tvoid extract_smallest_component(component_type& smallest_component,\n\t                                std::size_t& smallest_size,\n\t                                std::vector<component_type>& other_components) noexcept {\n\t\tcomponent_type current_component = getComponentIndex<Component>();\n\t\tconst std::size_t current_size = this->components[current_component]->size();\n\n\t\tif (current_size < smallest_size) {\n\t\t\tother_components.push_back(smallest_component);\n\t\t\tsmallest_component = current_component;\n\t\t\tsmallest_size = current_size;\n\t\t} else\n\t\t\tother_components.push_back(current_component);\n\n\t\textract_smallest_component<Components...>(smallest_component, smallest_size, other_components);\n\t}\n\n\ttemplate <typename... Components>\n\tstd::enable_if_t<sizeof...(Components) == 0> insert_entities(entity_set& entities) {}\n\n\ttemplate <typename Component, typename... Components>\n\tvoid insert_entities(entity_set& entities) noexcept {\n\t\tstd::size_t component = getComponentIndex<Component>();\n\n\t\tentity_map* map = this->components[component];\n\t\tif (map != nullptr) {\n\t\t\tcomponent_iterator first(map->begin());\n\t\t\tcomponent_iterator last(map->end());\n\n\t\t\tentities.insert(first, last);\n\t\t}\n\n\t\tinsert_entities<Components...>(entities);\n\t}\n\n\ttemplate <typename ViewType, typename Iterator, typename Filter>\n\tauto filter_view(const Iterator& first, const Iterator& last, const Filter& filter) noexcept {\n\t\tusing iterator_type = filter_iterator<Iterator, iterator_end, Filter>;\n\t\titerator_type start(first, last, filter);\n\t\titerator_end stop;\n\t\treturn basic_view<ViewType, iterator_type>(this, start, stop);\n\t}\n\n\ttemplate <typename ViewType, typename Iterator, typename Transform>\n\tauto transform_view(const Iterator& first, const Iterator& last, const Transform& transform) noexcept {\n\t\tusing iterator_type = transform_iterator<Iterator, iterator_end, Transform>;\n\t\titerator_type start(first, last, transform);\n\t\titerator_end stop;\n\t\treturn basic_view<ViewType, iterator_type>(this, start, stop);\n\t}\n\n\ttemplate <typename ViewType, typename Iterator, typename Filter, typename Transform>\n\tauto filter_transform_view(const Iterator& first, const Iterator& last, const Filter& filter, const Transform& transform) noexcept {\n\t\tusing iterator_type = filter_transform_iterator<Iterator, iterator_end, Filter, Transform>;\n\t\titerator_type start(first, last, filter, transform);\n\t\titerator_end stop;\n\t\treturn basic_view<ViewType, iterator_type>(this, start, stop);\n\t}\n\n\ttemplate <typename ViewType, typename Iterator>\n\tauto default_view(const Iterator& first, const Iterator& last) noexcept {\n\t\tusing iterator_type = default_iterator<Iterator, iterator_end>;\n\t\titerator_type start(first, last);\n\t\titerator_end stop;\n\t\treturn basic_view<ViewType, iterator_type>(this, start, stop);\n\t}\n\n\t//-------------------------------------------------------------------------------------//\n\t// Filter matching                                                                     //\n\t//-------------------------------------------------------------------------------------//\n\n\ttemplate <typename Component>\n\tstruct match {\n\t\tconstexpr std::enable_if_t<std::is_base_of_v<RC, Component>, bool> operator()(Registry<Entity>& registry, const entity_type& entity) {\n\t\t\treturn registry.has<Component>(entity);\n\t\t}\n\t};\n\n\ttemplate <typename Component>\n\tstruct match<neg<Component>> {\n\t\tconstexpr bool operator()(Registry<Entity>& registry, const entity_type& entity) {\n\t\t\treturn !match<Component>()(registry, entity);\n\t\t}\n\t};\n\n\ttemplate <typename Component>\n\tstruct match<conj<Component>> {\n\t\tconstexpr bool operator()(Registry<Entity>& registry, const entity_type& entity) {\n\t\t\treturn match<Component>()(registry, entity);\n\t\t}\n\t};\n\n\ttemplate <typename Component>\n\tstruct match<disj<Component>> {\n\t\tconstexpr bool operator()(Registry<Entity>& registry, const entity_type& entity) {\n\t\t\treturn match<Component>()(registry, entity);\n\t\t}\n\t};\n\n\ttemplate <typename Component, typename... Components>\n\tstruct match<conj<Component, Components...>> {\n\t\tconstexpr bool operator()(Registry<Entity>& registry, const entity_type& entity) {\n\t\t\treturn match<Component>()(registry, entity) && match<conj<Components...>>()(registry, entity);\n\t\t}\n\t};\n\n\ttemplate <typename Component, typename... Components>\n\tstruct match<disj<Component, Components...>> {\n\t\tconstexpr bool operator()(Registry<Entity>& registry, const entity_type& entity) {\n\t\t\treturn match<Component>()(registry, entity) || match<disj<Components...>>()(registry, entity);\n\t\t}\n\t};\n\n\ttemplate <typename ComponentA, typename ComponentB>\n\tstruct match<exor<ComponentA, ComponentB>> {\n\t\tconstexpr bool operator()(Registry<Entity>& registry, const entity_type& entity) {\n\t\t\treturn match<ComponentA>()(registry, entity) != match<ComponentB>()(registry, entity);\n\t\t}\n\t};\n\n\t//-------------------------------------------------------------------------------------//\n\t// Mutators                                                                            //\n\t//-------------------------------------------------------------------------------------//\n\npublic:\n\t/**\n\t* Returns the index of the given component\n\t*/\n\ttemplate <typename Component>\n\t[[nodiscard]] component_type getComponentIndex() {\n\t\tcomponent_type index = component_index<Component>::index();\n\t\tif (index >= this->type_mapping.size()) {\n\t\t\tstd::string fullName = Util::typeName<Component>();\n\t\t\tstd::string camelCase = Util::demangle(fullName);\n\t\t\tstd::string name = Util::decamel(camelCase);\n\t\t\tthis->type_mapping.insert(std::make_pair(index, name));\n\t\t}\n\n\t\twhile (index >= this->components.size())\n\t\t\tthis->components.push_back(new entity_map());\n\n\t\treturn index;\n\t}\n\n\t/**\n\t* Returns a string view of name of the component corresponding to the given component id\n\t*/\n\t[[nodiscard]] std::string_view getComponentName(const component_type& component) {\n\t\treturn type_mapping.at(component);\n\t}\n\n\t/**\n\t * Returns a string view of the name of the given component\n\t */\n\ttemplate <typename Component>\n\t[[nodiscard]] std::string_view getComponentName() {\n\t\treturn this->type_mapping.at(getComponentIndex<Component>());\n\t}\n\n\t/**\n\t * Initializes the component vector to create an order in the components\n\t */\n\ttemplate <typename Component, typename... Components>\n\tvoid init() {\n\t\tcomponent_type index = getComponentIndex<Component>();\n\n\t\tinit<Components...>();\n\t}\n\n\t/**\n\t * Creates a new entity with an empty parent and adds it to the registry\n\t */\n\t[[nodiscard]] entity_type create(const entity_type& parent = null_entity) noexcept {\n\t\trepresentation_type id;\n\t\tif (this->id_queue.empty()) {\n\t\t\tid = merge(parent, nextID());\n\t\t} else {\n\t\t\tentity_type lastID = this->id_queue.front();\n\n\t\t\tid = merge(parent, lastID);\n\n\t\t\tthis->id_queue.pop();\n\t\t}\n\n\t\tthis->entities.insert(id);\n\n\t\treturn static_cast<entity_type>(id);\n\t}\n\n\t/**\n\t * Removes the given entity from the registry, returns the null entity if the entity is successfully removed\n\t */\n\tentity_type destroy(const entity_type& entity) noexcept {\n\t\tif (entity == null_entity)\n\t\t\treturn null_entity;\n\n\t\tauto entities_iterator = this->entities.find(static_cast<representation_type>(entity));\n\t\tif (entities_iterator != this->entities.end()) {\n\t\t\tthis->entities.erase(entities_iterator);\n\t\t\tid_queue.push(entity);\n\n\t\t\tfor (entity_map* map : this->components) {\n\t\t\t\tauto component_iterator = map->find(entity);\n\t\t\t\tif (component_iterator != map->end()) {\n\t\t\t\t\t// the component's intrusive_ptr will clean up the component\n\t\t\t\t\tmap->erase(component_iterator);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null_entity;\n\t\t}\n\n\t\treturn entity;\n\t}\n\n\t/**\n\t * Instantiates a component using the given type and arguments and adds it to the given entity\n\t */\n\ttemplate <typename Component, typename... Args>\n\tIRef<Component> add(const entity_type& entity, Args&&... args) noexcept {\n\t\tauto entities_iterator = this->entities.find(static_cast<representation_type>(entity));\n\t\tif (entities_iterator == this->entities.end())\n\t\t\treturn IRef<Component>();\n\n\t\tIRef<Component> component = make_intrusive<Component>(std::forward<Args>(args)...);\n\t\tcomponent_type index = getComponentIndex<Component>();\n\n\t\tentity_map* map = this->components[index];\n\t\tauto result = map->insert(std::make_pair(entity, intrusive_cast<RC>(component)));\n\n\t\treturn component;\n\t}\n\n\t/**\n\t * Removes the component with the given component id from the given entity, returns whether the erasure was successful\n\t */\n\tbool remove(const entity_type& entity, const component_type& index) noexcept {\n\t\tif (index >= this->components.size())\n\t\t\treturn false;\n\n\t\tauto entities_iterator = this->entities.find(static_cast<representation_type>(entity));\n\t\tif (entities_iterator == this->entities.end())\n\t\t\treturn false;\n\n\t\tentity_map* map = this->components[index];\n\t\tauto component_iterator = map->find(entity);\n\t\tif (component_iterator == map->end())\n\t\t\treturn false;\n\n\t\tmap->erase(component_iterator);\n\t\t// Todo check if really destroyed\n\n\t\treturn true;\n\t}\n\n\n\t/**\n\t * Removes the component of the given type from the given entity, returns whether the erasure was successful\n\t */\n\ttemplate <typename Component>\n\tbool remove(const entity_type& entity) noexcept {\n\t\tcomponent_type index = getComponentIndex<Component>();\n\n\t\treturn remove(entity, index);\n\t}\n\n\t//-------------------------------------------------------------------------------------//\n\t// Getters                                                                               //\n\t//-------------------------------------------------------------------------------------//\n\n\t/**\n\t * Returns the component of the given type from the given entity, nullptr if no such component exists\n\t */\n\ttemplate <typename Component>\n\t[[nodiscard]] IRef<Component> get(const entity_type& entity) noexcept {\n\t\tif (entity == null_entity)\n\t\t\treturn IRef<Component>();\n\n\t\tauto entities_iterator = this->entities.find(static_cast<representation_type>(entity));\n\t\tif (entities_iterator == this->entities.end())\n\t\t\treturn IRef<Component>();\n\n\t\tcomponent_type index = getComponentIndex<Component>();\n\t\tentity_map* map = this->components[index];\n\t\tauto component_iterator = map->find(entity);\n\t\tif (component_iterator == map->end())\n\t\t\treturn IRef<Component>();\n\n\t\treturn intrusive_cast<Component>(component_iterator->second);\n\t}\n\n\t/**\n\t * Returns the first component of the given type from the given entity, nullptr if no such component exists\n\t */\n\ttemplate <typename Component>\n\t[[nodiscard]] auto getAll(const entity_type& entity) noexcept {\n\t\tauto transform = [](const component_map_iterator& iterator) {\n\t\t\treturn intrusive_cast<Component>(iterator->second);\n\t\t};\n\n\t\tif (entity == null_entity)\n\t\t\treturn transform_view<only<Component>>(component_map_iterator{}, component_map_iterator{}, transform);\n\n\t\tauto entities_iterator = this->entities.find(static_cast<representation_type>(entity));\n\t\tif (entities_iterator == this->entities.end())\n\t\t\treturn transform_view<only<Component>>(component_map_iterator{}, component_map_iterator{}, transform);\n\n\t\tcomponent_type index = getComponentIndex<Component>();\n\t\tentity_map* map = this->components[index];\n\t\tauto component_range = map->equal_range(entity);\n\t\tif (component_range.first == map->end())\n\t\t\treturn transform_view<only<Component>>(component_map_iterator{}, component_map_iterator{}, transform);\n\n\t\tcomponent_map_iterator first(component_range.first);\n\t\tcomponent_map_iterator last(component_range.second);\n\n\t\treturn transform_view<only<Component>>(first, last, transform);\n\t}\n\n\t/**\n\t * Returns the component of the given type from the given entity, or creates one using the provides arguments and returns it.\n\t */\n\ttemplate <typename Component, typename... Args>\n\t[[nodiscard]] IRef<Component> getOrAdd(const entity_type& entity, Args&&... args) {\n\t\tauto entities_iterator = this->entities.find(static_cast<representation_type>(entity));\n\t\tif (entities_iterator == this->entities.end())\n\t\t\treturn IRef<Component>();\n\n\t\tcomponent_type index = getComponentIndex<Component>();;\n\t\tentity_map* map = this->components[index];\n\t\tauto component_iterator = map->find(entity);\n\t\tif (component_iterator == map->end()) {\n\t\t\tIRef<Component> component = make_intrusive<Component>(std::forward<Args>(args)...);\n\n\t\t\tmap->insert(std::make_pair(entity, intrusive_cast<RC>(component)));\n\n\t\t\treturn component;\n\t\t}\n\n\t\treturn intrusive_cast<Component>(component_iterator->second);\n\t}\n\n\t/**\n\t * Returns the component of the given type from the given entity, the default value if no such component exists, note that the component will be copied\n\t */\n\ttemplate <typename Component, typename... Args>\n\t[[nodiscard]] Component getOr(const entity_type& entity, Args&&... args) {\n\t\tIRef<Component> result = get<Component>(entity);\n\t\tif (result == nullptr)\n\t\t\treturn Component(std::forward<Args>(args)...);\n\t\telse\n\t\t\treturn *result;\n\t}\n\n\t/**\n\t * Returns whether the registry contains the given entity\n\t */\n\t[[nodiscard]] bool contains(const entity_type& entity) noexcept {\n\t\treturn this->entities.find(static_cast<representation_type>(entity)) != entities.end();\n\t}\n\n\t/**\n\t * Returns whether the given entity has a component of the given type\n\t */\n\ttemplate <typename Component>\n\t[[nodiscard]] bool has(const entity_type& entity) noexcept {\n\t\treturn count<Component>(entity);\n\t}\n\n\t/**\n\t * Returns whether the given entity has a component with the given component index\n\t */\n\t[[nodiscard]] bool has(const entity_type& entity, const component_type& index) noexcept {\n\t\treturn count(entity, index);\n\t}\n\n\t/**\n\t *  Returns the number of components of the given type\n\t */\n\ttemplate <typename Component>\n\t[[nodiscard]] std::size_t count(const entity_type& entity) noexcept {\n\t\tcomponent_type index = getComponentIndex<Component>();\n\n\t\treturn count(entity, index);\n\t}\n\n\t/**\n\t  *  Returns the number of components with the given component index\n\t  */\n\t[[nodiscard]] std::size_t count(const entity_type& entity, const component_type& index) noexcept {\n\t\tauto entities_iterator = this->entities.find(static_cast<representation_type>(entity));\n\t\tif (entities_iterator == this->entities.end())\n\t\t\treturn 0;\n\n\t\tentity_map* map = this->components[index];\n\t\treturn map->count(entity);\n\t}\n\n\n\t//-------------------------------------------------------------------------------------//\n\t// Parent & self                                                                       //\n\t//-------------------------------------------------------------------------------------//    \n\n\t/**\n\t * Returns the parent of the given entity\n\t */\n\t[[nodiscard]] constexpr entity_type getParent(const representation_type& entity) {\n\t\treturn parent(entity);\n\t}\n\n\t/**\n\t * Returns the parent of the given entity\n\t */\n\t[[nodiscard]] constexpr entity_type getParent(const entity_type& entity) {\n\t\tentity_set_iterator iterator = this->entities.find(static_cast<representation_type>(entity));\n\t\tif (iterator != this->entities.end())\n\t\t\treturn parent(*iterator);\n\n\t\treturn null_entity;\n\t}\n\n\t/**\n\t * Returns the self id of the given entity\n\t */\n\t[[nodiscard]] constexpr entity_type getSelf(const representation_type& entity) {\n\t\treturn self(entity);\n\t}\n\n\t/**\n\t * Returns the self id of the given entity\n\t */\n\t[[nodiscard]] constexpr entity_type getSelf(const entity_type& entity) {\n\t\treturn entity;\n\t}\n\n\t/**\n\t * Sets the parent of the given entity to the given parent, returns true if successful, returns false if the entity does not exist.\n\t */\n\tbool setParent(const entity_type& entity, const entity_type& parent) noexcept {\n\t\tauto entity_iterator = this->entities.find(static_cast<representation_type>(entity));\n\t\tif (entity_iterator == this->entities.end())\n\t\t\treturn false;\n\n\t\tif (parent != null_entity) {\n\t\t\tauto parent_iterator = this->entities.find(parent);\n\t\t\tif (parent_iterator == this->entities.end())\n\t\t\t\treturn false;\n\t\t}\n\n\t\trepresentation_type newEntity = merge(parent, entity);\n\t\tauto hint_iterator = entity_iterator;\n\t\t++hint_iterator;\n\t\tthis->entities.erase(entity_iterator);\n\t\tthis->entities.insert(hint_iterator, newEntity);\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Returns the children of the given parent entity\n\t */\n\t[[nodiscard]] auto getChildren(const entity_type& entity) noexcept {\n\t\tentity_set_iterator first = this->entities.begin();\n\t\tentity_set_iterator last = this->entities.end();\n\n\t\tauto filter = [this, entity](const entity_set_iterator& iterator) {\n\t\t\treturn parent(*iterator) == entity;\n\t\t};\n\n\t\tauto transform = [](const entity_set_iterator& iterator) {\n\t\t\treturn self(*iterator);\n\t\t};\n\n\t\tif (!contains(entity))\n\t\t\treturn filter_transform_view<no_type>(last, last, filter, transform);\n\n\t\treturn filter_transform_view<no_type>(first, last, filter, transform);\n\t}\n\n\t/**\n\t * Returns the children of the given parent entity\n\t */\n\t[[nodiscard]] auto getChildren(const representation_type& entity) noexcept {\n\t\treturn getChildren(self(entity));\n\t}\n\n\n\t//-------------------------------------------------------------------------------------//\n\t// Views                                                                               //\n\t//-------------------------------------------------------------------------------------//\n\n\t/**\n\t * Returns an iterator which iterates over all entities having all the given components\n\t */\nprivate:\n\ttemplate <typename Component>\n\t[[nodiscard]] auto view(type<only<Component>>) noexcept {\n\t\t// Todo make more efficient\n\t\treturn view(type<disj<Component>>{});\n\t}\n\n\ttemplate <typename Component, typename... Components>\n\t[[nodiscard]] auto view(type<conj<Component, Components...>>) noexcept {\n\t\tstatic_assert(unique_types<Component, Components...>);\n\n\t\tstd::vector<component_type> other_components;\n\t\tother_components.reserve(sizeof...(Components));\n\n\t\tcomponent_type smallest_component = getComponentIndex<Component>();\n\t\tstd::size_t smallest_size = this->components[smallest_component]->size();\n\n\t\textract_smallest_component<Components...>(smallest_component, smallest_size, other_components);\n\n\t\tauto filter = [this, other_components](const component_map_iterator& iterator) {\n\t\t\tfor (component_type component : other_components) {\n\t\t\t\tauto component_iterator = this->components[component]->find(iterator->first);\n\t\t\t\tif (component_iterator == this->components[component]->end())\n\t\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn true;\n\t\t};\n\n\t\tauto transform = [](const component_map_iterator& iterator) {\n\t\t\treturn iterator->first;\n\t\t};\n\n\t\tentity_map* map = this->components[smallest_component];\n\t\tcomponent_map_iterator first(map->begin());\n\t\tcomponent_map_iterator last(map->end());\n\t\treturn filter_transform_view<conj<Component, Components...>>(first, last, filter, transform);\n\t}\n\n\t/**\n\t * Returns an iterator which iterates over all entities having any of the given components\n\t */\n\ttemplate <typename... Components>\n\t[[nodiscard]] auto view(type<disj<Components...>>) noexcept {\n\t\tstatic_assert(unique_types<Components...>);\n\t\tentity_set entities;\n\t\tinsert_entities<Components...>(entities);\n\n\t\tauto filter = [entities](const entity_set_iterator& iterator) {\n\t\t\treturn entities.find(*iterator) != entities.end();\n\t\t};\n\n\t\treturn filter_view<disj<Components...>>(this->entities.begin(), this->entities.end(), filter);\n\t}\n\npublic:\n\t/**\n\t * Returns a view which iterates over the components of the given entity\n\t */\n\t[[nodiscard]] auto getComponents(const entity_type& entity) noexcept {\n\t\tcomponent_vector_iterator first = components.begin();\n\t\tcomponent_vector_iterator last = components.end();\n\n\t\tauto filter = [entity](const component_vector_iterator& iterator) {\n\t\t\tentity_map* map = *iterator;\n\n\t\t\treturn map->find(entity) != map->end();\n\t\t};\n\n\t\tauto transform = [this, first, entity](const component_vector_iterator& iterator) {\n\t\t\tentity_map* map = *iterator;\n\t\t\tauto component_range = map->equal_range(entity);\n\n\t\t\tcomponent_map_iterator firstComponent(component_range.first);\n\t\t\tcomponent_map_iterator lastComponent(component_range.second);\n\n\t\t\tauto component_transform = [](const component_map_iterator& iterator) {\n\t\t\t\treturn iterator->second;\n\t\t\t};\n\n\t\t\tauto result = std::make_pair(std::distance(first, iterator), transform_view<no_type>(firstComponent, lastComponent, component_transform));\n\t\t\treturn result;\n\t\t};\n\n\t\treturn filter_transform_view<no_type>(first, last, filter, transform);\n\t}\n\n\t/**\n\t * Returns a view that iterates over all entities which satisfy the given filter\n\t */\n\ttemplate <typename Filter>\n\t[[nodiscard]] auto filter(const Filter& filter) {\n\t\tentity_set_iterator first = this->entities.begin();\n\t\tentity_set_iterator last = this->entities.end();\n\n\t\treturn filter_view<no_type, entity_set_iterator>(first, last, filter);\n\t}\n\n\t/**\n\t * Returns a view that iterates over all entities which satisfy the given filter\n\t */\n\ttemplate <typename Filter>\n\t[[nodiscard]] auto filter() {\n\t\tentity_set_iterator first = this->entities.begin();\n\t\tentity_set_iterator last = this->entities.end();\n\n\t\tauto filter = [this](const entity_set_iterator& iterator) {\n\t\t\treturn !match<Filter>()(*this, *iterator);\n\t\t};\n\n\t\treturn filter_view<no_type, entity_set_iterator>(first, last, filter);\n\t}\n\n\t/**\n\t * Returns a view that iterates over all entities and outputs the transformed entity\n\t */\n\ttemplate <typename Transform>\n\t[[nodiscard]] auto transform(const Transform& transform) {\n\t\tentity_set_iterator first = this->entities.begin();\n\t\tentity_set_iterator last = this->entities.end();\n\n\t\treturn transform_view<no_type, entity_set_iterator>(first, last, transform);\n\t}\n\n\t/**\n\t * Returns a view that iterates over all entities which satisfy the given filter and outputs the transformed entity\n\t */\n\ttemplate <typename Filter, typename Transform>\n\t[[nodiscard]] auto filter_transform(const Filter& filter, const Transform& transform) {\n\t\tentity_set_iterator first = this->entities.begin();\n\t\tentity_set_iterator last = this->entities.end();\n\n\t\treturn filter_transform_view<no_type, entity_set_iterator>(first, last, filter, transform);\n\t}\n\n\t/**\n\t * Returns a view that iterates over all entities which satisfy the given filter and outputs the transformed entity\n\t */\n\ttemplate <typename Filter, typename Transform>\n\t[[nodiscard]] auto filter_transform(const Transform& transform) {\n\t\tentity_set_iterator first = this->entities.begin();\n\t\tentity_set_iterator last = this->entities.end();\n\n\t\tauto filter = [](const entity_set_iterator& iterator) {\n\t\t\treturn !match<Filter>()(*iterator);\n\t\t};\n\n\t\treturn filter_transform_view<no_type, entity_set_iterator>(first, last, filter, transform);\n\t}\n\n\t/**\n\t * Returns an iterator which iterates over all entities which satisfy the view type\n\t */\n\ttemplate <typename... Type>\n\t[[nodiscard]] auto view() noexcept {\n\t\tif constexpr (sizeof...(Type) == 1)\n\t\t\tif constexpr (std::is_base_of_v<RC, Type...>)\n\t\t\t\treturn view(type<only<Type...>>{});\n\t\t\telse\n\t\t\t\treturn view(type<Type...>{});\n\t\telse\n\t\t\treturn view(type<conj<Type...>>{});\n\n\t}\n};\n\ntypedef Registry<std::uint16_t> Registry16;\ntypedef Registry<std::uint32_t> Registry32;\ntypedef Registry<std::uint64_t> Registry64;\n\n};\n"
  },
  {
    "path": "engine/engine.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <VCProjectVersion>15.0</VCProjectVersion>\n    <ProjectGuid>{ADC11C63-6986-41DC-9297-FC5DC58A2B55}</ProjectGuid>\n    <RootNamespace>engine</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup />\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalIncludeDirectories>$(SolutionDir)include;$(SolutionDir)engine;$(SolutionDir);</AdditionalIncludeDirectories>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>core.h</PrecompiledHeaderFile>\n      <PreprocessorDefinitions>_MBCS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n      <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <Lib>\n      <AdditionalLibraryDirectories>$(SolutionDir)lib;$(OutDir)</AdditionalLibraryDirectories>\n      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalIncludeDirectories>$(SolutionDir)include;$(SolutionDir)engine;$(SolutionDir);</AdditionalIncludeDirectories>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <PrecompiledHeaderFile>core.h</PrecompiledHeaderFile>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>\n    </ClCompile>\n    <Lib>\n      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\n    </Lib>\n    <Lib>\n      <AdditionalLibraryDirectories>$(SolutionDir)lib;$(OutDir)</AdditionalLibraryDirectories>\n      <LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <Link>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"core.h\" />\n    <ClInclude Include=\"ecs\\registry.h\" />\n    <ClInclude Include=\"event\\event.h\" />\n    <ClInclude Include=\"event\\keyEvent.h\" />\n    <ClInclude Include=\"event\\mouseEvent.h\" />\n    <ClInclude Include=\"event\\windowEvent.h\" />\n    <ClInclude Include=\"input\\inputHandler.h\" />\n    <ClInclude Include=\"input\\keyboard.h\" />\n    <ClInclude Include=\"input\\modifiers.h\" />\n    <ClInclude Include=\"input\\mouse.h\" />\n    <ClInclude Include=\"io\\export.h\" />\n    <ClInclude Include=\"io\\import.h\" />\n    <ClInclude Include=\"layer\\layer.h\" />\n    <ClInclude Include=\"layer\\layerStack.h\" />\n    <ClInclude Include=\"options\\keyboardOptions.h\" />\n    <ClInclude Include=\"resource\\meshResource.h\" />\n    <ClInclude Include=\"tool\\buttonTool.h\" />\n    <ClInclude Include=\"tool\\stateTool.h\" />\n    <ClInclude Include=\"tool\\tool.h\" />\n    <ClInclude Include=\"tool\\toolManager.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"core.cpp\">\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeaderFile Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">core.h</PrecompiledHeaderFile>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">Create</PrecompiledHeader>\n      <PrecompiledHeaderFile Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">core.h</PrecompiledHeaderFile>\n    </ClCompile>\n    <ClCompile Include=\"input\\inputHandler.cpp\" />\n    <ClCompile Include=\"input\\keyboard.cpp\" />\n    <ClCompile Include=\"input\\modifiers.cpp\" />\n    <ClCompile Include=\"input\\mouse.cpp\" />\n    <ClCompile Include=\"io\\export.cpp\" />\n    <ClCompile Include=\"io\\import.cpp\" />\n    <ClCompile Include=\"layer\\layerStack.cpp\" />\n    <ClCompile Include=\"options\\keyboardOptions.cpp\" />\n    <ClCompile Include=\"resource\\meshResource.cpp\" />\n    <ClCompile Include=\"tool\\toolManager.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "engine/event/event.h",
    "content": "#pragma once\n\n#include <string>\n\nnamespace P3D::Engine {\n\nenum class EventType {\n\tNone = 0,\n\tWindowClose, WindowResize, WindowDrop, FrameBufferResize,\n\tMouseScroll, MouseMove, MouseDrag, MousePress, MouseRelease, MouseExit, MouseEnter,\n\tKeyPress, KeyRelease, KeyDoublePress\n};\n\nenum EventCategory : char {\n\tEventCategoryNone\t\t = 0 << 0,\n\tEventCategoryInput\t\t = 1 << 0,\n\tEventCategoryMouse\t\t = 1 << 1, \n\tEventCategoryMouseButton = 1 << 2, \n\tEventCategoryKeyboard\t = 1 << 3,\n\tEventCategoryWindow\t\t = 1 << 4,\n\tEventCategoryApplication = 1 << 5\n};\n\n#define EVENT_TYPE(type) \\\n\tinline static EventType getStaticType() { return EventType::type; } \\\n\tinline virtual EventType getType() const override { return getStaticType(); } \\\n\tinline virtual std::string getName() const override { return #type; }\n\n#define EVENT_CATEGORY(category) \\\n\tvirtual char getCategory() const override { return category; }\n\nstruct Event {\npublic:\n\tbool handled = false;\n\n\t[[nodiscard]] virtual EventType getType() const = 0;\n\t[[nodiscard]] virtual char getCategory() const = 0;\n\t[[nodiscard]] virtual std::string getName() const = 0;\n\n\t[[nodiscard]] bool inCategory(char category) const {\n\t\treturn (category & getCategory()) != 0;\n\t}\n\n\t[[nodiscard]] bool inCategory(const EventCategory& category) const {\n\t\treturn inCategory(static_cast<char>(category));\n\t}\n};\n\n#define EVENT_BIND(function) \\\n\t[&] (auto& event) -> bool { return function(event); }\n\t\nclass EventDispatcher {\nprivate:\n\tEvent& event;\n\npublic:\n\tEventDispatcher(Event& event) : event(event) {}\n\n\ttemplate<typename T, typename F>\n\tbool dispatch(const F& function) {\n\t\tif (event.getType() == T::getStaticType()) {\n\t\t\tevent.handled = function(static_cast<T&>(event)); \n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n};\n\n};"
  },
  {
    "path": "engine/event/keyEvent.h",
    "content": "#pragma once\n\n#include \"event.h\"\n#include \"../input/keyboard.h\"\n#include \"../input/modifiers.h\"\n\nnamespace P3D::Engine {\n\nclass KeyEvent : public Event {\nprivate:\n\tKey key;\n\tModifiers modifiers;\n\npublic:\n\tEVENT_CATEGORY(EventCategoryInput | EventCategoryKeyboard);\n\n\tinline Key getKey() const {\n\t\treturn key;\n\t}\n\n\tinline Modifiers getModifiers() const {\n\t\treturn modifiers;\n\t}\n\nprotected:\n\tinline KeyEvent(const Key& key, const Modifiers& modifiers) : key(key), modifiers(modifiers) {}\n};\n\nclass DoubleKeyPressEvent : public KeyEvent {\npublic:\n\tEVENT_TYPE(KeyDoublePress);\n\n\tinline DoubleKeyPressEvent(const Key& key, const Modifiers& modifiers) : KeyEvent(key, modifiers) {}\n};\n\nclass KeyPressEvent : public KeyEvent {\nprivate:\n\tbool repeat;\n\npublic:\n\tEVENT_TYPE(KeyPress);\n\n\tinline KeyPressEvent(const Key& key, const Modifiers& modifiers = 0, bool repeat = false) : KeyEvent(key, modifiers), repeat(repeat) {}\n\n\tinline bool isRepeated() const {\n\t\treturn repeat;\n\t}\n};\n\nclass KeyReleaseEvent : public KeyEvent {\npublic:\n\tEVENT_TYPE(KeyRelease);\n\n\tinline KeyReleaseEvent(const Key& key, const Modifiers& modifiers = 0) : KeyEvent(key, modifiers) {}\n};\n\n};"
  },
  {
    "path": "engine/event/mouseEvent.h",
    "content": "#pragma once\n\n#include \"event.h\"\n#include \"../input/mouse.h\"\n#include \"../input/modifiers.h\"\n\nnamespace P3D::Engine {\n\nclass MouseEvent : public Event {\nprivate:\n\tint x;\n\tint y;\n\nprotected:\n\tinline MouseEvent(int x, int y) : x(x), y(y) {};\n\npublic:\n\tEVENT_CATEGORY(EventCategoryMouse | EventCategoryInput);\n\n\t// Returns the x position at the time of the event\n\tinline int getX() const {\n\t\treturn x;\n\t}\n\n\t// Returns the y position at the time of the event\n\tinline int getY() const {\n\t\treturn y;\n\t}\n};\n\nclass MouseMoveEvent : public MouseEvent {\nprivate:\n\tint newX;\n\tint newY;\n\npublic:\n\tEVENT_TYPE(MouseMove);\n\n\tinline MouseMoveEvent(int oldX, int oldY, int newX, int newY) : MouseEvent(oldX, oldY), newX(newX), newY(newY) {}\n\n\tinline int getOldX() const {\n\t\treturn getX();\n\t}\n\n\tinline int getOldY() const {\n\t\treturn getY();\n\t}\n\n\tinline int getNewX() const {\n\t\treturn newX;\n\t}\n\n\tinline int getNewY() const {\n\t\treturn newY;\n\t}\n};\n\nclass MouseScrollEvent : public MouseEvent {\nprivate:\n\tint xOffset;\n\tint yOffset;\n\npublic:\n\tEVENT_TYPE(MouseScroll);\n\n\tinline MouseScrollEvent(int x, int y, int xOffset, int yOffset) : MouseEvent(x, y), xOffset(xOffset), yOffset(yOffset) {}\n\n\tinline int getXOffset() const {\n\t\treturn xOffset;\n\t}\n\n\tinline int getYOffset() const {\n\t\treturn yOffset;\n\t}\n};\n\nclass MouseEnterEvent : public MouseEvent {\npublic:\n\tEVENT_TYPE(MouseEnter);\n\n\tinline MouseEnterEvent(int x, int y) : MouseEvent(x, y) {}\n};\n\nclass MouseExitEvent : public MouseEvent {\npublic:\n\tEVENT_TYPE(MouseExit);\n\n\tinline MouseExitEvent(int x, int y) : MouseEvent(x, y) {}\n};\n\nclass MouseButtonEvent : public MouseEvent {\nprivate:\n\tButton button;\n\tModifiers modifiers;\n\nprotected:\n\tinline MouseButtonEvent(int x, int y, const Button& button, const Modifiers& modifiers = Modifier::NONE) : MouseEvent(x, y), button(button), modifiers(modifiers) {}\n\npublic:\n\tEVENT_CATEGORY(EventCategoryMouse | EventCategoryMouseButton | EventCategoryInput);\n\n\tinline Button getButton() const {\n\t\treturn button;\n\t}\n\n\tinline Modifiers getModifiers() const {\n\t\treturn modifiers;\n\t}\n};\n\nclass MousePressEvent : public MouseButtonEvent {\npublic:\n\tEVENT_TYPE(MousePress);\n\n\tinline MousePressEvent(int x, int y, const Button& button, const Modifiers& modifiers = Modifier::NONE) : MouseButtonEvent(x, y, button, modifiers) {}\n};\n\nclass MouseReleaseEvent : public MouseButtonEvent {\npublic:\n\tEVENT_TYPE(MouseRelease);\n\n\tinline MouseReleaseEvent(int x, int y, const Button& button, const Modifiers& modifiers = Modifier::NONE) : MouseButtonEvent(x, y, button, modifiers) {}\n};\n\nclass MouseDragEvent : public MouseButtonEvent {\nprivate:\n\tint newX;\n\tint newY;\n\npublic:\n\tEVENT_TYPE(MouseDrag);\n\n\tinline MouseDragEvent(int oldX, int oldY, int newX, int newY, const Button& button, const Modifiers& modifiers) : MouseButtonEvent(oldX, oldY, button, modifiers), newX(newX), newY(newY) {}\n\n\tinline int getOldX() const {\n\t\treturn getX();\n\t}\n\n\tinline int getOldY() const {\n\t\treturn getY();\n\t}\n\n\tinline int getNewX() const {\n\t\treturn newX;\n\t}\n\n\tinline int getNewY() const {\n\t\treturn newY;\n\t}\n\n\tinline bool isLeftDragging() const {\n\t\treturn getButton() == Mouse::LEFT;\n\t}\n\n\tinline bool isMiddleDragging() const {\n\t\treturn getButton() == Mouse::MIDDLE;\n\t}\n\n\tinline bool isRightDragging() const {\n\t\treturn getButton() == Mouse::RIGHT;\n\t}\n};\n\n};"
  },
  {
    "path": "engine/event/windowEvent.h",
    "content": "#pragma once\n\n#include \"event.h\"\n\nnamespace P3D::Engine {\n\nclass WindowEvent : public Event {\npublic:\n\tEVENT_CATEGORY(EventCategoryWindow);\n\nprotected:\n\tinline WindowEvent() {};\n};\n\nclass WindowResizeEvent : public WindowEvent {\nprivate:\n\tunsigned int width;\n\tunsigned int height;\n\npublic:\n\tEVENT_TYPE(WindowResize);\n\n\tinline WindowResizeEvent(unsigned int width, unsigned int height) : WindowEvent(), width(width), height(height) {};\n\n\tinline unsigned int getWidth() const {\n\t\treturn width;\n\t}\n\n\tinline unsigned int getHeight() const {\n\t\treturn height;\n\t}\n};\n\nclass WindowCloseEvent : public WindowEvent {\npublic:\n\tEVENT_TYPE(WindowClose);\n\n\tinline WindowCloseEvent() : WindowEvent() {};\n};\n\nclass WindowDropEvent : public WindowEvent {\nprivate:\n\tstd::string path;\n\npublic:\n\tEVENT_TYPE(WindowDrop);\n\n\tinline WindowDropEvent(const std::string& path) : WindowEvent(), path(path) {};\n\n\tinline std::string getPath() const {\n\t\treturn path;\n\t}\n};\n\nclass FrameBufferResizeEvent : public WindowEvent {\nprivate:\n\tunsigned int width;\n\tunsigned int height;\n\npublic:\n\tEVENT_TYPE(FrameBufferResize);\n\n\tinline FrameBufferResizeEvent(unsigned int width, unsigned int height) : WindowEvent(), width(width), height(height) {};\n\n\tinline unsigned int getWidth() const {\n\t\treturn width;\n\t}\n\n\tinline unsigned int getHeight() const {\n\t\treturn height;\n\t}\n};\n\n};"
  },
  {
    "path": "engine/input/inputHandler.cpp",
    "content": "#include \"core.h\"\n\n#include \"inputHandler.h\"\n\n#include \"keyboard.h\"\n#include \"mouse.h\"\n\n#include \"event/event.h\"\n#include \"event/keyEvent.h\"\n#include \"event/mouseEvent.h\"\n#include \"event/windowEvent.h\"\n\nnamespace P3D::Engine {\n\n#pragma region callbacks\n\nvoid InputHandler::keyCallback(int code, int action, int mods) {\n\tKey key = Keyboard::getKey(code);\n\tModifiers modifiers = Modifiers(mods);\n\n\tif (action == Keyboard::KEY_PRESS) {\n\t\tif (keys[key.getCode()] == false && glfwGetTime() - timestamp[key.getCode()] < keyInterval) {\n\t\t\tDoubleKeyPressEvent event(key, mods);\n\t\t\tonEvent(event);\n\t\t}  else {\n\t\t\tKeyPressEvent event(key, mods);\n\t\t\tonEvent(event);\n\t\t}\n\n\t\tkeys[key.getCode()] = true;\n\t\ttimestamp[key.getCode()] = glfwGetTime();\n\t\tanyKey++;\n\t} else if (action == Keyboard::KEY_RELEASE) {\n\t\tkeys[key.getCode()] = false;\n\t\tanyKey--;\n\n\t\tKeyReleaseEvent event(key, mods);\n\t\tonEvent(event);\n\t} else if (action == Keyboard::KEY_REPEAT) {\n\t\tKeyPressEvent event(key, mods, true);\n\t\tonEvent(event);\n\t}\n}\n\nvoid InputHandler::cursorCallback(double x, double y) {\n\tint oldX = static_cast<int>(this->mousePosition.x);\n\tint oldY = static_cast<int>(this->mousePosition.y);\n\tint newX = static_cast<int>(x - viewport.x);\n\tint newY = static_cast<int>(y - viewport.y);\n\n\tMouseMoveEvent event(oldX, oldY, newX, newY);\n\tonEvent(event);\n\n\tif (leftDragging) {\n\t\tMouseDragEvent event(oldX, oldY, newX, newY, Mouse::LEFT, Modifiers(0));\n\t\tonEvent(event);\n\t}\n\n\tif (middleDragging) {\n\t\tMouseDragEvent event(oldX, oldY, newX, newY, Mouse::MIDDLE, Modifiers(0));\n\t\tonEvent(event);\n\t}\n\n\tif (rightDragging) {\n\t\tMouseDragEvent event(oldX, oldY, newX, newY, Mouse::RIGHT, Modifiers(0));\n\t\tonEvent(event);\n\t}\n\n\tthis->mousePosition = Vec2(newX, newY);\n}\n\nvoid InputHandler::cursorEnterCallback(int entered) {\n\tint oldX = static_cast<int>(this->mousePosition.x);\n\tint oldY = static_cast<int>(this->mousePosition.y);\n\n\tif (entered) {\n\t\tMouseEnterEvent event(oldX, oldY);\n\t\tonEvent(event);\n\t} else {\n\t\tleftDragging = false;\n\t\tmiddleDragging = false;\n\t\trightDragging = false;\n\n\t\tMouseExitEvent event(oldX, oldY);\n\t\tonEvent(event);\n\t}\n}\n\nvoid InputHandler::scrollCallback(double xOffset, double yOffset) {\n\tMouseScrollEvent event(static_cast<int>(mousePosition.x), static_cast<int>(mousePosition.y), static_cast<int>(xOffset), static_cast<int>(yOffset));\n\tonEvent(event);\n}\n\nvoid InputHandler::mouseButtonCallback(int button, int action, int mods) {\n\tint oldX = static_cast<int>(this->mousePosition.x);\n\tint oldY = static_cast<int>(this->mousePosition.y);\n\n\tif (action == Mouse::PRESS) {\n\t\tif (Mouse::RIGHT == button) rightDragging = true;\n\t\tif (Mouse::MIDDLE == button) middleDragging = true;\n\t\tif (Mouse::LEFT == button) leftDragging = true;\n\n\t\tMousePressEvent event(oldX, oldY, Mouse::getButton(button), Modifiers(mods));\n\t\tonEvent(event);\n\n\t} else if (action == Mouse::RELEASE) {\n\t\tif (Mouse::RIGHT == button) rightDragging = false;\n\t\tif (Mouse::MIDDLE == button) middleDragging = false;\n\t\tif (Mouse::LEFT == button) leftDragging = false;\n\n\t\tMouseReleaseEvent event(oldX, oldY, Mouse::getButton(button), Modifiers(mods));\n\t\tonEvent(event);\n\t}\n}\n\nvoid InputHandler::windowSizeCallback(int width, int height) {\n\tWindowResizeEvent event(width, height);\n\tonEvent(event);\n}\n\nvoid InputHandler::windowDropCallback(const char* path) {\n\tstd::string stdPath(path);\n\tWindowDropEvent event(stdPath);\n\tonEvent(event);\n}\n\nvoid InputHandler::framebufferSizeCallback(int width, int height) {\n\tFrameBufferResizeEvent event(width, height);\n\tonEvent(event);\n}\n\n#pragma endregion\n\nVec2 InputHandler::getMousePosition() const {\n\tdouble x, y;\n\tglfwGetCursorPos(window, &x, &y);\n\treturn Vec2(x - viewport.x, y - viewport.y);\n}\n\nbool InputHandler::getKey(const Key& key) const {\n\tif (key.getCode() < Keyboard::KEY_FIRST || key.getCode() > Keyboard::KEY_LAST)\n\t\treturn false;\n\n\treturn keys[key.getCode()];\n}\n\nvoid InputHandler::setKey(const Key& key, bool pressed) {\n\tif (key.getCode() < Keyboard::KEY_FIRST || key.getCode() > Keyboard::KEY_LAST)\n\t\treturn;\n\t\n\tkeys[key.getCode()] = pressed;\n}\n\nvoid InputHandler::setCallBacks(GLFWwindow* window) {\n\tglfwSetWindowUserPointer(window, this);\n\n\tglfwSetKeyCallback(window, [] (GLFWwindow* window, int key, int scancode, int action, int mods) {\n\t\tstatic_cast<InputHandler*>(glfwGetWindowUserPointer(window))->keyCallback(key, action, mods);\n\t});\n\n\tglfwSetCursorPosCallback(window, [] (GLFWwindow* window, double x, double y) {\n\t\tstatic_cast<InputHandler*>(glfwGetWindowUserPointer(window))->cursorCallback(x, y);\n\t});\n\n\tglfwSetCursorEnterCallback(window, [] (GLFWwindow* window, int entered) {\n\t\tstatic_cast<InputHandler*>(glfwGetWindowUserPointer(window))->cursorEnterCallback(entered);\n\t});\n\n\tglfwSetScrollCallback(window, [] (GLFWwindow* window, double xOffset, double yOffset) {\n\t\tstatic_cast<InputHandler*>(glfwGetWindowUserPointer(window))->scrollCallback(xOffset, yOffset);\n\t});\n\n\tglfwSetMouseButtonCallback(window, [] (GLFWwindow* window, int button, int action, int mods) {\n\t\tstatic_cast<InputHandler*>(glfwGetWindowUserPointer(window))->mouseButtonCallback(button, action, mods);\n\t});\n\n\tglfwSetWindowSizeCallback(window, [] (GLFWwindow* window, int width, int height) {\n\t\tstatic_cast<InputHandler*>(glfwGetWindowUserPointer(window))->windowSizeCallback(width, height);\n\t});\n\n\tglfwSetFramebufferSizeCallback(window, [] (GLFWwindow* window, int width, int height) {\n\t\tstatic_cast<InputHandler*>(glfwGetWindowUserPointer(window))->framebufferSizeCallback(width, height);\n\t});\n\n\tglfwSetDropCallback(window, [] (GLFWwindow* window, int count, const char** paths) {\n\t\tInputHandler* inputHandler = static_cast<InputHandler*>(glfwGetWindowUserPointer(window));\n\t\tfor (int i = 0; i < count; i++)\n\t\t\tinputHandler->windowDropCallback(paths[i]);\n\t});\n}\n\nInputHandler::InputHandler(GLFWwindow* window) : window(window) {\n\tfor (bool& k : this->keys)\n\t\tk = false;\n\n\tsetCallBacks(window);\n}\n\n};"
  },
  {
    "path": "engine/input/inputHandler.h",
    "content": "#pragma once\n\n#include \"keyboard.h\"\n#include <GLFW/glfw3.h>\n\nnamespace P3D::Engine {\n\nclass Event;\n\nclass InputHandler {\nprivate:\n\tvoid setCallBacks(GLFWwindow* window);\n\nprotected:\n\tGLFWwindow* window;\n\nprivate:\n\tbool modifiers[1];\n\tdouble timestamp[GLFW_KEY_LAST + 1];\n\tvoid keyCallback(int key, int action, int mods);\n\tvoid cursorCallback(double x, double y);\n\tvoid cursorEnterCallback(int entered);\n\tvoid windowDropCallback(const char* path);\n\tvoid scrollCallback(double xOffset, double yOffset);\n\tvoid mouseButtonCallback(int button, int action, int mods);\n\tvoid windowSizeCallback(int width, int height);\n\tvoid framebufferSizeCallback(int width, int height);\n\n\tdouble keyInterval = 0.2;\npublic:\n\tbool keys[GLFW_KEY_LAST + 1];\n\tchar anyKey = 0;\n\n\tbool rightDragging = false;\n\tbool middleDragging = false;\n\tbool leftDragging = false;\n\n\tVec2 mousePosition;\n\tVec4 viewport;\n\n\tInputHandler(GLFWwindow* window);\n\n\tbool getKey(const Key& key) const;\n\tvoid setKey(const Key& key, bool pressed);\n\tVec2 getMousePosition() const;\n\n\tvirtual void onEvent(Event& event) {};\n};\n\n};"
  },
  {
    "path": "engine/input/keyboard.cpp",
    "content": "#include \"core.h\"\n\n#include \"keyboard.h\"\n\n#include <stdexcept>\n\n#include <GLFW/glfw3.h>\n\nnamespace P3D::Engine {\n\nstd::string Key::getName() const {\n\treturn name;\n}\n\nint Key::getCode() const {\n\treturn code;\n}\n\n// Key <-> Key\nbool Key::operator==(const Key& other) const {\n\treturn other.code == code;\n}\n\nbool Key::operator!=(const Key& other) const {\n\treturn other.code != code;\n}\n\nbool Key::operator>=(const Key& other) const {\n\treturn other.code >= code;\n}\n\nbool Key::operator>(const Key& other) const {\n\treturn other.code > code;\n}\n\nbool Key::operator<=(const Key& other) const {\n\treturn other.code <= code;\n}\n\nbool Key::operator<(const Key& other) const {\n\treturn other.code < code;\n}\n\n// Key <-> int\nbool Key::operator==(int other) const {\n\treturn other == code;\n}\n\nbool Key::operator!=(int other) const {\n\treturn other != code;\n}\n\nbool Key::operator>=(int other) const {\n\treturn other >= code;\n}\n\nbool Key::operator>(int other) const {\n\treturn other > code;\n}\n\nbool Key::operator<=(int other) const {\n\treturn other <= code;\n}\n\nbool Key::operator<(int other) const {\n\treturn other < code;\n}\n\n// Key <-> string\nbool Key::operator==(const std::string& other) const {\n\treturn other == name;\n}\n\nbool Key::operator!=(const std::string& other) const {\n\treturn other != name;\n}\n\nnamespace Keyboard {\n\n\tconst Key KEY_UNKNOWN         = { \"none\"           , GLFW_KEY_UNKNOWN       };\n\tconst Key KEY_SPACE           = { \"space\"          , GLFW_KEY_SPACE         };\n\tconst Key KEY_APOSTROPHE      = { \"apostrophe\"     , GLFW_KEY_APOSTROPHE    };\n\tconst Key KEY_COMMA           = { \"comma\"          , GLFW_KEY_COMMA         };\n\tconst Key KEY_MINUS           = { \"minus\"          , GLFW_KEY_MINUS         };\n\tconst Key KEY_PERIOD          = { \"period\"         , GLFW_KEY_PERIOD        };\n\tconst Key KEY_SLASH           = { \"slash\"          , GLFW_KEY_SLASH         };\n\tconst Key KEY_NUMBER_0        = { \"number_0\"       , GLFW_KEY_0             };\n\tconst Key KEY_NUMBER_1        = { \"number_1\"       , GLFW_KEY_1             };\n\tconst Key KEY_NUMBER_2        = { \"number_2\"       , GLFW_KEY_2             };\n\tconst Key KEY_NUMBER_3        = { \"number_3\"       , GLFW_KEY_3             };\n\tconst Key KEY_NUMBER_4        = { \"number_4\"       , GLFW_KEY_4             };\n\tconst Key KEY_NUMBER_5        = { \"number_5\"       , GLFW_KEY_5             };\n\tconst Key KEY_NUMBER_6        = { \"number_6\"       , GLFW_KEY_6             };\n\tconst Key KEY_NUMBER_7        = { \"number_7\"       , GLFW_KEY_7             };\n\tconst Key KEY_NUMBER_8        = { \"number_8\"       , GLFW_KEY_8             };\n\tconst Key KEY_NUMBER_9        = { \"number_9\"       , GLFW_KEY_9             };\n\tconst Key KEY_SEMICOLON       = { \"semicolon\"      , GLFW_KEY_SEMICOLON     };\n\tconst Key KEY_EQUAL           = { \"equal\"          , GLFW_KEY_EQUAL         };\n\tconst Key KEY_A               = { \"a\"              , GLFW_KEY_A             };\n\tconst Key KEY_B               = { \"b\"              , GLFW_KEY_B             };\n\tconst Key KEY_C               = { \"c\"              , GLFW_KEY_C             };\n\tconst Key KEY_D               = { \"d\"              , GLFW_KEY_D             };\n\tconst Key KEY_E               = { \"e\"              , GLFW_KEY_E             };\n\tconst Key KEY_F               = { \"f\"              , GLFW_KEY_F             };\n\tconst Key KEY_G               = { \"g\"              , GLFW_KEY_G             };\n\tconst Key KEY_H               = { \"h\"              , GLFW_KEY_H             };\n\tconst Key KEY_I               = { \"i\"              , GLFW_KEY_I             };\n\tconst Key KEY_J               = { \"j\"              , GLFW_KEY_J             };\n\tconst Key KEY_K               = { \"k\"              , GLFW_KEY_K             };\n\tconst Key KEY_L               = { \"l\"              , GLFW_KEY_L             };\n\tconst Key KEY_M               = { \"m\"              , GLFW_KEY_M             };\n\tconst Key KEY_N               = { \"n\"              , GLFW_KEY_N             };\n\tconst Key KEY_O               = { \"o\"              , GLFW_KEY_O             };\n\tconst Key KEY_P               = { \"p\"              , GLFW_KEY_P             };\n\tconst Key KEY_Q               = { \"q\"              , GLFW_KEY_Q             };\n\tconst Key KEY_R               = { \"r\"              , GLFW_KEY_R             };\n\tconst Key KEY_S               = { \"s\"              , GLFW_KEY_S             };\n\tconst Key KEY_T               = { \"t\"              , GLFW_KEY_T             };\n\tconst Key KEY_U               = { \"u\"              , GLFW_KEY_U             };\n\tconst Key KEY_V               = { \"v\"              , GLFW_KEY_V             };\n\tconst Key KEY_W               = { \"w\"              , GLFW_KEY_W             };\n\tconst Key KEY_X               = { \"x\"              , GLFW_KEY_X             };\n\tconst Key KEY_Y               = { \"y\"              , GLFW_KEY_Y             };\n\tconst Key KEY_Z               = { \"z\"              , GLFW_KEY_Z             };\n\tconst Key KEY_LEFT_BRACKET    = { \"left_bracket\"   , GLFW_KEY_LEFT_BRACKET  };\n\tconst Key KEY_BACKSLASH       = { \"backslash\"      , GLFW_KEY_BACKSLASH     };\n\tconst Key KEY_RIGHT_BRACKET   = { \"right_bracket\"  , GLFW_KEY_RIGHT_BRACKET };\n\tconst Key KEY_GRAVE_ACCENT    = { \"grave_accent\"   , GLFW_KEY_GRAVE_ACCENT  };\n\tconst Key KEY_WORLD_1         = { \"world_1\"        , GLFW_KEY_WORLD_1       };\n\tconst Key KEY_WORLD_2         = { \"world_2\"        , GLFW_KEY_WORLD_2       };\n\tconst Key KEY_ESCAPE          = { \"escape\"         , GLFW_KEY_ESCAPE        };\n\tconst Key KEY_ENTER           = { \"enter\"          , GLFW_KEY_ENTER         };\n\tconst Key KEY_TAB             = { \"tab\"            , GLFW_KEY_TAB           };\n\tconst Key KEY_BACKSPACE       = { \"backspace\"      , GLFW_KEY_BACKSPACE     };\n\tconst Key KEY_INSERT          = { \"insert\"         , GLFW_KEY_INSERT        };\n\tconst Key KEY_DELETE          = { \"delete\"         , GLFW_KEY_DELETE        };\n\tconst Key KEY_RIGHT           = { \"right\"          , GLFW_KEY_RIGHT         };\n\tconst Key KEY_LEFT            = { \"left\"           , GLFW_KEY_LEFT          };\n\tconst Key KEY_DOWN            = { \"down\"           , GLFW_KEY_DOWN          };\n\tconst Key KEY_UP              = { \"up\"             , GLFW_KEY_UP            };\n\tconst Key KEY_PAGE_UP         = { \"page_up\"        , GLFW_KEY_PAGE_UP       };\n\tconst Key KEY_PAGE_DOWN       = { \"page_down\"      , GLFW_KEY_PAGE_DOWN     };\n\tconst Key KEY_HOME            = { \"home\"           , GLFW_KEY_HOME          };\n\tconst Key KEY_END             = { \"end\"            , GLFW_KEY_END           };\n\tconst Key KEY_CAPS_LOCK       = { \"caps_lock\"      , GLFW_KEY_CAPS_LOCK     };\n\tconst Key KEY_SCROLL_LOCK     = { \"scroll_lock\"    , GLFW_KEY_SCROLL_LOCK   };\n\tconst Key KEY_NUM_LOCK        = { \"num_lock\"       , GLFW_KEY_NUM_LOCK      };\n\tconst Key KEY_PRINT_SCREEN    = { \"print_screen\"   , GLFW_KEY_PRINT_SCREEN  };\n\tconst Key KEY_PAUSE           = { \"pause\"          , GLFW_KEY_PAUSE         };\n\tconst Key KEY_F1              = { \"f1\"             , GLFW_KEY_F1            };\n\tconst Key KEY_F2              = { \"f2\"             , GLFW_KEY_F2            };\n\tconst Key KEY_F3              = { \"f3\"             , GLFW_KEY_F3            };\n\tconst Key KEY_F4              = { \"f4\"             , GLFW_KEY_F4            };\n\tconst Key KEY_F5              = { \"f5\"             , GLFW_KEY_F5            };\n\tconst Key KEY_F6              = { \"f6\"             , GLFW_KEY_F6            };\n\tconst Key KEY_F7              = { \"f7\"             , GLFW_KEY_F7            };\n\tconst Key KEY_F8              = { \"f8\"             , GLFW_KEY_F8            };\n\tconst Key KEY_F9              = { \"f9\"             , GLFW_KEY_F9            };\n\tconst Key KEY_F10             = { \"f10\"            , GLFW_KEY_F10           };\n\tconst Key KEY_F11             = { \"f11\"            , GLFW_KEY_F11           };\n\tconst Key KEY_F12             = { \"f12\"            , GLFW_KEY_F12           };\n\tconst Key KEY_F13             = { \"f13\"            , GLFW_KEY_F13           };\n\tconst Key KEY_F14             = { \"f14\"            , GLFW_KEY_F14           };\n\tconst Key KEY_F15             = { \"f15\"            , GLFW_KEY_F15           };\n\tconst Key KEY_F16             = { \"f16\"            , GLFW_KEY_F16           };\n\tconst Key KEY_F17             = { \"f17\"            , GLFW_KEY_F17           };\n\tconst Key KEY_F18             = { \"f18\"            , GLFW_KEY_F18           };\n\tconst Key KEY_F19             = { \"f19\"            , GLFW_KEY_F19           };\n\tconst Key KEY_F20             = { \"f20\"            , GLFW_KEY_F20           };\n\tconst Key KEY_F21             = { \"f21\"            , GLFW_KEY_F21           };\n\tconst Key KEY_F22             = { \"f22\"            , GLFW_KEY_F22           };\n\tconst Key KEY_F23             = { \"f23\"            , GLFW_KEY_F23           };\n\tconst Key KEY_F24             = { \"f24\"            , GLFW_KEY_F24           };\n\tconst Key KEY_F25             = { \"f25\"            , GLFW_KEY_F25           };\n\tconst Key KEY_NUMPAD_0        = { \"numpad_0\"       , GLFW_KEY_KP_0          };\n\tconst Key KEY_NUMPAD_1        = { \"numpad_1\"       , GLFW_KEY_KP_1          };\n\tconst Key KEY_NUMPAD_2        = { \"numpad_2\"       , GLFW_KEY_KP_2          };\n\tconst Key KEY_NUMPAD_3        = { \"numpad_3\"       , GLFW_KEY_KP_3          };\n\tconst Key KEY_NUMPAD_4        = { \"numpad_4\"       , GLFW_KEY_KP_4          };\n\tconst Key KEY_NUMPAD_5        = { \"numpad_5\"       , GLFW_KEY_KP_5          };\n\tconst Key KEY_NUMPAD_6        = { \"numpad_6\"       , GLFW_KEY_KP_6          };\n\tconst Key KEY_NUMPAD_7        = { \"numpad_7\"       , GLFW_KEY_KP_7          };\n\tconst Key KEY_NUMPAD_8        = { \"numpad_8\"       , GLFW_KEY_KP_8          };\n\tconst Key KEY_NUMPAD_9        = { \"numpad_9\"       , GLFW_KEY_KP_9          };\n\tconst Key KEY_NUMPAD_DECIMAL  = { \"numpad_decimal\" , GLFW_KEY_KP_DECIMAL    };\n\tconst Key KEY_NUMPAD_DIVIDE   = { \"numpad_divide\"  , GLFW_KEY_KP_DIVIDE     };\n\tconst Key KEY_NUMPAD_MULTIPLY = { \"numpad_multiply\", GLFW_KEY_KP_MULTIPLY   };\n\tconst Key KEY_NUMPAD_SUBTRACT = { \"numpad_subtract\", GLFW_KEY_KP_SUBTRACT   };\n\tconst Key KEY_NUMPAD_ADD      = { \"numpad_add\"     , GLFW_KEY_KP_ADD        };\n\tconst Key KEY_NUMPAD_ENTER    = { \"numpad_enter\"   , GLFW_KEY_KP_ENTER      };\n\tconst Key KEY_NUMPAD_EQUAL    = { \"numpad_equal\"   , GLFW_KEY_KP_EQUAL      };\n\tconst Key KEY_LEFT_SHIFT      = { \"left_shift\"     , GLFW_KEY_LEFT_SHIFT    };\n\tconst Key KEY_LEFT_CONTROL    = { \"left_control\"   , GLFW_KEY_LEFT_CONTROL  };\n\tconst Key KEY_LEFT_ALT        = { \"left_alt\"       , GLFW_KEY_LEFT_ALT      };\n\tconst Key KEY_LEFT_SUPER      = { \"left_super\"     , GLFW_KEY_LEFT_SUPER    };\n\tconst Key KEY_RIGHT_SHIFT     = { \"rigth_shift\"    , GLFW_KEY_RIGHT_SHIFT   };\n\tconst Key KEY_RIGHT_CONTROL   = { \"right_control\"  , GLFW_KEY_RIGHT_CONTROL };\n\tconst Key KEY_RIGHT_ALT       = { \"right_alt\"      , GLFW_KEY_RIGHT_ALT     };\n\tconst Key KEY_RIGHT_SUPER     = { \"right_super\"    , GLFW_KEY_RIGHT_SUPER   };\n\tconst Key KEY_MENU            = { \"menu\"           , GLFW_KEY_MENU          };\n\n\tconst int KEY_FIRST       = GLFW_KEY_SPACE;\n\tconst int KEY_LAST        = GLFW_KEY_LAST;\n\n\tconst int KEY_PRESS       = GLFW_PRESS;\n\tconst int KEY_RELEASE     = GLFW_RELEASE;\n\tconst int KEY_REPEAT      = GLFW_REPEAT;\n\n\tstd::map<int, Key> keymap = {\n\t\t{ KEY_UNKNOWN.getCode()        , KEY_UNKNOWN         },\n\t\t{ KEY_SPACE.getCode()          , KEY_SPACE           },\n\t\t{ KEY_APOSTROPHE.getCode()     , KEY_APOSTROPHE      },\n\t\t{ KEY_COMMA.getCode()          , KEY_COMMA           },\n\t\t{ KEY_MINUS.getCode()          , KEY_MINUS           },\n\t\t{ KEY_PERIOD.getCode()         , KEY_PERIOD          },\n\t\t{ KEY_SLASH.getCode()          , KEY_SLASH           },\n\t\t{ KEY_NUMBER_0.getCode()       , KEY_NUMBER_0        },\n\t\t{ KEY_NUMBER_1.getCode()       , KEY_NUMBER_1        },\n\t\t{ KEY_NUMBER_2.getCode()       , KEY_NUMBER_2        },\n\t\t{ KEY_NUMBER_3.getCode()       , KEY_NUMBER_3        },\n\t\t{ KEY_NUMBER_4.getCode()       , KEY_NUMBER_4        },\n\t\t{ KEY_NUMBER_5.getCode()       , KEY_NUMBER_5        },\n\t\t{ KEY_NUMBER_6.getCode()       , KEY_NUMBER_6        },\n\t\t{ KEY_NUMBER_7.getCode()       , KEY_NUMBER_7        },\n\t\t{ KEY_NUMBER_8.getCode()       , KEY_NUMBER_8        },\n\t\t{ KEY_NUMBER_9.getCode()       , KEY_NUMBER_9        },\n\t\t{ KEY_SEMICOLON.getCode()      , KEY_SEMICOLON       },\n\t\t{ KEY_A.getCode()              , KEY_A               },\n\t\t{ KEY_B.getCode()              , KEY_B               },\n\t\t{ KEY_C.getCode()              , KEY_C               },\n\t\t{ KEY_D.getCode()              , KEY_D               },\n\t\t{ KEY_E.getCode()              , KEY_E               },\n\t\t{ KEY_F.getCode()              , KEY_F               },\n\t\t{ KEY_G.getCode()              , KEY_G               },\n\t\t{ KEY_H.getCode()              , KEY_H               },\n\t\t{ KEY_I.getCode()              , KEY_I               },\n\t\t{ KEY_J.getCode()              , KEY_J               },\n\t\t{ KEY_K.getCode()              , KEY_K               },\n\t\t{ KEY_L.getCode()              , KEY_L               },\n\t\t{ KEY_M.getCode()              , KEY_M               },\n\t\t{ KEY_N.getCode()              , KEY_N               },\n\t\t{ KEY_O.getCode()              , KEY_O               },\n\t\t{ KEY_P.getCode()              , KEY_P               },\n\t\t{ KEY_Q.getCode()              , KEY_Q               },\n\t\t{ KEY_R.getCode()              , KEY_R               },\n\t\t{ KEY_S.getCode()              , KEY_S               },\n\t\t{ KEY_T.getCode()              , KEY_T               },\n\t\t{ KEY_U.getCode()              , KEY_U               },\n\t\t{ KEY_V.getCode()              , KEY_V               },\n\t\t{ KEY_W.getCode()              , KEY_W               },\n\t\t{ KEY_X.getCode()              , KEY_X               },\n\t\t{ KEY_Y.getCode()              , KEY_Y               },\n\t\t{ KEY_Z.getCode()              , KEY_Z               },\n\t\t{ KEY_LEFT_BRACKET.getCode()   , KEY_LEFT_BRACKET    },\n\t\t{ KEY_BACKSLASH.getCode()      , KEY_BACKSLASH       },\n\t\t{ KEY_RIGHT_BRACKET.getCode()  , KEY_RIGHT_BRACKET   },\n\t\t{ KEY_GRAVE_ACCENT.getCode()   , KEY_GRAVE_ACCENT    },\n\t\t{ KEY_WORLD_1.getCode()        , KEY_WORLD_1         },\n\t\t{ KEY_WORLD_2.getCode()        , KEY_WORLD_2         },\n\t\t{ KEY_ESCAPE.getCode()         , KEY_ESCAPE          },\n\t\t{ KEY_ENTER.getCode()          , KEY_ENTER           },\n\t\t{ KEY_TAB.getCode()            , KEY_TAB             },\n\t\t{ KEY_BACKSPACE.getCode()      , KEY_BACKSPACE       },\n\t\t{ KEY_INSERT.getCode()         , KEY_INSERT          },\n\t\t{ KEY_DELETE.getCode()         , KEY_DELETE          },\n\t\t{ KEY_RIGHT.getCode()          , KEY_RIGHT           },\n\t\t{ KEY_LEFT.getCode()           , KEY_LEFT            },\n\t\t{ KEY_DOWN.getCode()           , KEY_DOWN            },\n\t\t{ KEY_UP.getCode()             , KEY_UP              },\n\t\t{ KEY_PAGE_UP.getCode()        , KEY_PAGE_UP         },\n\t\t{ KEY_PAGE_DOWN.getCode()      , KEY_PAGE_DOWN       },\n\t\t{ KEY_HOME.getCode()           , KEY_HOME            },\n\t\t{ KEY_END.getCode()            , KEY_END             },\n\t\t{ KEY_CAPS_LOCK.getCode()      , KEY_CAPS_LOCK       },\n\t\t{ KEY_SCROLL_LOCK.getCode()    , KEY_SCROLL_LOCK     },\n\t\t{ KEY_NUM_LOCK.getCode()       , KEY_NUM_LOCK        },\n\t\t{ KEY_PRINT_SCREEN.getCode()   , KEY_PRINT_SCREEN    },\n\t\t{ KEY_PAUSE.getCode()          , KEY_PAUSE           },\n\t\t{ KEY_F1.getCode()             , KEY_F1              },\n\t\t{ KEY_F2.getCode()             , KEY_F2              },\n\t\t{ KEY_F3.getCode()             , KEY_F3              },\n\t\t{ KEY_F4.getCode()             , KEY_F4              },\n\t\t{ KEY_F5.getCode()             , KEY_F5              },\n\t\t{ KEY_F6.getCode()             , KEY_F6              },\n\t\t{ KEY_F7.getCode()             , KEY_F7              },\n\t\t{ KEY_F8.getCode()             , KEY_F8              },\n\t\t{ KEY_F9.getCode()             , KEY_F9              },\n\t\t{ KEY_F10.getCode()            , KEY_F10             },\n\t\t{ KEY_F11.getCode()            , KEY_F11             },\n\t\t{ KEY_F12.getCode()            , KEY_F12             },\n\t\t{ KEY_F13.getCode()            , KEY_F13             },\n\t\t{ KEY_F14.getCode()            , KEY_F14             },\n\t\t{ KEY_F15.getCode()            , KEY_F15             },\n\t\t{ KEY_F16.getCode()            , KEY_F16             },\n\t\t{ KEY_F17.getCode()            , KEY_F17             },\n\t\t{ KEY_F18.getCode()            , KEY_F18             },\n\t\t{ KEY_F19.getCode()            , KEY_F19             },\n\t\t{ KEY_F20.getCode()            , KEY_F20             },\n\t\t{ KEY_F21.getCode()            , KEY_F21             },\n\t\t{ KEY_F22.getCode()            , KEY_F22             },\n\t\t{ KEY_F23.getCode()            , KEY_F23             },\n\t\t{ KEY_F24.getCode()            , KEY_F24             },\n\t\t{ KEY_F25.getCode()            , KEY_F25             },\n\t\t{ KEY_NUMPAD_0.getCode()       , KEY_NUMPAD_0        },\n\t\t{ KEY_NUMPAD_1.getCode()       , KEY_NUMPAD_1        },\n\t\t{ KEY_NUMPAD_2.getCode()       , KEY_NUMPAD_2        },\n\t\t{ KEY_NUMPAD_3.getCode()       , KEY_NUMPAD_3        },\n\t\t{ KEY_NUMPAD_4.getCode()       , KEY_NUMPAD_4        },\n\t\t{ KEY_NUMPAD_5.getCode()       , KEY_NUMPAD_5        },\n\t\t{ KEY_NUMPAD_6.getCode()       , KEY_NUMPAD_6        },\n\t\t{ KEY_NUMPAD_7.getCode()       , KEY_NUMPAD_7        },\n\t\t{ KEY_NUMPAD_8.getCode()       , KEY_NUMPAD_8        },\n\t\t{ KEY_NUMPAD_9.getCode()       , KEY_NUMPAD_9        },\n\t\t{ KEY_NUMPAD_DECIMAL.getCode() , KEY_NUMPAD_DECIMAL  },\n\t\t{ KEY_NUMPAD_DIVIDE.getCode()  , KEY_NUMPAD_DIVIDE   },\n\t\t{ KEY_NUMPAD_MULTIPLY.getCode(), KEY_NUMPAD_MULTIPLY },\n\t\t{ KEY_NUMPAD_SUBTRACT.getCode(), KEY_NUMPAD_SUBTRACT },\n\t\t{ KEY_NUMPAD_ADD.getCode()     , KEY_NUMPAD_ADD      },\n\t\t{ KEY_NUMPAD_ENTER.getCode()   , KEY_NUMPAD_ENTER    },\n\t\t{ KEY_NUMPAD_EQUAL.getCode()   , KEY_NUMPAD_EQUAL    },\n\t\t{ KEY_LEFT_SHIFT.getCode()     , KEY_LEFT_SHIFT      },\n\t\t{ KEY_LEFT_CONTROL.getCode()   , KEY_LEFT_CONTROL    },\n\t\t{ KEY_LEFT_ALT.getCode()       , KEY_NUMPAD_SUBTRACT },\n\t\t{ KEY_LEFT_SUPER.getCode()     , KEY_NUMPAD_SUBTRACT },\n\t\t{ KEY_RIGHT_SHIFT.getCode()    , KEY_NUMPAD_SUBTRACT },\n\t\t{ KEY_RIGHT_CONTROL.getCode()  , KEY_NUMPAD_SUBTRACT },\n\t\t{ KEY_RIGHT_ALT.getCode()      , KEY_NUMPAD_SUBTRACT },\n\t\t{ KEY_RIGHT_SUPER.getCode()    , KEY_NUMPAD_SUBTRACT },\n\t\t{ KEY_MENU.getCode()           , KEY_MENU            },\n\t};\n\n\tKey getKey(const std::string& name) {\n\t\tfor (auto key : keymap) {\n\t\t\tif (key.second.getName() == name)\n\t\t\t\treturn key.second;\n\t\t}\n\n\t\treturn KEY_UNKNOWN;\n\t}\n\n\tKey getKey(int code) {\n\t\ttry {\n\t\t\tKey& key = keymap.at(code);\n\t\t\treturn key;\n\t\t} catch (const std::out_of_range&) {\n\t\t\treturn KEY_UNKNOWN;\n\t\t}\n\t}\n\n}\n\n};"
  },
  {
    "path": "engine/input/keyboard.h",
    "content": "#pragma once\n\nnamespace P3D::Engine {\n\nstruct Key {\nprivate:\n\tstd::string name;\n\tint code;\n\npublic:\n\tinline Key(const std::string& name, int code) : name(name), code(code) {}\n\n\tstd::string getName() const;\n\tint getCode() const;\n\n\t// Key <-> Key\n\tbool operator==(const Key& other) const;\n\tbool operator!=(const Key& other) const;\n\tbool operator>=(const Key& other) const;\n\tbool operator>(const Key& other) const;\n\tbool operator<=(const Key& other) const;\n\tbool operator<(const Key& other) const;\n\n\t// Key <-> int\n\tbool operator==(int other) const;\n\tbool operator!=(int other) const;\n\tbool operator>=(int other) const;\n\tbool operator>(int other) const;\n\tbool operator<=(int other) const;\n\tbool operator<(int other) const;\n\n\t// Key <-> string\n\tbool operator==(const std::string& other) const;\n\tbool operator!=(const std::string& other) const;\n};\n\nnamespace Keyboard {\n\n\tKey getKey(const std::string& name);\n\tKey getKey(int code);\n\n\textern const Key KEY_UNKNOWN;\n\textern const Key KEY_SPACE;\n\textern const Key KEY_APOSTROPHE;\n\textern const Key KEY_COMMA;\n\textern const Key KEY_MINUS;\n\textern const Key KEY_PERIOD;\n\textern const Key KEY_SLASH;\n\textern const Key KEY_NUMBER_0;\n\textern const Key KEY_NUMBER_1;\n\textern const Key KEY_NUMBER_2;\n\textern const Key KEY_NUMBER_3;\n\textern const Key KEY_NUMBER_4;\n\textern const Key KEY_NUMBER_5;\n\textern const Key KEY_NUMBER_6;\n\textern const Key KEY_NUMBER_7;\n\textern const Key KEY_NUMBER_8;\n\textern const Key KEY_NUMBER_9;\n\textern const Key KEY_SEMICOLON;\n\textern const Key KEY_EQUAL;\n\textern const Key KEY_A;\n\textern const Key KEY_B;\n\textern const Key KEY_C;\n\textern const Key KEY_D;\n\textern const Key KEY_E;\n\textern const Key KEY_F;\n\textern const Key KEY_G;\n\textern const Key KEY_H;\n\textern const Key KEY_I;\n\textern const Key KEY_J;\n\textern const Key KEY_K;\n\textern const Key KEY_L;\n\textern const Key KEY_M;\n\textern const Key KEY_N;\n\textern const Key KEY_O;\n\textern const Key KEY_P;\n\textern const Key KEY_Q;\n\textern const Key KEY_R;\n\textern const Key KEY_S;\n\textern const Key KEY_T;\n\textern const Key KEY_U;\n\textern const Key KEY_V;\n\textern const Key KEY_W;\n\textern const Key KEY_X;\n\textern const Key KEY_Y;\n\textern const Key KEY_Z;\n\textern const Key KEY_LEFT_BRACKET;\n\textern const Key KEY_BACKSLASH;\n\textern const Key KEY_RIGHT_BRACKET;\n\textern const Key KEY_GRAVE_ACCENT;\n\textern const Key KEY_WORLD_1;\n\textern const Key KEY_WORLD_2;\n\textern const Key KEY_ESCAPE;\n\textern const Key KEY_ENTER;\n\textern const Key KEY_TAB;\n\textern const Key KEY_BACKSPACE;\n\textern const Key KEY_INSERT;\n\textern const Key KEY_DELETE;\n\textern const Key KEY_RIGHT;\n\textern const Key KEY_LEFT;\n\textern const Key KEY_DOWN;\n\textern const Key KEY_UP;\n\textern const Key KEY_PAGE_UP;\n\textern const Key KEY_PAGE_DOWN;\n\textern const Key KEY_HOME;\n\textern const Key KEY_END;\n\textern const Key KEY_CAPS_LOCK;\n\textern const Key KEY_SCROLL_LOCK;\n\textern const Key KEY_NUM_LOCK;\n\textern const Key KEY_PRINT_SCREEN;\n\textern const Key KEY_PAUSE;\n\textern const Key KEY_F1;\n\textern const Key KEY_F2;\n\textern const Key KEY_F3;\n\textern const Key KEY_F4;\n\textern const Key KEY_F5;\n\textern const Key KEY_F6;\n\textern const Key KEY_F7;\n\textern const Key KEY_F8;\n\textern const Key KEY_F9;\n\textern const Key KEY_F10;\n\textern const Key KEY_F11;\n\textern const Key KEY_F12;\n\textern const Key KEY_F13;\n\textern const Key KEY_F14;\n\textern const Key KEY_F15;\n\textern const Key KEY_F16;\n\textern const Key KEY_F17;\n\textern const Key KEY_F18;\n\textern const Key KEY_F19;\n\textern const Key KEY_F20;\n\textern const Key KEY_F21;\n\textern const Key KEY_F22;\n\textern const Key KEY_F23;\n\textern const Key KEY_F24;\n\textern const Key KEY_F25;\n\textern const Key KEY_NUMPAD_0;\n\textern const Key KEY_NUMPAD_1;\n\textern const Key KEY_NUMPAD_2;\n\textern const Key KEY_NUMPAD_3;\n\textern const Key KEY_NUMPAD_4;\n\textern const Key KEY_NUMPAD_5;\n\textern const Key KEY_NUMPAD_6;\n\textern const Key KEY_NUMPAD_7;\n\textern const Key KEY_NUMPAD_8;\n\textern const Key KEY_NUMPAD_9;\n\textern const Key KEY_NUMPAD_DECIMAL;\n\textern const Key KEY_NUMPAD_DIVIDE;\n\textern const Key KEY_NUMPAD_MULTIPLY;\n\textern const Key KEY_NUMPAD_SUBTRACT;\n\textern const Key KEY_NUMPAD_ADD;\n\textern const Key KEY_NUMPAD_ENTER;\n\textern const Key KEY_NUMPAD_EQUAL;\n\textern const Key KEY_LEFT_SHIFT;\n\textern const Key KEY_LEFT_CONTROL;\n\textern const Key KEY_LEFT_ALT;\n\textern const Key KEY_LEFT_SUPER;\n\textern const Key KEY_RIGHT_SHIFT;\n\textern const Key KEY_RIGHT_CONTROL;\n\textern const Key KEY_RIGHT_ALT;\n\textern const Key KEY_RIGHT_SUPER;\n\textern const Key KEY_MENU;\n\n\textern const int KEY_FIRST;\n\textern const int KEY_LAST;\n\textern const int KEY_PRESS;\n\textern const int KEY_RELEASE;\n\textern const int KEY_REPEAT;\n\n}\n\n};"
  },
  {
    "path": "engine/input/modifiers.cpp",
    "content": "#include \"core.h\"\n\n#include <GLFW/glfw3.h>\n\n#include \"modifiers.h\"\n\nnamespace P3D::Engine {\n\t\nint Modifiers::getModifiers() const {\n\treturn modifiers;\n}\n\nbool Modifiers::isCtrlPressed() const {\n\treturn modifiers & Modifier::CTRL;\n}\n\nbool Modifiers::isShiftPressed() const {\n\treturn modifiers & Modifier::SHIFT;\n}\n\nbool Modifiers::isSuperPressed() const {\n\treturn modifiers & Modifier::SUPER;\n}\n\nbool Modifiers::isAltPressed() const {\n\treturn modifiers & Modifier::ALT;\n}\n\nnamespace Modifier {\n\tconst int NONE = 0;\n\tconst int SHIFT = GLFW_MOD_SHIFT;\n\tconst int CTRL = GLFW_MOD_CONTROL;\n\tconst int ALT = GLFW_MOD_ALT;\n\tconst int SUPER = GLFW_MOD_SUPER;\n};\n\n};"
  },
  {
    "path": "engine/input/modifiers.h",
    "content": "#pragma once\n\nnamespace P3D::Engine {\n\t\nnamespace Modifier {\n\textern const int NONE;\n\textern const int SHIFT;\n\textern const int CTRL;\n\textern const int ALT;\n\textern const int SUPER;\n};\n\nstruct Modifiers {\nprivate:\n\tint modifiers;\n\npublic:\n\tinline Modifiers(int modifiers) : modifiers(modifiers) {}\n\n\tint getModifiers() const;\n\tbool isCtrlPressed() const;\n\tbool isShiftPressed() const;\n\tbool isSuperPressed() const;\n\tbool isAltPressed() const;\n};\n\n};"
  },
  {
    "path": "engine/input/mouse.cpp",
    "content": "#include \"core.h\"\n\n#include \"mouse.h\"\n\n#include <stdexcept>\n\n#include <GLFW/glfw3.h>\n\nnamespace P3D::Engine {\n\nstd::string Button::getName() const {\n\treturn name;\n}\n\nint Button::getCode() const {\n\treturn code;\n}\n\n// Button <-> Button\nbool Button::operator==(const Button& other) const {\n\treturn other.code == code;\n}\n\nbool Button::operator!=(const Button& other) const {\n\treturn other.code != code;\n}\n\n// Key <-> int\nbool Button::operator==(int other) const {\n\treturn other == code;\n}\n\nbool Button::operator!=(int other) const {\n\treturn other != code;\n}\n\n// Key <-> string\nbool Button::operator==(const std::string& other) const {\n\treturn other == name;\n}\n\nbool Button::operator!=(const std::string& other) const {\n\treturn other != name;\n}\n\nnamespace Mouse {\n\n\tconst Button UNKNOWN = { \"none\"        , -1                       };\n\tconst Button LEFT    = { \"mouse_left\"  , GLFW_MOUSE_BUTTON_LEFT   };\n\tconst Button RIGHT   = {\"mouse_right\"  , GLFW_MOUSE_BUTTON_RIGHT  };\n\tconst Button MIDDLE  = { \"mouse_middle\", GLFW_MOUSE_BUTTON_MIDDLE };\n\tconst Button MOUSE_4 = { \"mouse_4\"     , GLFW_MOUSE_BUTTON_4      };\n\tconst Button MOUSE_5 = { \"mouse_5\"     , GLFW_MOUSE_BUTTON_5      };\n\tconst Button MOUSE_6 = { \"mouse_6\"     , GLFW_MOUSE_BUTTON_6      };\n\tconst Button MOUSE_7 = { \"mouse_7\"     , GLFW_MOUSE_BUTTON_7      };\n\tconst Button MOUSE_8 = { \"mouse_8\"     , GLFW_MOUSE_BUTTON_8      };\n\n\tconst int MOUSE_FIRST = GLFW_MOUSE_BUTTON_LAST;\n\tconst int MOUSE_LAST = GLFW_MOUSE_BUTTON_LEFT;\n\n\tconst int PRESS = GLFW_PRESS;\n\tconst int RELEASE = GLFW_RELEASE;\n\tconst int REPEAT = GLFW_REPEAT;\n\n\tstd::map<int, Button> buttonmap = {\n\t\t{ UNKNOWN.getCode(), UNKNOWN },\n\t\t{ LEFT.getCode()   , LEFT    },\n\t\t{ RIGHT.getCode()  , RIGHT   },\n\t\t{ MIDDLE.getCode() , MIDDLE  },\n\t\t{ MOUSE_4.getCode(), MOUSE_4 },\n\t\t{ MOUSE_5.getCode(), MOUSE_5 },\n\t\t{ MOUSE_6.getCode(), MOUSE_6 },\n\t\t{ MOUSE_7.getCode(), MOUSE_7 },\n\t\t{ MOUSE_8.getCode(), MOUSE_8 }\n\t};\n\n\tButton getButton(std::string name) {\n\t\tfor (auto& button : buttonmap) {\n\t\t\tif (button.second.getName() == name)\n\t\t\t\treturn button.second;\n\t\t}\n\n\t\tthrow \"Unreachable\";\n\t}\n\n\tButton getButton(int code) {\n\t\ttry {\n\t\t\tButton& key = buttonmap.at(code);\n\t\t\treturn key;\n\t\t} catch (const std::out_of_range&) {\n\t\t\treturn UNKNOWN;\n\t\t}\n\t}\n}\n\n};"
  },
  {
    "path": "engine/input/mouse.h",
    "content": "#pragma once\n\nnamespace P3D::Engine {\n\nstruct Button {\nprivate:\n\tstd::string name;\n\tint code;\n\npublic:\n\tinline Button(const std::string& name, int code) : name(name), code(code) {}\n\n\tstd::string getName() const;\n\tint getCode() const;\n\n\t// Button <-> Button\n\tbool operator==(const Button& other) const;\n\tbool operator!=(const Button& other) const;\n\n\t// Key <-> int\n\tbool operator==(int other) const;\n\tbool operator!=(int other) const;\n\n\t// Key <-> string\n\tbool operator==(const std::string& other) const;\n\tbool operator!=(const std::string& other) const;\n};\n\t\t\t\t\t\t\t \nnamespace Mouse {\n\n\tButton getButton(std::string name);\n\tButton getButton(int code);\n\n\textern const Button LEFT;\n\textern const Button RIGHT;\n\textern const Button MIDDLE;\n\textern const Button MOUSE_4;\n\textern const Button MOUSE_5;\n\textern const Button MOUSE_6;\n\textern const Button MOUSE_7;\n\textern const Button MOUSE_8;\n\n\textern const int MOUSE_FIRST;\n\textern const int MOUSE_LAST;\n\t\n\textern const int PRESS;\n\textern const int RELEASE;\n\textern const int REPEAT;\n\n};\n\n};"
  },
  {
    "path": "engine/io/export.cpp",
    "content": "#include \"core.h\"\n\n#include \"export.h\"\n\n#include \"../graphics/extendedTriangleMesh.h\"\n\n#include <fstream>\n#include <sstream>\n\n#include \"../util/fileUtils.h\"\n\nnamespace P3D {\n\n/*\n\tExport\n*/\n\ntemplate<typename T>\nvoid Export::write(std::ostream& output, T const* buffer, int size) {\n\tfor (int i = 0; i < size; i++) {\n\t\toutput.write((T*) (buffer + i * sizeof(T)), 1);\n\t}\n}\n\ntemplate<typename T>\nvoid Export::write(std::ostream& output, const T& value) {\n\tchar const* v = reinterpret_cast<char const*>(&value);\n\twrite<char>(output, v, sizeof(T));\n}\n\nstd::string Export::str(Vec3 vector) {\n\tstd::stringstream ss;\n\tss << vector.x << \" \" << vector.y << \" \" << vector.z;\n\treturn ss.str();\n}\n\nstd::string Export::str(Vec4 vector) {\n\tstd::stringstream ss;\n\tss << vector.x << \" \" << vector.y << \" \" << vector.z << \" \" << vector.w;\n\treturn ss.str();\n}\n\nstd::string Export::str(Mat3 matrix) {\n\tstd::stringstream ss;\n\n\tdouble data[9];\n\tmatrix.toColMajorData(data);\n\n\tss << data[0];\n\tfor (int i = 1; i < 9; i++) {\n\t\tss << ' ' << data[i];\n\t}\n\n\treturn ss.str();\n}\n\nstd::string Export::str(Position pos) {\n\tstd::stringstream ss;\n\tss << pos.x.value << \" \" << pos.y.value << \" \" << pos.z.value;\n\treturn ss.str();\n}\n\nstd::string Export::str(DiagonalMat3 matrix) {\n\treturn Export::str(Vec3(matrix[0], matrix[1], matrix[2]));\n}\n\nstd::string Export::str(int num) {\n\treturn std::to_string(num);\n}\n\nstd::string Export::str(double num) {\n\treturn std::to_string(num);\n}\n\n/*\n\tEnd of Export\n*/\n\n/*\n\tOBJExport\n*/\n\nvoid saveBinaryObj(std::string filename, const Graphics::ExtendedTriangleMesh& shape) {\n\tUtil::warnIfFileExists(filename);\n\n\tstd::ofstream output;\n\toutput.open(filename, std::ios::binary | std::ios::out);\n\n\tenum : char {\n\t\tV,\n\t\tVN,\n\t\tVT,\n\t\tVNT\n\t};\n\n\tchar flag = V;\n\tif (shape.uvs != nullptr && shape.normals != nullptr) {\n\t\tflag = VNT;\n\t} else if (shape.uvs != nullptr) {\n\t\tflag = VT;\n\t} else if (shape.normals != nullptr) {\n\t\tflag = VN;\n\t}\n\n\tExport::write<char>(output, flag);\n\tExport::write<const int>(output, shape.vertexCount);\n\tExport::write<const int>(output, shape.triangleCount);\n\n\tfor (Vec3f vertex : shape.iterVertices()) {\n\t\tExport::write<Vec3f>(output, vertex);\n\t}\n\n\tif (shape.normals != nullptr) {\n\t\tfor (int i = 0; i < shape.vertexCount; i++) {\n\t\t\tVec3f normal = shape.normals.get()[i];\n\t\t\tExport::write<Vec3f>(output, normal);\n\t\t}\n\t}\n\n\tif (shape.uvs != nullptr) {\n\t\tfor (int i = 0; i < shape.vertexCount; i++) {\n\t\t\tVec2f uv = shape.uvs.get()[i];\n\t\t\tExport::write<Vec2f>(output, uv);\n\t\t}\n\t}\n\n\tfor (Triangle triangle : shape.iterTriangles()) {\n\t\tfor (int index : triangle.indexes) {\n\t\t\tExport::write<int>(output, index);\n\t\t}\n\t}\n\n\toutput.close();\n}\n\nvoid saveNonBinaryObj(const std::string& filename, const Graphics::ExtendedTriangleMesh& shape) {\n\tUtil::warnIfFileExists(filename);\n\n\tstd::ofstream output;\n\toutput.open(filename);\n\n\tfor (Vec3f vertex : shape.iterVertices()) {\n\t\toutput << \"v \" << vertex.x << \" \" << vertex.y << \" \" << vertex.z << std::endl;\n\t}\n\n\tif (shape.normals != nullptr) {\n\t\tfor (int i = 0; i < shape.vertexCount; i++) {\n\t\t\tVec3 normal = shape.normals.get()[i];\n\t\t\toutput << \"vn \" << normal.x << \" \" << normal.y << \" \" << normal.z << std::endl;\n\t\t}\n\t}\n\n\tif (shape.uvs != nullptr) {\n\t\tfor (int i = 0; i < shape.vertexCount; i++) {\n\t\t\tVec2 uv = shape.uvs.get()[i];\n\t\t\toutput << \"vt \" << uv.x << \" \" << uv.y << std::endl;\n\t\t}\n\t}\n\n\tfor (Triangle triangle : shape.iterTriangles()) {\n\t\toutput << \"f\";\n\n\t\tfor (int index : triangle.indexes) {\n\t\t\tindex++;\n\t\t\tif (shape.normals != nullptr && shape.uvs != nullptr) {\n\t\t\t\toutput << \" \" << index << \"/\" << index << \"/\" << index;\n\t\t\t} else if (shape.uvs != nullptr) {\n\t\t\t\toutput << \" \" << index << \"//\" << index;\n\t\t\t} else if (shape.normals != nullptr) {\n\t\t\t\toutput << \" \" << index << \"/\" << index;\n\t\t\t} else {\n\t\t\t\toutput << \" \" << index;\n\t\t\t}\n\t\t}\n\n\t\toutput << std::endl;\n\t}\n\n\toutput.close();\n}\n\nvoid OBJExport::save(const std::string& filename, const Graphics::ExtendedTriangleMesh& shape, bool binary) {\n\tif (binary)\n\t\tsaveBinaryObj(filename, shape);\n\telse\n\t\tsaveNonBinaryObj(filename, shape);\n}\n\n/*\n\tEnd of OBJExport\n*/\n\n};"
  },
  {
    "path": "engine/io/export.h",
    "content": "#pragma once\n\nnamespace P3D::Graphics {\nstruct ExtendedTriangleMesh;\n};\n\nnamespace P3D {\n\nnamespace Export {\n\ttemplate<typename T>\n\tvoid write(std::ostream& output, T const * buffer, int size);\n\n\ttemplate<typename T>\n\tvoid write(std::ostream& output, const T& value);\n\n\tstd::string str(Vec4 vector);\n\tstd::string str(Vec3 vector);\n\tstd::string str(Position pos);\n\tstd::string str(Mat3 matrix);\n\tstd::string str(DiagonalMat3 matrix);\n\tstd::string str(int num);\n\tstd::string str(double num);\n};\n\nnamespace OBJExport {\n\tvoid save(const std::string& file, const Graphics::ExtendedTriangleMesh&, bool binary = false);\n};\n\n};"
  },
  {
    "path": "engine/io/import.cpp",
    "content": "#include \"core.h\"\n\n#include \"import.h\"\n\n#include <fstream>\n#include <optional>\n\n#include \"../util/stringUtil.h\"\n#include <Physics3D/physical.h>\n#include \"../graphics/extendedTriangleMesh.h\"\n\nnamespace P3D {\n\n/*\n\tImport\n*/\n\nint Import::parseInt(const std::string& num) {\n\treturn std::stoi(num);\n}\n\nlong long Import::parseLong(const std::string& num) {\n\treturn std::stoll(num);\n}\n\nFix<32> Import::parseFix(const std::string& num) {\n\tlong long v = std::stoll(num);\n\treturn Fix<32>(static_cast<int64_t>(v));\n}\n\ndouble Import::parseDouble(const std::string& num) {\n\treturn std::stod(num);\n}\n\nfloat Import::parseFloat(const std::string& num) {\n\treturn std::stof(num);\n}\n\nVec3 Import::parseVec3(const std::string& vec) {\n\tstd::vector<std::string> tokens = Util::split(vec, ' ');\n\tVec3 vector = Vec3();\n\tfor (int i = 0; i < 3; i++)\n\t\tvector[i] = Import::parseDouble(tokens[i]);\n\t\n\treturn vector;\n}\n\nPosition Import::parsePosition(const std::string& vec) {\n\tstd::vector<std::string> tokens = Util::split(vec, ' ');\n\treturn Position(Import::parseFix(tokens[0]), Import::parseFix(tokens[1]), Import::parseFix(tokens[2]));\n}\n\nVec4 Import::parseVec4(const std::string& vec) {\n\tstd::vector<std::string> tokens = Util::split(vec, ' ');\n\tVec4 vector;\n\tfor (int i = 0; i < 4; i++)\n\t\tvector[i] = Import::parseDouble(tokens[i]);\n\t\n\treturn vector;\n}\n\nVec4f Import::parseVec4f(const std::string& vec) {\n\tstd::vector<std::string> tokens = Util::split(vec, ' ');\n\tVec4f vector;\n\tfor (int i = 0; i < 4; i++)\n\t\tvector[i] = Import::parseFloat(tokens[i]);\n\t\n\treturn vector;\n}\n\nVec3f Import::parseVec3f(const std::string& vec) {\n\tstd::vector<std::string> tokens = Util::split(vec, ' ');\n\tVec3f vector = Vec3f();\n\tfor (int i = 0; i < 3; i++)\n\t\tvector[i] = Import::parseFloat(tokens[i]);\n\t\n\treturn vector;\n}\n\nDiagonalMat3 Import::parseDiagonalMat3(const std::string& mat) {\n\tstd::vector<std::string> tokens = Util::split(mat, ' ');\n\tDiagonalMat3 matrix = DiagonalMat3();\n\tfor (int i = 0; i < 3; i++)\n\t\tmatrix[i] = Import::parseDouble(tokens[i]);\n\t\n\treturn matrix;\n}\n\nMat3 Import::parseMat3(const std::string& mat) {\n\tstd::vector<std::string> tokens = Util::split(mat, ' ');\n\tdouble data[9];\n\n\tfor (int i = 0; i < 9; i++)\n\t\tdata[i] = Import::parseDouble(tokens[i]);\n\n\treturn Matrix<double, 3, 3>::fromColMajorData(data);\n}\n\ntemplate<typename T>\nT Import::read(std::istream& input) {\n\tchar * buffer = (char*) alloca(sizeof(T));\n\tinput.read(buffer, sizeof(T));\n\treturn *reinterpret_cast<T*>(buffer);\n}\n\n/*\n\tEnd of Import\n*/\n\n\n\n/*\n\tOBJImport\n*/\n\nstruct Vertex {\n\tint position;\n\tstd::optional<int> normal;\n\tstd::optional<int> uv;\n\n\tVertex() : position(0), normal(std::nullopt), uv(std::nullopt) {}\n\n\tVertex(const std::string_view& line) {\n\t\tstd::vector<std::string_view> tokens = Util::split_view(line, '/');\n\t\tsize_t length = tokens.size();\n\n\t\t// Positions\n\t\tposition = std::stoi(std::string(tokens[0])) - 1;\n\n\t\t// Uvs\n\t\tif (length > 1 && !tokens[1].empty())\n\t\t\tuv = std::stoi(std::string(tokens[1])) - 1;\n\n\t\t// Normals\n\t\tif (length > 2 && !tokens[2].empty())\n\t\t\tnormal = std::stoi(std::string(tokens[2])) - 1;\n\t}\n\n\tbool operator==(const Vertex& other) const {\n\t\treturn position == other.position && normal == other.normal && uv == other.uv;\n\t}\n};\n\nstruct VertexHasher {\n\tsize_t operator()(const P3D::Vertex& vertex) const {\n\n\t\tsize_t result = std::hash<int>()(vertex.position);\n\n\t\tif (vertex.normal.has_value())\n\t\t\tresult = result >> 1 ^ std::hash<int>()(vertex.normal.value()) << 1;\n\n\t\tif (vertex.uv.has_value())\n\t\t\tresult = result >> 1 ^ std::hash<int>()(vertex.uv.value()) << 1;\n\n\t\treturn result;\n\t}\n};\n\nstruct Face {\n\tVertex vertices[3];\n\n\tFace(const Vertex& v1, const Vertex& v2, const Vertex& v3) {\n\t\tvertices[0] = v1;\n\t\tvertices[1] = v2;\n\t\tvertices[2] = v3;\n\t}\n\n\tVertex& operator[](std::size_t index) {\n\t\tassert(index < 3);\n\n\t\treturn vertices[index];\n\t}\n\n\tconst Vertex& operator[](int index) const {\n\t\tassert(index < 3);\n\n\t\treturn vertices[index];\n\t}\n};\n\nGraphics::ExtendedTriangleMesh reorderWithoutSharedVerticesSupport(const std::vector<Vec3f>& positions, const std::vector<Vec3f>& normals, const std::vector<Vec2f>& uvs, const std::vector<Face>& faces) {\n\t// Positions\n\tVec3f* positionArray = new Vec3f[positions.size()];\n\tfor (std::size_t i = 0; i < positions.size(); i++)\n\t\tpositionArray[i] = positions[i];\n\n\t// Normals\n\tVec3f* normalArray = nullptr;\n\tif (!normals.empty())\n\t\tnormalArray = new Vec3f[positions.size()];\n\n\t// UVs, tangents and bitangents\n\tVec2f* uvArray = nullptr;\n\tVec3f* tangentArray = nullptr;\n\tVec3f* bitangentArray = nullptr;\n\tif (!uvs.empty()) {\n\t\tuvArray = new Vec2f[positions.size()];\n\t\ttangentArray = new Vec3f[positions.size()];\n\t\tbitangentArray = new Vec3f[positions.size()];\n\t}\n\n\t// Triangles\n\tTriangle* triangleArray = new Triangle[faces.size()];\n\tfor (std::size_t faceIndex = 0; faceIndex < faces.size(); faceIndex++) {\n\t\tconst Face& face = faces[faceIndex];\n\n\t\t// Save triangle\n\t\ttriangleArray[faceIndex] = Triangle { face.vertices[0].position, face.vertices[1].position, face.vertices[2].position };\n\n\t\t// Calculate tangent and bitangent\n\t\tVec3f tangent;\n\t\tVec3f bitangent;\n\t\tif (uvArray) {\n\t\t\tVec3f edge1 = positions[face.vertices[1].position] - positions[face.vertices[0].position];\n\t\t\tVec3f edge2 = positions[face.vertices[2].position] - positions[face.vertices[0].position];\n\t\t\tVec2f dUV1 = uvs[*face.vertices[1].uv] - uvs[*face.vertices[0].uv];\n\t\t\tVec2f dUV2 = uvs[*face.vertices[2].uv] - uvs[*face.vertices[0].uv];\n\n\t\t\tfloat f = 1.0f / (dUV1.x * dUV2.y - dUV2.x * dUV1.y);\n\n\t\t\ttangent.x = f * (dUV2.y * edge1.x - dUV1.y * edge2.x);\n\t\t\ttangent.y = f * (dUV2.y * edge1.y - dUV1.y * edge2.y);\n\t\t\ttangent.z = f * (dUV2.y * edge1.z - dUV1.y * edge2.z);\n\t\t\ttangent = normalize(tangent);\n\n\t\t\tbitangent.x = f * (-dUV2.x * edge1.x + dUV1.x * edge2.x);\n\t\t\tbitangent.y = f * (-dUV2.x * edge1.y + dUV1.x * edge2.y);\n\t\t\tbitangent.z = f * (-dUV2.x * edge1.z + dUV1.x * edge2.z);\n\t\t\tbitangent = normalize(bitangent);\n\t\t}\n\n\t\tfor (int vertexIndex = 0; vertexIndex < 3; vertexIndex++) {\n\t\t\tconst Vertex& vertex = face[vertexIndex];\n\n\t\t\t// Save normal\n\t\t\tif (normalArray && vertex.normal.has_value())\n\t\t\t\tnormalArray[vertex.position] = normals[*vertex.normal];\n\n\t\t\t// Save uv, tangent and bitangent\n\t\t\tif (uvArray && vertex.uv.has_value()) {\n\t\t\t\tuvArray[vertex.position] = uvs[*vertex.uv];\n\t\t\t\ttangentArray[vertex.position] = tangent;\n\t\t\t\tbitangentArray[vertex.position] = bitangent;\n\t\t\t}\n\t\t}\n\t}\n\n\tGraphics::ExtendedTriangleMesh result(positionArray, static_cast<int>(positions.size()), triangleArray, static_cast<int>(faces.size()));\n\tresult.setNormalBuffer(SRef<const Vec3f[]>(normalArray));\n\tresult.setUVBuffer(SRef<const Vec2f[]>(uvArray));\n\tresult.setTangentBuffer(SRef<const Vec3f[]>(tangentArray));\n\tresult.setBitangentBuffer(SRef<const Vec3f[]>(bitangentArray));\n\n\treturn result;\n}\n\nGraphics::ExtendedTriangleMesh reorderWithSharedVerticesSupport(const std::vector<Vec3f>& positions, const std::vector<Vec3f>& normals, const std::vector<Vec2f>& uvs, const std::vector<Face>& faces) {\n\tstd::unordered_map<Vertex, int, VertexHasher> mapping;\n\n\t// Get index of each vertex - uv - normal tuple\n\tauto getIndex = [&mapping] (const Vertex& vertex) -> int {\n\t\tauto iterator = mapping.find(vertex);\n\t\tif (iterator == mapping.end()) {\n\t\t\tint index = static_cast<int>(mapping.size());\n\t\t\tmapping.emplace(vertex, index);\n\n\t\t\treturn index;\n\t\t}\n\n\t\treturn iterator->second;\n\t};\n\n\t// Fill triangle array\n\tTriangle* triangleArray = new Triangle[faces.size()];\n\tfor (std::size_t faceIndex = 0; faceIndex < faces.size(); faceIndex++) {\n\t\tconst Face& face = faces[faceIndex];\n\n\t\tconst Vertex& v0 = face.vertices[0];\n\t\tconst Vertex& v1 = face.vertices[1];\n\t\tconst Vertex& v2 = face.vertices[2];\n\n\t\tint i0 = getIndex(v0);\n\t\tint i1 = getIndex(v1);\n\t\tint i2 = getIndex(v2);\n\n\t\t// Save triangle\n\t\ttriangleArray[faceIndex] = Triangle { i0, i1, i2 };\n\t}\n\n\t// Array size\n\tstd::size_t size = mapping.size();\n\n\t// Positions\n\tVec3f* positionArray = new Vec3f[size];\n\n\t// Normals\n\tVec3f* normalArray = nullptr;\n\tif (!normals.empty())\n\t\tnormalArray = new Vec3f[size];\n\n\t// UV\n\tVec2f* uvArray = nullptr;\n\tif (!uvs.empty()) \n\t\tuvArray = new Vec2f[size];\n\n\t// Fill arrays\n\tfor (const auto& [vertex, index] : mapping) {\n\t\t// Store position\n\t\tpositionArray[index] = positions[vertex.position];\n\t\t\n\t\t// Store normal\n\t\tif (normalArray && vertex.normal.has_value())\n\t\t\tnormalArray[index] = normals[*vertex.normal];\n\n\t\t// Store uv\n\t\tif (uvArray && vertex.uv.has_value()) \n\t\t\tuvArray[index] = uvs[*vertex.uv];\n\t}\n\n\tGraphics::ExtendedTriangleMesh result(positionArray, size, triangleArray, static_cast<int>(faces.size()));\n\tresult.setNormalBuffer(SRef<const Vec3f[]>(normalArray));\n\tresult.setUVBuffer(SRef<const Vec2f[]>(uvArray));\n\n\treturn result;\n}\n\nGraphics::ExtendedTriangleMesh loadBinaryObj(std::istream& input) {\n\tchar flag = Import::read<char>(input);\n\tint vertexCount = Import::read<int>(input);\n\tint triangleCount = Import::read<int>(input);\n\n\tchar V = 0;\n\tchar VN = 1;\n\tchar VT = 2;\n\tchar VNT = 3;\n\n\tVec3f* vertices = new Vec3f[vertexCount];\n\tfor (int i = 0; i < vertexCount; i++) {\n\t\tVec3 vertex = Import::read<Vec3f>(input);\n\n\t\tvertices[i] = vertex;\n\t}\n\n\tVec3f* normals = nullptr;\n\tif (flag == VN || flag == VNT) {\n\t\tnormals = new Vec3f[vertexCount];\n\n\t\tfor (int i = 0; i < vertexCount; i++) {\n\t\t\tnormals[i] = Import::read<Vec3f>(input);\n\t\t}\n\t}\n\n\tVec2f* uvs = nullptr;\n\tVec3f* tangents = nullptr;\n\tVec3f* bitangents = nullptr;\n\tif (flag == VT || flag == VNT) {\n\t\tuvs = new Vec2f[vertexCount];\n\t\ttangents = new Vec3f[vertexCount];\n\t\tbitangents = new Vec3f[vertexCount];\n\n\t\tfor (int i = 0; i < vertexCount; i++) {\n\t\t\tuvs[i] = Import::read<Vec2f>(input);\n\t\t}\n\t}\n\n\tTriangle* triangles = new Triangle[triangleCount];\n\tfor (int i = 0; i < triangleCount; i++) {\n\t\tTriangle triangle = Import::read<Triangle>(input);\n\n\t\ttriangles[i] = triangle;\n\n\t\t// Calculate (bi)tangents\n\t\tif (flag == VT || flag == VNT) {\n\t\t\tVec3f tangent;\n\t\t\tVec3f bitangent;\n\n\t\t\tVec3f edge1 = vertices[triangle.secondIndex] - vertices[triangle.firstIndex];\n\t\t\tVec3f edge2 = vertices[triangle.thirdIndex] - vertices[triangle.firstIndex];\n\t\t\tVec2f dUV1 = uvs[triangle.secondIndex] - uvs[triangle.firstIndex];\n\t\t\tVec2f dUV2 = uvs[triangle.thirdIndex] - uvs[triangle.firstIndex];\n\n\t\t\tfloat f = 1.0f / (dUV1.x * dUV2.y - dUV2.x * dUV1.y);\n\n\t\t\ttangent.x = f * (dUV2.y * edge1.x - dUV1.y * edge2.x);\n\t\t\ttangent.y = f * (dUV2.y * edge1.y - dUV1.y * edge2.y);\n\t\t\ttangent.z = f * (dUV2.y * edge1.z - dUV1.y * edge2.z);\n\t\t\ttangents[triangle.firstIndex] = normalize(tangent);\n\t\t\ttangents[triangle.secondIndex] = normalize(tangent);\n\t\t\ttangents[triangle.thirdIndex] = normalize(tangent);\n\n\t\t\tbitangent.x = f * (-dUV2.x * edge1.x + dUV1.x * edge2.x);\n\t\t\tbitangent.y = f * (-dUV2.x * edge1.y + dUV1.x * edge2.y);\n\t\t\tbitangent.z = f * (-dUV2.x * edge1.z + dUV1.x * edge2.z);\n\t\t\tbitangents[triangle.firstIndex] = normalize(bitangent);\n\t\t\tbitangents[triangle.secondIndex] = normalize(bitangent);\n\t\t\tbitangents[triangle.thirdIndex] = normalize(bitangent);\n\t\t}\n\t}\n\n\tGraphics::ExtendedTriangleMesh result(vertices, vertexCount, triangles, triangleCount);\n\tresult.setNormalBuffer(SRef<const Vec3f[]>(normals));\n\tresult.setUVBuffer(SRef<const Vec2f[]>(uvs));\n\tresult.setTangentBuffer(SRef<const Vec3f[]>(tangents));\n\tresult.setBitangentBuffer(SRef<const Vec3f[]>(bitangents));\n\n\treturn result;\n}\n\nGraphics::ExtendedTriangleMesh loadNonBinaryObj(std::istream& input) {\n\tstd::vector<Vec3f> vertices;\n\tstd::vector<Vec3f> normals;\n\tstd::vector<Vec2f> uvs;\n\tstd::vector<Face> faces;\n\n\tstd::string line;\n\twhile (getline(input, line)) {\n\t\tstd::vector<std::string_view> tokens = Util::split_view(line, ' ');\n\n\t\tif (tokens.empty())\n\t\t\tcontinue;\n\n\t\tif (tokens[0] == \"v\") {\n\t\t\tfloat x = std::stof(std::string(tokens[1]));\n\t\t\tfloat y = std::stof(std::string(tokens[2]));\n\t\t\tfloat z = std::stof(std::string(tokens[3]));\n\n\t\t\tvertices.emplace_back(x, y, z);\n\t\t} else if (tokens[0] == \"f\") {\n\t\t\tVertex v1(tokens[1]);\n\t\t\tVertex v2(tokens[2]);\n\t\t\tVertex v3(tokens[3]);\n\n\t\t\tfaces.emplace_back(v1, v2, v3);\n\n\t\t\tif (tokens.size() > 4)\n\t\t\t\tfaces.emplace_back(v1, v3, Vertex(tokens[4]));\n\t\t} else if (tokens[0] == \"vt\") {\n\t\t\tfloat u = std::stof(std::string(tokens[1]));\n\t\t\tfloat v = 1.0f - std::stof(std::string(tokens[2]));\n\n\t\t\tuvs.emplace_back(u, v);\n\t\t} else if (tokens[0] == \"vn\") {\n\t\t\tfloat x = std::stof(std::string(tokens[1]));\n\t\t\tfloat y = std::stof(std::string(tokens[2]));\n\t\t\tfloat z = std::stof(std::string(tokens[3]));\n\n\t\t\tnormals.emplace_back(x, y, z);\n\t\t}\n\t}\n\n\treturn reorderWithSharedVerticesSupport(vertices, normals, uvs, faces);\n}\n\nGraphics::ExtendedTriangleMesh OBJImport::load(std::istream& file, bool binary) {\n\tif (binary)\n\t\treturn loadBinaryObj(file);\n\telse\n\t\treturn loadNonBinaryObj(file);\n}\n\nGraphics::ExtendedTriangleMesh OBJImport::load(const std::string& file) {\n\tbool binary;\n\tif (Util::endsWith(file, \".bobj\"))\n\t\tbinary = true;\n\telse if (Util::endsWith(file, \".obj\"))\n\t\tbinary = false;\n\telse\n\t\treturn Graphics::ExtendedTriangleMesh();\n\n\treturn OBJImport::load(file, binary);\n}\n\nGraphics::ExtendedTriangleMesh OBJImport::load(const std::string& file, bool binary) {\n\tstd::ifstream input;\n\n\tif (binary)\n\t\tinput.open(file, std::ios::binary);\n\telse\n\t\tinput.open(file);\n\n\tGraphics::ExtendedTriangleMesh shape = load(input, binary);\n\n\tinput.close();\n\n\treturn shape;\n}\n\n/*\n\tEnd of OBJImport\n*/\n\n}"
  },
  {
    "path": "engine/io/import.h",
    "content": "#pragma once\n\n#include <istream>\n\nnamespace P3D::Graphics {\nstruct ExtendedTriangleMesh;\n};\n\nnamespace P3D {\n\nnamespace Import {\n\tint parseInt(const std::string& num);\n\tlong long parseLong(const std::string& num);\n\tFix<32> parseFix(const std::string& num);\n\tfloat parseFloat(const std::string& num);\n\tdouble parseDouble(const std::string& num);\n\tVec3 parseVec3(const std::string& vec);\n\tVec3f parseVec3f(const std::string& vec);\n\tVec4 parseVec4(const std::string& vec);\n\tVec4f parseVec4f(const std::string& vec);\n\tPosition parsePosition(const std::string& pos);\n\tDiagonalMat3 parseDiagonalMat3(const std::string& mat);\n\tMat3 parseMat3(const std::string& mat);\n\n\ttemplate<typename T>\n\tT read(std::istream& input);\n};\n\nnamespace OBJImport {\n\tGraphics::ExtendedTriangleMesh load(std::istream& file, bool binary = false);\n\tGraphics::ExtendedTriangleMesh load(const std::string& file, bool binary);\n\tGraphics::ExtendedTriangleMesh load(const std::string& file);\n};\n\n};"
  },
  {
    "path": "engine/layer/layer.h",
    "content": "#pragma once\n\n#include \"../event/event.h\"\n#include \"../ecs/registry.h\"\n\n#include <string>\n\nnamespace P3D::Engine {\n\nclass Layer {\nprotected:\n\tvoid* ptr = nullptr;\n\npublic:\n\n\tenum LayerFlags : char {\n\t\t// No flags, update, render and events are called\n\t\tNone = 0 << 0,\n\n\t\t// Whether the layer is disabled, no update, render or event calls\n\t\tDisabled = 1 << 0,\n\n\t\t// Whether the layer is hidden, no render calls\n\t\tNoRender = 1 << 1,\n\n\t\t// Whether the layer receives events\n\t\tNoEvents = 1 << 2,\n\n\t\t// Whether the layer updates\n\t\tNoUpdate = 1 << 3\n\t};\n\n\tstd::string name;\n\tchar flags;\n\n\tinline Layer() : ptr(nullptr), name(), flags(None) {};\n\tinline Layer(const std::string& name, void* ptr, char flags = None) : ptr(ptr), name(name), flags(flags) {}\n\n\tinline virtual void onAttach() {}\n\tinline virtual void onDetach() {}\n\tinline virtual void onInit(Registry64& registry) {}\n\tinline virtual void onEvent(Registry64& registry, Event& event) {}\n\tinline virtual void onUpdate(Registry64& registry) {}\n\tinline virtual void onRender(Registry64& registry) {}\n\tinline virtual void onClose(Registry64& registry) {}\n};\n\n};"
  },
  {
    "path": "engine/layer/layerStack.cpp",
    "content": "#include \"core.h\"\n\n#include \"layerStack.h\"\n\nnamespace P3D::Engine {\n\nLayerStack::LayerStack() {\n\tinsert = 0;\n}\n\nvoid LayerStack::pushLayer(Layer* layer) {\n\tstack.insert(stack.begin() + insert++, layer);\n\tlayer->onAttach();\n}\n\nvoid LayerStack::popLayer(Layer* layer) {\n\tconst auto where = std::find(begin(), end(), layer);\n\n\tif (where != end()) {\n\t\tstack.erase(where);\n\t\tinsert--;\n\n\t\tlayer->onDetach();\n\t}\n}\n\nvoid LayerStack::onInit(Registry64& registry) {\n\tfor (auto* layer : *this) \n\t\tlayer->onInit(registry);\n}\n\nvoid LayerStack::onUpdate(Registry64& registry) {\n\tfor (auto* layer : *this) {\n\t\tif (layer->flags & (Layer::Disabled | Layer::NoUpdate))\n\t\t\tcontinue;\n\n\t\tlayer->onUpdate(registry);\n\t}\n}\n\nvoid LayerStack::onEvent(Registry64& registry, Event& event) {\n\tfor (auto i = rbegin(); i != rend(); ++i) {\n\t\tauto* layer = *i;\n\n\t\tif (layer->flags & (Layer::Disabled | Layer::NoEvents))\n\t\t\tcontinue;\n\n\t\tlayer->onEvent(registry, event);\n\n\t\tif (event.handled)\n\t\t\treturn;\n\t}\n}\n\nvoid LayerStack::onRender(Registry64& registry) {\n\tfor (auto* layer : *this) {\n\t\tif (layer->flags & (Layer::Disabled | Layer::NoRender))\n\t\t\tcontinue;\n\n\t\tlayer->onRender(registry);\n\t}\n}\n\nvoid LayerStack::onClose(Registry64& registry) {\n\tfor (auto i = rbegin(); i != rend(); ++i)\n\t\t(*i)->onClose(registry);\n\t\n}\n\nstd::vector<Layer*>::iterator LayerStack::begin() {\n\treturn stack.begin();\n}\n\nstd::vector<Layer*>::iterator LayerStack::end() {\n\treturn stack.end();\n}\n\nstd::vector<Layer*>::reverse_iterator LayerStack::rbegin() {\n\treturn stack.rbegin();\n}\n\nstd::vector<Layer*>::reverse_iterator LayerStack::rend() {\n\treturn stack.rend();\n}\n\n};"
  },
  {
    "path": "engine/layer/layerStack.h",
    "content": "#pragma once\n\n#include \"layer.h\"\n#include \"../engine/ecs/registry.h\"\n\nnamespace P3D::Engine {\n\nclass LayerStack {\nprivate:\n\tstd::vector<Layer*> stack;\n\tint insert;\n\npublic:\n\tLayerStack();\n\n\tvoid pushLayer(Layer* layer);\n\tvoid popLayer(Layer* layer);\n\n\tvoid onInit(Registry64& registry);\n\tvoid onUpdate(Registry64& registry);\n\tvoid onEvent(Registry64& registry, Event& event);\n\tvoid onRender(Registry64& registry);\n\tvoid onClose(Registry64& registry);\n\n\tstd::vector<Layer*>::iterator begin();\n\tstd::vector<Layer*>::iterator end();\n\n\tstd::vector<Layer*>::reverse_iterator rbegin();\n\tstd::vector<Layer*>::reverse_iterator rend();\n};\n\n};"
  },
  {
    "path": "engine/options/keyboardOptions.cpp",
    "content": "#include \"core.h\"\n\n#include \"keyboardOptions.h\"\n\nnamespace P3D::Engine {\n\nnamespace KeyboardOptions {\n\n\tnamespace Move {\n\t\tKey forward  = Keyboard::KEY_UNKNOWN;\n\t\tKey backward = Keyboard::KEY_UNKNOWN;\n\t\tKey right    = Keyboard::KEY_UNKNOWN;\n\t\tKey left     = Keyboard::KEY_UNKNOWN;\n\t\tKey jump     = Keyboard::KEY_UNKNOWN;\n\t\tKey fly      = Keyboard::KEY_UNKNOWN;\n\t\tKey ascend   = Keyboard::KEY_UNKNOWN;\n\t\tKey descend  = Keyboard::KEY_UNKNOWN;\n\t};\n\n\tnamespace Rotate {\n\t\tKey up    = Keyboard::KEY_UNKNOWN;\n\t\tKey down  = Keyboard::KEY_UNKNOWN;\n\t\tKey left  = Keyboard::KEY_UNKNOWN;\n\t\tKey right = Keyboard::KEY_UNKNOWN;\n\t};\n\n\tnamespace Tick {\n\t\tKey run   = Keyboard::KEY_UNKNOWN;\n\t\tKey pause = Keyboard::KEY_UNKNOWN;\n\t\tnamespace Speed {\n\t\t\tKey up   = Keyboard::KEY_UNKNOWN;\n\t\t\tKey down = Keyboard::KEY_UNKNOWN;\n\t\t};\n\t};\n\n\tnamespace Debug {\n\t\tKey spheres = Keyboard::KEY_UNKNOWN;\n\t\tKey tree    = Keyboard::KEY_UNKNOWN;\n\t\tKey pies    = Keyboard::KEY_UNKNOWN;\n\t\tKey frame   = Keyboard::KEY_UNKNOWN;\n\t};\n\n\tnamespace Edit {\n\t\tKey translate = Keyboard::KEY_UNKNOWN;\n\t\tKey rotate    = Keyboard::KEY_UNKNOWN;\n\t\tKey scale     = Keyboard::KEY_UNKNOWN;\n\t\tKey select    = Keyboard::KEY_UNKNOWN;\n\t\tKey region    = Keyboard::KEY_UNKNOWN;\n\t};\n\n\tnamespace Part {\n\t\tKey remove           = Keyboard::KEY_UNKNOWN;\n\t\tKey anchor           = Keyboard::KEY_UNKNOWN;\n\t\tKey makeMainPart     = Keyboard::KEY_UNKNOWN;\n\t\tKey makeMainPhysical = Keyboard::KEY_UNKNOWN;\n\t}\n\n\tnamespace Application {\n\t\tKey close = Keyboard::KEY_UNKNOWN;\n\t}\n\n\tnamespace World {\n\t\tKey valid = Keyboard::KEY_UNKNOWN;\n\t}\n\n\tKey loadKey(const Util::Properties& properties, std::string key) {\n\t\treturn Keyboard::getKey(properties.get(key));\n\t}\n\n\tvoid saveKey(Util::Properties& properties, std::string property, const Key& key) {\n\t\tproperties.set(property, key.getName());\n\t}\n\n\tvoid load(const Util::Properties& properties) {\n\t\t// Move\n\t\tMove::forward = loadKey(properties, \"move.forward\");\n\t\tMove::backward = loadKey(properties, \"move.backward\");\n\t\tMove::right = loadKey(properties, \"move.right\");\n\t\tMove::left = loadKey(properties, \"move.left\");\n\t\tMove::jump = loadKey(properties, \"move.jump\");\n\t\tMove::fly = loadKey(properties, \"move.fly\");\n\t\tMove::ascend = loadKey(properties, \"move.ascend\");\n\t\tMove::descend = loadKey(properties, \"move.descend\");\n\n\t\t// Rotate\n\t\tRotate::up = loadKey(properties, \"rotate.up\");\n\t\tRotate::down = loadKey(properties, \"rotate.down\");\n\t\tRotate::left = loadKey(properties, \"rotate.left\");\n\t\tRotate::right = loadKey(properties, \"rotate.right\");\n\n\t\t// Tick\n\t\tTick::run = loadKey(properties, \"tick.run\");\n\t\tTick::pause = loadKey(properties, \"tick.pause\");\n\t\tTick::Speed::up = loadKey(properties, \"tick.speed.up\");\n\t\tTick::Speed::down = loadKey(properties, \"tick.speed.down\");\n\t\n\t\t// Debug\n\t\tDebug::spheres = loadKey(properties, \"debug.spheres\");\n\t\tDebug::tree = loadKey(properties, \"debug.tree\");\n\t\tDebug::pies = loadKey(properties, \"debug.pies\");\n\t\tDebug::frame = loadKey(properties, \"debug.frame\");\n\n\t\t// Part\n\t\tPart::anchor = loadKey(properties, \"part.anchor\");\n\t\tPart::remove = loadKey(properties, \"part.delete\");\n\t\tPart::makeMainPart = loadKey(properties, \"part.makeMainPart\");\n\t\tPart::makeMainPhysical = loadKey(properties, \"part.makeMainPhysical\");\n\n\t\t// Edit\n\t\tEdit::translate = loadKey(properties, \"edit.translate\");\n\t\tEdit::rotate = loadKey(properties, \"edit.rotate\");\n\t\tEdit::scale = loadKey(properties, \"edit.scale\");\n\t\tEdit::select = loadKey(properties, \"edit.select\");\n\t\tEdit::region = loadKey(properties, \"edit.region\");\n\n\t\t// Application\n\t\tApplication::close = loadKey(properties, \"application.close\");\n\n\t\t// World\n\t\tWorld::valid = loadKey(properties, \"world.valid\");\n\t}\n\n\tvoid save(Util::Properties& properties) {\n\t\t// Move\n\t\tsaveKey(properties, \"move.forward\", Move::forward);\n\t\tsaveKey(properties, \"move.backward\", Move::backward);\n\t\tsaveKey(properties, \"move.right\", Move::right);\n\t\tsaveKey(properties, \"move.left\", Move::left);\n\t\tsaveKey(properties, \"move.jump\", Move::jump);\n\t\tsaveKey(properties, \"move.fly\", Move::fly);\n\t\tsaveKey(properties, \"move.ascend\", Move::ascend);\n\t\tsaveKey(properties, \"move.descend\", Move::descend);\n\n\t\t// Rotate\n\t\tsaveKey(properties, \"rotate.up\", Rotate::up);\n\t\tsaveKey(properties, \"rotate.down\", Rotate::down);\n\t\tsaveKey(properties, \"rotate.left\", Rotate::left);\n\t\tsaveKey(properties, \"rotate.right\", Rotate::right);\n\n\t\t// Tick\n\t\tsaveKey(properties, \"tick.run\", Tick::run);\n\t\tsaveKey(properties, \"tick.pause\", Tick::pause);\n\t\tsaveKey(properties, \"tick.speed.up\", Tick::Speed::up);\n\t\tsaveKey(properties, \"tick.speed.down\", Tick::Speed::down);\n\n\t\t// Debug\n\t\tsaveKey(properties, \"debug.spheres\", Debug::spheres);\n\t\tsaveKey(properties, \"debug.tree\", Debug::tree);\n\t\tsaveKey(properties, \"debug.pies\", Debug::pies);\n\t\tsaveKey(properties, \"debug.frame\", Debug::frame);\n\n\t\t// Part\n\t\tsaveKey(properties, \"part.anchor\", Part::anchor);\n\t\tsaveKey(properties, \"part.delete\", Part::remove);\n\n\t\t// Edit\n\t\tsaveKey(properties, \"edit.translate\", Edit::translate);\n\t\tsaveKey(properties, \"edit.rotate\", Edit::rotate);\n\t\tsaveKey(properties, \"edit.scale\", Edit::scale);\n\t\tsaveKey(properties, \"edit.select\", Edit::select);\n\t\tsaveKey(properties, \"edit.region\", Edit::region);\n\n\t\t// Application\n\t\tsaveKey(properties, \"application.close\", Application::close);\n\n\t\t// World\n\t\tsaveKey(properties, \"world.valid\", World::valid);\n\t}\n}\n\n};"
  },
  {
    "path": "engine/options/keyboardOptions.h",
    "content": "#pragma once\n\n#include \"../input/keyboard.h\"\n#include \"../util/properties.h\"\n\nnamespace P3D::Engine {\n\nnamespace KeyboardOptions {\n\tusing Engine::Key;\n\n\tnamespace Move {\n\t\textern Key forward;\n\t\textern Key backward;\n\t\textern Key right;\n\t\textern Key left;\n\n\t\textern Key jump;\n\t\textern Key fly;\n\t\textern Key ascend;\n\t\textern Key descend;\n\t};\n\n\tnamespace Rotate {\n\t\textern Key up;\n\t\textern Key down;\n\t\textern Key left;\n\t\textern Key right;\n\t}\n\n\tnamespace Tick {\n\t\textern Key pause;\n\t\textern Key run;\n\t\tnamespace Speed {\n\t\t\textern Key up;\n\t\t\textern Key down;\n\t\t};\n\t};\n\n\tnamespace Debug {\n\t\textern Key spheres;\n\t\textern Key tree;\n\t\textern Key pies;\n\t\textern Key frame;\n\t};\n\n\tnamespace Edit {\n\t\textern Key translate;\n\t\textern Key rotate;\n\t\textern Key scale;\n\t\textern Key select;\n\t\textern Key region;\n\t};\n\n\tnamespace Part {\n\t\textern Key remove;\n\t\textern Key anchor;\n\t\textern Key makeMainPart;\n\t\textern Key makeMainPhysical;\n\t}\n\n\tnamespace Application {\n\t\textern Key close;\n\t}\n\n\tnamespace World {\n\t\textern Key valid;\n\t}\n\n\tvoid load(const Util::Properties& properties);\n\tvoid save(Util::Properties& properties);\n}\n\n};"
  },
  {
    "path": "engine/resource/meshResource.cpp",
    "content": "#include \"core.h\"\n\n#include \"meshResource.h\"\n#include \"../io/import.h\"\n#include \"../graphics/extendedTriangleMesh.h\"\n\nnamespace P3D::Engine {\n\nMeshResource* MeshAllocator::load(const std::string& name, const std::string& path) {\n\tGraphics::ExtendedTriangleMesh shape = OBJImport::load(path);\n\n\treturn new MeshResource(name, path, shape);\n}\n\n};"
  },
  {
    "path": "engine/resource/meshResource.h",
    "content": "#pragma once\n\n#include \"../util/resource/resource.h\"\n\n#include \"../graphics/mesh/indexedMesh.h\"\n#include \"../graphics/extendedTriangleMesh.h\"\n\nnamespace P3D::Engine {\n\nclass MeshResource;\n\nclass MeshAllocator : public ResourceAllocator<MeshResource> {\npublic:\n\tvirtual MeshResource* load(const std::string& name, const std::string& path) override;\n};\n\nclass MeshResource : public Resource {\nprivate:\n\tGraphics::ExtendedTriangleMesh shape;\npublic:\n\tDEFINE_RESOURCE(Mesh, \"../res/fonts/default/default.ttf\");\n\n\tMeshResource(const std::string& path, Graphics::ExtendedTriangleMesh shape) : Resource(path, path), shape(shape) {\n\n\t}\n\n\tMeshResource(const std::string& name, const std::string& path, Graphics::ExtendedTriangleMesh shape) : Resource(name, path), shape(shape) {\n\n\t}\n\n\tGraphics::ExtendedTriangleMesh* getShape() {\n\t\treturn &shape;\n\t}\n\n\tvoid close() override {\n\t\t\n\t}\n\n\tstatic MeshAllocator getAllocator() {\n\t\treturn MeshAllocator();\n\t}\n};\n\n};"
  },
  {
    "path": "engine/tool/buttonTool.h",
    "content": "#pragma once\n\n#include \"tool.h\"\n\nnamespace P3D::Engine {\n\ntypedef char ToolStatus;\n\nclass ButtonTool : public Tool {\n\t\n};\n\n};"
  },
  {
    "path": "engine/tool/stateTool.h",
    "content": "#pragma once\n\n#include \"tool.h\"\n\nnamespace P3D::Engine {\n\ntypedef char ToolStatus;\n\nclass StateTool : public Tool {\nprivate:\n\tToolStatus toolStatus = 0;\n\nprotected:\n\tvoid setToolStatus(ToolStatus toolStatus) {\n\t\tthis->toolStatus = toolStatus;\n\t}\n\n\tStateTool() : Tool() {}\n\npublic:\n\tToolStatus getToolStatus() const {\n\t\treturn toolStatus;\n\t}\n};\n\n};"
  },
  {
    "path": "engine/tool/tool.h",
    "content": "#pragma once\n\n#include <string>\n\nnamespace P3D::Engine {\n\nclass Event;\n\n#define DEFINE_TOOL(name, description, cursor) \\\n\tinline std::string getName() { return getStaticName(); } \\\n\tinline std::string getDescription() { return getStaticDescription(); } \\\n\tinline static std::string getStaticName() { return name; } \\\n\tinline static std::string getStaticDescription() { return description; } \\\n\tinline int getCursorType() { return cursor; } \\\n\t\nclass Tool {\n\npublic:\n\tTool() = default;\n\n\tvirtual ~Tool() = default;\n\n\t/*\n\t\tReturns the name of this tool\n\t*/\n\tvirtual std::string getName() = 0;\n\tstatic std::string getStaticName();\n\n\t/*\n\t\tReturns the description of this tool\n\t*/\n\tvirtual std::string getDescription() = 0;\n\tstatic std::string getStaticDescription();\n\n\t/*\n\t\tWhen the tool gets registered\n\t*/\n\tvirtual void onRegister() {}\n\n\t/*\n\t\tWhen the tool gets deregistered\n\t*/\n\tvirtual void onDeregister() {}\n\t\n\t/*\n\t\tWhen the tool is selected\n\t*/\n\tvirtual void onSelect() {}\n\n\t/*\n\t\tWhen the tool is deselected\n\t*/\n\tvirtual void onDeselect() {}\n\n\t/*\n\t\tWhen the tool gets updated\n\t*/\n\tvirtual void onUpdate() {}\n\n\t/*\n\t\tWhen the tool gets rendered\n\t*/\n\tvirtual void onRender() {}\n\n\t/*\n\t\tWhen the tool receives an event\n\t*/\n\tvirtual void onEvent(Event& event) {}\n\t\n};\n\n};"
  },
  {
    "path": "engine/tool/toolManager.cpp",
    "content": "#include \"core.h\"\n\n#include \"toolManager.h\"\n\n#include \"buttonTool.h\"\n\nnamespace P3D::Engine {\n\t\n\tToolManager::ToolManager(): activeTool(nullptr) {\n\n\t}\n\n\tToolManager::~ToolManager() {\n\t\tToolManager::onClose();\n\t}\n\n\tToolManager& ToolManager::operator=(ToolManager&& other) noexcept {\n\t\tif (this != &other) {\n\t\t\tactiveTool = std::exchange(other.activeTool, nullptr);\n\t\t\ttools = std::move(other.tools);\n\t\t}\n\n\t\treturn *this;\n\t}\n\n\tToolManager::ToolManager(ToolManager&& other) noexcept: activeTool(other.activeTool), tools(std::move(other.tools)) {\n\t\tother.activeTool = nullptr;\n\t}\n\n\tvoid ToolManager::onEvent(Event& event) {\n\t\tif (activeTool == nullptr)\n\t\t\treturn;\n\n\t\tactiveTool->onEvent(event);\n\t}\n\n\tvoid ToolManager::onUpdate() {\n\t\tif (activeTool == nullptr)\n\t\t\treturn;\n\n\t\tactiveTool->onUpdate();\n\t}\n\n\tvoid ToolManager::onRender() {\n\t\tif (activeTool == nullptr)\n\t\t\treturn;\n\n\t\tactiveTool->onRender();\n\t}\n\n\tvoid ToolManager::onClose() {\n\t\tif (activeTool != nullptr)\n\t\t\tactiveTool->onDeselect();\n\n\t\tfor (Tool* tool : tools) {\n\t\t\ttool->onDeregister();\n\t\t\tdelete tool;\n\t\t}\n\n\t\tactiveTool = nullptr;\n\t\ttools.clear();\n\t}\n\n\tbool ToolManager::deselectTool() {\n\t\tif (activeTool == nullptr)\n\t\t\treturn false;\n\n\t\tactiveTool->onDeselect();\n\t\tactiveTool = nullptr;\n\n\t\treturn true;\n\t}\n\n\tbool ToolManager::selectTool(const std::string& name) {\n\t\tauto iterator = std::find_if(tools.begin(), tools.end(),\n\t\t                             [&name](Tool* tool) { return tool->getName() == name; });\n\n\t\tif (iterator == tools.end())\n\t\t\treturn false;\n\n\t\tTool* tool = *iterator;\n\t\t\n\t\tif (dynamic_cast<ButtonTool*>(tool) != nullptr) {\n\t\t\ttool->onSelect();\n\t\t\ttool->onDeselect();\n\t\t} else {\n\t\t\tif (activeTool != nullptr)\n\t\t\t\tactiveTool->onDeselect();\n\n\t\t\tactiveTool = tool;\n\t\t\tactiveTool->onSelect();\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tbool ToolManager::selectTool(Tool* tool) {\n\t\tauto iterator = std::find(tools.begin(), tools.end(), tool);\n\t\tif (iterator == tools.end())\n\t\t\treturn false;\n\t\t\n\t\tif (tool == nullptr)\n\t\t\treturn deselectTool();\n\n\t\tif (dynamic_cast<ButtonTool*>(tool) != nullptr) {\n\t\t\ttool->onSelect();\n\t\t\ttool->onDeselect();\n\t\t} else {\n\t\t\tif (activeTool != nullptr)\n\t\t\t\tactiveTool->onDeselect();\n\n\t\t\tactiveTool = tool;\n\t\t\tactiveTool->onSelect();\n\t\t}\n\t\t\n\t\treturn true;\n\t}\n\n\tbool ToolManager::isSelected(Tool* tool) {\n\t\treturn activeTool == tool;\n\t}\n\n\tbool ToolManager::isSelected(const std::string& name) {\n\t\treturn activeTool->getName() == name;\n\t}\n\n\tstd::vector<Tool*>::iterator ToolManager::begin() {\n\t\treturn tools.begin();\n\t}\n\n\tstd::vector<Tool*>::iterator ToolManager::end() {\n\t\treturn tools.end();\n\t}\n\n}\n"
  },
  {
    "path": "engine/tool/toolManager.h",
    "content": "#pragma once\n\n#include \"tool.h\"\n\nnamespace P3D::Engine {\n\nclass Event;\n\nclass ToolManager {\npublic:\n\tTool* activeTool;\n\tstd::vector<Tool*> tools;\n\n\tToolManager();\n\tvirtual ~ToolManager();\n\n\tToolManager(ToolManager&& other) noexcept;\n\tToolManager& operator=(ToolManager&& other) noexcept;\n\n\tToolManager(const ToolManager& other) = delete;\n\tToolManager& operator=(const ToolManager& other) = delete;\n\n\ttemplate<typename DerivedTool, typename... Args>\n\tstd::enable_if_t<std::is_base_of_v<Tool, DerivedTool>, bool> registerTool(Args&&... args) {\n\t\tDerivedTool* tool = new DerivedTool(std::forward<Args>(args)...);\n\t\ttools.push_back(tool);\n\t\ttool->onRegister();\n\t\t\n\t\treturn true;\n\t}\n\n\ttemplate<typename DerivedTool>\n\tstd::enable_if_t<std::is_base_of_v<Tool, DerivedTool>, bool> deregisterTool() {\n\t\tauto iterator = std::find_if(tools.begin(), tools.end(), [] (Tool* tool) { return tool->getName() == DerivedTool::getStaticName(); });\n\t\tif (iterator == tools.end())\n\t\t\treturn false;\n\n\t\tDerivedTool* tool = *iterator;\n\t\t\n\t\ttools.erase(iterator);\n\t\ttool->onDeregister();\n\t\tdelete tool;\n\t\t\n\t\treturn true;\n\t}\n\n\tvirtual void onEvent(Event& event);\n\tvirtual void onUpdate();\n\tvirtual void onRender();\n\tvirtual void onClose();\n\n\tbool deselectTool();\n\n\tbool selectTool(const std::string& name);\n\tbool selectTool(Tool* tool);\n\n\tbool isSelected(Tool* tool);\n\tbool isSelected(const std::string& name);\n\n\ttemplate<typename T>\n\tbool selectTool() {\n\t\treturn selectTool(T::getStaticName());\n\t}\n\t\n\ttemplate<typename T>\n\tbool isSelected() {\n\t\treturn isSelected(T::getStaticName());\n\t}\n\n\tstd::vector<Tool*>::iterator begin();\n\tstd::vector<Tool*>::iterator end();\n};\n\n};"
  },
  {
    "path": "examples/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.10)\n\nproject(Physics3D-OpenGL-Demo VERSION 1.0)\n\nmessage(STATUS \"Build type: ${CMAKE_BUILD_TYPE}\")\nmessage(STATUS \"Building with: ${CMAKE_CXX_COMPILER_ID}\")\nmessage(STATUS \"CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}\")\nmessage(STATUS \"CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}\")\n\nset(CMAKE_CXX_STANDARD 17)\nset(CMAKE_CXX_STANDARD_REQUIRED True)\n\nif (CMAKE_CXX_COMPILER_ID STREQUAL \"MSVC\")\n  set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} /arch:AVX2\")\n  set(CMAKE_CXX_FLAGS_RELEASE \"${CMAKE_CXX_FLAGS_RELEASE} /O2\")\nelse()\n  set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -Wall -march=native\")\n  set(CMAKE_CXX_FLAGS_RELEASE \"${CMAKE_CXX_FLAGS_RELEASE} -O3\")\nendif()\n\nadd_executable(openglBasic \n\topenglBasic.cpp\n)\n\n# OpenGL, GLEW, GLFW\nfind_package(OpenGL REQUIRED)\nfind_package(GLEW REQUIRED)\nfind_package(glfw3 REQUIRED)\n\ntarget_link_libraries(openglBasic glfw)\ntarget_link_libraries(openglBasic OpenGL::GL)\ntarget_link_libraries(openglBasic GLEW::GLEW)\n\n# Physics3D\nadd_subdirectory(../Physics3D build)\n\ntarget_include_directories(openglBasic PUBLIC ../)\ntarget_link_libraries(openglBasic Physics3D)\n"
  },
  {
    "path": "examples/examples.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <VCProjectVersion>16.0</VCProjectVersion>\n    <Keyword>Win32Proj</Keyword>\n    <ProjectGuid>{bbe4c27e-7eda-4f07-a5a0-9103bfb4c47c}</ProjectGuid>\n    <RootNamespace>examples</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalIncludeDirectories>$(SolutionDir)include;$(SolutionDir)application;$(SolutionDir)</AdditionalIncludeDirectories>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <AdditionalLibraryDirectories>$(SolutionDir)lib;$(OutDir)</AdditionalLibraryDirectories>\n      <AdditionalDependencies>glfw3.lib;glew32s.lib;opengl32.lib;Physics3D.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions);GLEW_STATIC</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalIncludeDirectories>$(SolutionDir)include;$(SolutionDir)application;$(SolutionDir)</AdditionalIncludeDirectories>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <AdditionalLibraryDirectories>$(SolutionDir)lib;$(OutDir)</AdditionalLibraryDirectories>\n      <AdditionalDependencies>glfw3.lib;glew32s.lib;opengl32.lib;Physics3D.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"openglBasic.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "examples/openglBasic.cpp",
    "content": "// Include GLEW. Always include it before gl.h and glfw3.h, since it's a bit magic.\n#include <GL/glew.h>\n#include <GLFW/glfw3.h>\n\n#include <Physics3D/math/linalg/vec.h>\n#include <Physics3D/math/linalg/mat.h>\n#include <Physics3D/math/linalg/trigonometry.h>\n\n#include <Physics3D/part.h>\n#include <Physics3D/world.h>\n#include <Physics3D/worldIteration.h>\n#include <Physics3D/geometry/polyhedron.h>\n#include <Physics3D/geometry/shape.h>\n#include <Physics3D/geometry/shapeClass.h>\n#include <Physics3D/geometry/shapeCreation.h>\n#include <Physics3D/geometry/shapeLibrary.h>\n#include <Physics3D/threading/physicsThread.h>\n#include <Physics3D/externalforces/directionalGravity.h>\n\n#include <cstdio>\n#include <vector>\n#include <memory>\n\nusing namespace P3D;\n\nGLFWwindow* initWindow() {\n\t// Initialise GLFW\n\tif(!glfwInit()) {\n\t\tstd::cerr << \"Failed to initialize GLFW\" << std::endl;\n\t\treturn nullptr;\n\t}\n\n\tglfwWindowHint(GLFW_SAMPLES, 4); // 4x antialiasing\n\tglfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // We want OpenGL 3.3\n\tglfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);\n\tglfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed\n\tglfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // We don't want the old OpenGL \n\n\n\t// Open a window and create its OpenGL context\n\tGLFWwindow* window = glfwCreateWindow( 1024, 768, \"Physics3D Demo\", nullptr, nullptr);\n\tif(window == nullptr) {\n\t\tstd::cerr << \"Failed to open GLFW window.\" << std::endl;\n\t\tglfwTerminate();\n\t\treturn nullptr;\n\t}\n\tglfwMakeContextCurrent(window); // Initialize GLEW\n\n\tif(glewInit() != GLEW_OK) {\n\t\tstd::cerr << \"Failed to initialize GLEW\" << std::endl;\n\t\treturn nullptr;\n\t}\n\n\t// Ensure we can capture the escape key being pressed below\n\tglfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);\n\treturn window;\n}\n\n\nstruct Color {\n\tunion {\n\t\tfloat data[3];\n\t\tstruct {\n\t\t\tfloat r;\n\t\t\tfloat g;\n\t\t\tfloat b;\n\t\t};\n\t\tVec3f asVec3f;\n\t};\n};\nnamespace Colors {\n\tstatic constexpr Color BLUE  {0.0f, 0.0f, 1.0f};\n\tstatic constexpr Color RED   {1.0f, 0.0f, 0.0f};\n\tstatic constexpr Color GREEN {0.0f, 1.0f, 0.0f};\n\tstatic constexpr Color WHITE {1.0f, 1.0f, 1.0f};\n\tstatic constexpr Color BLACK {0.0f, 0.0f, 0.0f};\n\tstatic constexpr Color GRAY  {0.5f, 0.5f, 0.5f};\n}\n\nconst char* const basicVertexShader = R\"(\n#version 300 es\nprecision highp float;\nlayout(location = 0) in vec3 vertexPosition_modelspace;\nlayout(location = 1) in vec3 vertexNormal_modelspace;\n\nuniform mat4 modelMatrix;\nuniform mat4 pvMatrix;\nuniform vec3 lightDirection;\nuniform vec3 partColor;\n\nout vec3 fragmentColor;\n  \nvoid main(){\n  // Output position of the vertex, in clip space : pvMatrix * modelMatrix * position\n  gl_Position = pvMatrix * modelMatrix * vec4(vertexPosition_modelspace,1);\n  vec3 vertexNormal_worldspace = mat3(modelMatrix) * vertexNormal_modelspace;\n  float brightness = (dot(-vertexNormal_worldspace, lightDirection) + 1.0f) / 2.0f;\n  //fragmentColor = vec3(brightness, brightness, brightness);\n  fragmentColor = brightness * partColor;\n}\n)\";\n\nconst char* basicFragmentShader = R\"(\n#version 300 es\nprecision highp float;\nout vec3 color;\nin vec3 fragmentColor;\nvoid main() {\n  color = fragmentColor;\n}\n)\";\n\nGLuint loadShaders(const char* vertexShaderSourceCode, const char* fragmentShaderSourceCode) {\n\t// Create the shaders\n\tGLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);\n\tGLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);\n\n\tGLint Result = GL_FALSE;\n\tint InfoLogLength;\n\n\t// Compile Vertex Shader\n\tprintf(\"Compiling vertex shader\\n\");\n\tglShaderSource(VertexShaderID, 1, &vertexShaderSourceCode , NULL);\n\tglCompileShader(VertexShaderID);\n\n\t// Check Vertex Shader\n\tglGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);\n\tglGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);\n\tif ( InfoLogLength > 0 ){\n\t\tstd::vector<char> VertexShaderErrorMessage(InfoLogLength+1);\n\t\tglGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);\n\t\tprintf(\"%s\\n\", &VertexShaderErrorMessage[0]);\n\t}\n\n\t// Compile Fragment Shader\n\tprintf(\"Compiling fragment shader\\n\");\n\tglShaderSource(FragmentShaderID, 1, &fragmentShaderSourceCode , NULL);\n\tglCompileShader(FragmentShaderID);\n\n\t// Check Fragment Shader\n\tglGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);\n\tglGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);\n\tif ( InfoLogLength > 0 ){\n\t\tstd::vector<char> FragmentShaderErrorMessage(InfoLogLength+1);\n\t\tglGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);\n\t\tprintf(\"%s\\n\", &FragmentShaderErrorMessage[0]);\n\t}\n\n\t// Link the program\n\tprintf(\"Linking program\\n\");\n\tGLuint ProgramID = glCreateProgram();\n\tglAttachShader(ProgramID, VertexShaderID);\n\tglAttachShader(ProgramID, FragmentShaderID);\n\tglLinkProgram(ProgramID);\n\n\t// Check the program\n\tglGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);\n\tglGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);\n\tif ( InfoLogLength > 0 ){\n\t\tstd::vector<char> ProgramErrorMessage(InfoLogLength+1);\n\t\tglGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);\n\t\tprintf(\"%s\\n\", &ProgramErrorMessage[0]);\n\t}\n\t\n\tglDetachShader(ProgramID, VertexShaderID);\n\tglDetachShader(ProgramID, FragmentShaderID);\n\t\n\tglDeleteShader(VertexShaderID);\n\tglDeleteShader(FragmentShaderID);\n\n\treturn ProgramID;\n}\n\nclass RenderShader {\n\tGLuint programID;\n\n\tGLuint modelMatrixID;\n\tGLuint pvMatrixID;\n\tGLuint lightDirectionID;\n\tGLuint partColorID;\n\npublic:\n\tRenderShader() {\n\t\tGLuint programID = loadShaders(basicVertexShader, basicFragmentShader);\n\t\tglUseProgram(programID);\n\t\t\n\t\tmodelMatrixID = glGetUniformLocation(programID, \"modelMatrix\");\n\t\tpvMatrixID = glGetUniformLocation(programID, \"pvMatrix\");\n\t\tlightDirectionID = glGetUniformLocation(programID, \"lightDirection\");\n\t\tpartColorID = glGetUniformLocation(programID, \"partColor\");\n\t}\n\tvoid setModelMatrix(Mat4f modelMatrix) {\n\t\tfloat modelData[16];\n\t\tmodelMatrix.toColMajorData(modelData);\n\t\tglUniformMatrix4fv(modelMatrixID, 1, GL_FALSE, modelData);\n\t}\n\tvoid setPVMatrix(Mat4f pvMatrix) {\n\t\tfloat pvData[16];\n\t\tpvMatrix.toColMajorData(pvData);\n\t\tglUniformMatrix4fv(pvMatrixID, 1, GL_FALSE, pvData);\n\t}\n\tvoid setLightDirection(Vec3f lightDirection) {\n\t\tglUniform3fv(lightDirectionID, 1, lightDirection.data);\n\t}\n\tvoid setPartColor(Color color) {\n\t\tglUniform3fv(partColorID, 1, color.data);\n\t}\n};\n\nclass ArrayMesh {\n\tGLuint vertexArrayID;\n\tGLuint vertexBuffer;\n\tGLuint normalsBuffer;\n\n\tsize_t triangleCount;\n\tconstexpr static GLuint INVALID = 0;\npublic:\n\tArrayMesh() : vertexArrayID(INVALID), vertexBuffer(INVALID), normalsBuffer(INVALID), triangleCount(0) {}\n\tArrayMesh(const float* vertexData, const float* normalsData, size_t triangleCount) : triangleCount(triangleCount) {\n\t\tglGenVertexArrays(1, &vertexArrayID);\n\t\tglBindVertexArray(vertexArrayID);\n\t\t// benerate buffers\n\t\tGLuint buffers[2];\n\t\tglGenBuffers(2, buffers);\n\t\tvertexBuffer = buffers[0];\n\t\tnormalsBuffer = buffers[1];\n\n\t\t// load vertices\n\t\tglBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);\n\t\tglBufferData(GL_ARRAY_BUFFER, triangleCount * 3 * 3 * sizeof(float), vertexData, GL_STATIC_DRAW);\n\n\t\t// load normals\n\t\tglBindBuffer(GL_ARRAY_BUFFER, normalsBuffer);\n\t\tglBufferData(GL_ARRAY_BUFFER, triangleCount * 3 * 3 * sizeof(float), normalsData, GL_STATIC_DRAW);\n\t}\n\t~ArrayMesh() {\n\t\tif(vertexArrayID != INVALID) {\n\t\t\tGLuint buffers[2]{vertexBuffer, normalsBuffer};\n\t\t\tglDeleteBuffers(2, buffers);\n\t\t\tglDeleteVertexArrays(1, &vertexArrayID);\n\t\t}\n\t}\n\tArrayMesh(ArrayMesh&) = delete;\n\tArrayMesh& operator=(ArrayMesh&) = delete;\n\tArrayMesh(ArrayMesh&& other) noexcept : \n\t\tvertexArrayID(other.vertexArrayID), \n\t\tvertexBuffer(other.vertexBuffer), \n\t\tnormalsBuffer(other.normalsBuffer), \n\t\ttriangleCount(other.triangleCount) {\n\t\t\n\t\tother.vertexArrayID = INVALID;\n\t\tother.vertexBuffer = INVALID;\n\t\tother.normalsBuffer = INVALID;\n\t}\n\tArrayMesh& operator=(ArrayMesh&& other) noexcept {\n\t\tstd::swap(this->vertexArrayID, other.vertexArrayID);\n\t\tstd::swap(this->vertexBuffer, other.vertexBuffer);\n\t\tstd::swap(this->normalsBuffer, other.normalsBuffer);\n\t\tstd::swap(this->triangleCount, other.triangleCount);\n\t\treturn *this;\n\t}\n\n\tvoid bind() const {\n\t\t// 1st attribute buffer : vertices\n\t\tglEnableVertexAttribArray(0);\n\t\tglBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);\n\t\tglVertexAttribPointer(\n\t\t\t0,                  // attribute 0. No particular reason for 0, but must match the layout in the shader.\n\t\t\t3,                  // size\n\t\t\tGL_FLOAT,           // type\n\t\t\tGL_FALSE,           // normalized?\n\t\t\t0,                  // stride\n\t\t\t(void*)0            // array buffer offset\n\t\t);\n\n\t\t// 2nd attribute buffer : normals\n\t\tglEnableVertexAttribArray(1);\n\t\tglBindBuffer(GL_ARRAY_BUFFER, normalsBuffer);\n\t\tglVertexAttribPointer(\n\t\t\t1,                                // attribute. No particular reason for 1, but must match the layout in the shader.\n\t\t\t3,                                // size\n\t\t\tGL_FLOAT,                         // type\n\t\t\tGL_TRUE,                          // normalized?\n\t\t\t0,                                // stride\n\t\t\t(void*)0                          // array buffer offset\n\t\t);\n\t}\n\tvoid unbind() const {\n\t\tglDisableVertexAttribArray(0);\n\t\tglDisableVertexAttribArray(1);\n\t}\n\tvoid render() const {\n\t\tglDrawArrays(GL_TRIANGLES, 0, 3 * triangleCount);\n\t}\n};\n\n/*\n\tTo optimally reuse our ArrayMeshes so we don't use too much vram, we create just one arrayMesh for each ShapeClass. \n\tAll Parts (no matter the size / scale) that have the same underlying ShapeClass will get the same ArrayMesh index. \n\tThis class manages the conversion and registration of these meshes. \n*/\nclass MeshRegistry {\n\tstd::vector<const ShapeClass*> knownShapeClasses;\n\tstd::vector<ArrayMesh> meshes;\n\n\tint findKnownShapeClassIndex(const ShapeClass* shapeClass) {\n\t\tfor(size_t i = 0; i < knownShapeClasses.size(); i++) {\n\t\t\tif(knownShapeClasses[i] == shapeClass) {\n\t\t\t\treturn static_cast<int>(i);\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t}\npublic:\n\tint registerShapeClassMesh(const ShapeClass* shapeClass, ArrayMesh&& mesh) {\n\t\tknownShapeClasses.push_back(shapeClass);\n\t\tmeshes.push_back(std::move(mesh));\n\t\treturn static_cast<int>(meshes.size() - 1);\n\t}\n\tint getMeshIndexFor(const ShapeClass* shapeClass) {\n\t\tfor(size_t i = 0; i < knownShapeClasses.size(); i++) {\n\t\t\tif(knownShapeClasses[i] == shapeClass) {\n\t\t\t\treturn static_cast<int>(i);\n\t\t\t}\n\t\t}\n\t\tPolyhedron shapeClassPolyhedron = shapeClass->asPolyhedron();\n\t\tVec3f* vertexBuf = new Vec3f[shapeClassPolyhedron.triangleCount * 3];\n\t\tVec3f* normalBuf = new Vec3f[shapeClassPolyhedron.triangleCount * 3];\n\t\tfor(int i = 0; i < shapeClassPolyhedron.triangleCount; i++) {\n\t\t\tTriangle t = shapeClassPolyhedron.getTriangle(i);\n\t\t\tvertexBuf[i*3+0] = shapeClassPolyhedron.getVertex(t.firstIndex);\n\t\t\tvertexBuf[i*3+1] = shapeClassPolyhedron.getVertex(t.secondIndex);\n\t\t\tvertexBuf[i*3+2] = shapeClassPolyhedron.getVertex(t.thirdIndex);\n\n\t\t\tVec3f normal = normalize(shapeClassPolyhedron.getNormalVecOfTriangle(t));\n\t\t\tnormalBuf[i*3+0] = normal;\n\t\t\tnormalBuf[i*3+1] = normal;\n\t\t\tnormalBuf[i*3+2] = normal;\n\t\t}\n\t\tArrayMesh arMesh(reinterpret_cast<float*>(vertexBuf), reinterpret_cast<float*>(normalBuf), shapeClassPolyhedron.triangleCount);\n\t\tdelete[] vertexBuf;\n\t\tdelete[] normalBuf;\n\t\treturn registerShapeClassMesh(shapeClass, std::move(arMesh));\n\t}\n\tconst ArrayMesh& operator[](int meshIndex) const {\n\t\treturn meshes[meshIndex];\n\t}\n};\n\nMeshRegistry meshRegistry;\n\nclass CustomPart : public Part {\npublic:\n\t// This index is the visual shape of the part, it indexes into MeshRegistry to find the proper ArrayMesh to draw. \n\t// For ease this is generated from the base shape's shapeClass. \n\tint meshIndex;\n\tColor color;\n\n\tCustomPart(const Shape& shape, const GlobalCFrame& position, const PartProperties& properties, int meshIndex, Color color) : \n\t\tPart(shape, position, properties), meshIndex(meshIndex), color(color) {}\n\n\tCustomPart(const Shape& shape, const GlobalCFrame& position, const PartProperties& properties, Color color) : \n\t\tPart(shape, position, properties), meshIndex(meshRegistry.getMeshIndexFor(shape.baseShape.get())), color(color) {}\n};\n\nvoid render(World<CustomPart>& world, UpgradeableMutex& worldMutex, RenderShader& shader) {\n\tMat4f viewMatrix = lookAt(Vec3f(12.0f, 6.0f, 15.0f), Vec3f(0.0f, 0.0f, 0.0f), Vec3f(0.0f, 1.0f, 0.0f));\n\tMat4f projectionMatrix = perspective(0.8f, 4.0f/3.0f, 0.1f, 100.0f);\n\n\tshader.setPVMatrix(projectionMatrix * viewMatrix);\n\n\t// multithreaded application, must use synchronization with PhysicsThread\n\tstd::shared_lock<UpgradeableMutex> worldReadLock(worldMutex);\n\tworld.forEachPart([&](const CustomPart& part) {\n\t\tconst ArrayMesh& mesh = meshRegistry[part.meshIndex];\n\t\tmesh.bind();\n\n\t\tshader.setPartColor(part.color);\n\t\tshader.setModelMatrix(part.getCFrame().asMat4WithPreScale(part.hitbox.scale));\n\t\tmesh.render();\n\n\t\tmesh.unbind();\n\t});\n}\n\nint main(int argc, const char** argv) {\n\tstd::cout << \"Starting Physics3D Demo\" << std::endl;\n\tGLFWwindow* window = initWindow();\n\tif(!window) return -1;\n\n\t// Enable depth test\n\tglEnable(GL_DEPTH_TEST);\n\t// Accept fragment if it closer to the camera than the former one\n\tglDepthFunc(GL_LESS);\n\n\t// Add face culling\n\tglEnable(GL_CULL_FACE);\n\tglCullFace(GL_BACK);\n\n\tglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n\n\tRenderShader shader;\n\n\t// World constructor accepts the tick delay. This code creates a world to run at 100 TPS. \n\tWorld<CustomPart> world(1 / 100.0);\n\tUpgradeableMutex worldMutex;\n\t\n\tPartProperties basicProperties;\n\tbasicProperties.density = 1.0;\n\tbasicProperties.friction = 0.5;\n\tbasicProperties.bouncyness = 0.4;\n\t\n\t// We must manage Part memory ourselves. World is simply a Part* container. \n\tstd::unique_ptr<CustomPart> floor = std::make_unique<CustomPart>(\n\t\tboxShape(20.0, 0.5, 20.0), \n\t\tGlobalCFrame(0.0, -2.0, 0.0), \n\t\tbasicProperties, \n\t\tColors::WHITE);\n\tstd::unique_ptr<CustomPart> wall = std::make_unique<CustomPart>(\n\t\tboxShape(3.0, 1.0, 10.0), \n\t\tGlobalCFrame(7.0, -2.0, 0.0, Rotation::fromEulerAngles(0.0, 0.0, 0.2)), \n\t\tbasicProperties, \n\t\tColors::GRAY);\n\tstd::unique_ptr<CustomPart> box = std::make_unique<CustomPart>(\n\t\tboxShape(2.0, 0.5, 3.0), \n\t\tGlobalCFrame(0.0, 1.3, 1.0, Rotation::fromEulerAngles(0.2, 0.1, 0.3)), \n\t\tbasicProperties, \n\t\tColors::BLUE);\n\tstd::unique_ptr<CustomPart> sphere = std::make_unique<CustomPart>(\n\t\tsphereShape(1.0), \n\t\tGlobalCFrame(1.4, 4.7, 1.0), \n\t\tbasicProperties, \n\t\tColors::GREEN);\n\tstd::unique_ptr<CustomPart> icosahedron = std::make_unique<CustomPart>(\n\t\tpolyhedronShape(ShapeLibrary::icosahedron), \n\t\tGlobalCFrame(4.0, 1.3, 4.0), \n\t\tbasicProperties, \n\t\tColors::RED);\n\t\n\tworld.addTerrainPart(floor.get());\n\tworld.addTerrainPart(wall.get());\n\tworld.addPart(box.get());\n\tworld.addPart(sphere.get());\n\tworld.addPart(icosahedron.get());\n\n\t// We can set part velocities and other properties. \n\ticosahedron->setAngularVelocity(Vec3(5.0, 5.0, 0.0));\n\n\t// External Force memory is also not managed by the engine. \n\tstd::unique_ptr<DirectionalGravity> gravity = std::make_unique<DirectionalGravity>(Vec3(0.0, -10.0, 0.0));\n\tworld.addExternalForce(gravity.get());\n\n\tPhysicsThread physicsThread(&world, &worldMutex);\n\tphysicsThread.start();\n\n\tshader.setLightDirection(normalize(Vec3f(0.4f, -1.0f, 0.2f)));\n\n\t// render loop\n\tdo {\n\t\t// Clear the screen. \n\t\tglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n\n\t\trender(world, worldMutex, shader);\n\n\t\t// Swap buffers\n\t\tglfwSwapBuffers(window);\n\t\tglfwPollEvents();\n\t\n\t// Check if the ESC key was pressed or the window was closed \n\t} while(glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS && glfwWindowShouldClose(window) == 0);\n\n\treturn 0;\n}\n"
  },
  {
    "path": "graphics/batch/batch.h",
    "content": "#pragma once\n\n#include \"batchConfig.h\"\n\n#include \"../buffers/vertexArray.h\"\n#include \"../buffers/vertexBuffer.h\"\n#include \"../buffers/indexBuffer.h\"\n\n#include \"../renderer.h\"\n\nnamespace P3D::Graphics {\n\ntemplate<typename Vertex>\nclass Batch {\nprotected:\n\tVertexArray* vao = nullptr;\n\tVertexBuffer* vbo = nullptr;\n\tIndexBuffer* ibo = nullptr;\n\n\tBatchConfig config;\n\n\tstd::vector<Vertex> vertexBuffer;\n\tstd::vector<unsigned int> indexBuffer;\n\n\tsize_t indexCounter;\n\npublic:\n\tVertex* vertexPointer;\n\tunsigned int* indexPointer;\n\tsize_t currentIndex;\n\n\tBatch(const BatchConfig& config) : config(config) {\n\t\tvao = new VertexArray();\n\t\tvbo = new VertexBuffer(config.bufferLayout, nullptr, 0);\n\t\tibo = new IndexBuffer(nullptr, 0);\n\n\t\tvao->addBuffer(vbo);\n\n\t\tvertexPointer = vertexBuffer.data();\n\t\tindexPointer = indexBuffer.data();\n\n\t\tindexCounter = 0;\n\t\tcurrentIndex = 0;\n\t};\n\n\tBatch(const Batch&) = delete;\n\n\tBatch& operator=(const Batch&) = delete;\n\n\t~Batch() {\n\t\tclose();\n\t}\n\n\tBatch(Batch&& other) {\n\t\tvao = other.vao;\n\t\tother.vao = nullptr;\n\n\t\tvbo = other.vbo;\n\t\tother.vbo = nullptr;\n\n\t\tibo = other.ibo;\n\t\tother.ibo = nullptr;\n\n\t\tindexCounter = other.indexCounter;\n\t\tother.indexCounter = 0;\n\n\t\tcurrentIndex = other.currentIndex;\n\t\tother.currentIndex = 0;\n\n\t\tvertexBuffer = std::move(other.vertexBuffer);\n\t\tother.vertexBuffer.clear();\n\n\t\tindexBuffer = std::move(other.indexBuffer);\n\t\tother.indexBuffer.clear();\n\n\t\tvertexPointer = other.vertexPointer;\n\t\tother.vertexPointer = other.vertexBuffer.data();\n\n\t\tindexPointer = other.indexPointer;\n\t\tother.indexPointer = other.indexBuffer.data();\n\n\t\tconfig = std::move(other.config);\n\t}\n\n\tBatch& operator=(Batch&& other) {\n\t\tif (this != &other) {\n\t\t\tclose();\n\t\t\tstd::swap(vao, other.vao);\n\t\t\tstd::swap(vbo, other.vbo);\n\t\t\tstd::swap(ibo, other.ibo);\n\n\t\t\tconfig = std::move(other.config);\n\t\t\tvertexBuffer = std::move(other.vertexBuffer);\n\t\t\tindexBuffer = std::move(other.indexBuffer);\n\n\t\t\tindexCounter = std::move(other.indexCounter);\n\t\t\tcurrentIndex = std::move(other.currentIndex);\n\n\t\t\tvertexPointer = std::move(other.vertexPointer);\n\t\t\tindexPointer = std::move(other.indexPointer);\n\t\t}\n\n\t\treturn *this;\n\t}\n\n\tinline void pushVertex(Vertex vertex) {\n\t\t*vertexPointer++ = vertex;\n\t\tindexCounter++;\n\t}\n\n\tinline void pushVertices(std::initializer_list<Vertex> vertices) {\n\t\tfor (Vertex vertex : vertices) {\n\t\t\t*vertexPointer++ = vertex;\n\t\t\tindexCounter++;\n\t\t}\n\t}\n\n\tinline void pushIndex(size_t index) {\n\t\t*indexPointer++ = currentIndex + index;\n\t}\n\n\tinline void pushIndices(std::initializer_list<size_t> indices) {\n\t\tfor (size_t index : indices)\n\t\t\t*indexPointer++ = currentIndex + index;\n\t}\n\n\tvoid reserve(size_t vertexCount, size_t indexCount) {\n\t\tsize_t oldVertexBufferSize = vertexBuffer.size();\n\t\tvertexBuffer.resize(oldVertexBufferSize + vertexCount);\n\t\tvertexPointer = vertexBuffer.data() + oldVertexBufferSize;\n\n\t\tsize_t oldIndexBufferSize = indexBuffer.size();\n\t\tindexBuffer.resize(oldIndexBufferSize + indexCount);\n\t\tindexPointer = indexBuffer.data() + oldIndexBufferSize;\n\t}\n\n\tvoid endIndex() {\n\t\tcurrentIndex += indexCounter;\n\t\tindexCounter = 0;\n\t}\n\n\tvirtual void submit() {\n\t\tvao->bind();\n\n\t\tvbo->fill((const void*) vertexBuffer.data(), vertexBuffer.size() * sizeof(Vertex), Graphics::Renderer::STREAM_DRAW);\n\t\tibo->fill((const unsigned int*) indexBuffer.data(), indexBuffer.size(), Graphics::Renderer::STREAM_DRAW);\n\n\t\tGraphics::Renderer::drawElements(config.type, indexBuffer.size(), Graphics::Renderer::UINT, nullptr);\n\n\t\tvbo->unbind();\n\t\tibo->unbind();\n\t\tvao->unbind();\n\n\t\tclear();\n\t}\n\n\tvoid clear() {\n\t\tvertexBuffer.clear();\n\t\tindexBuffer.clear();\n\n\t\tvertexPointer = vertexBuffer.data();\n\t\tindexPointer = indexBuffer.data();\n\n\t\tcurrentIndex = 0;\n\t\tindexCounter = 0;\n\t}\n\n\tvoid close() {\n\t\tclear();\n\n\t\tvao->close();\n\t\tvbo->close();\n\t\tibo->close();\n\t}\n};\n\n};"
  },
  {
    "path": "graphics/batch/batchConfig.h",
    "content": "#pragma once\n\n#include \"../buffers/bufferLayout.h\"\n\nnamespace P3D::Graphics {\n\nstruct BatchConfig {\n\t// Layout of the vertex buffer\n\tBufferLayout bufferLayout;\n\t// Primitive type\n\tunsigned int type;\n\n\tBatchConfig(BufferLayout bufferLayout, unsigned int type) : bufferLayout(bufferLayout), type(type) {};\n};\n\n};"
  },
  {
    "path": "graphics/batch/commandBatch.h",
    "content": "#pragma once\n\n#include \"batch.h\"\n\n#include \"../shader/shader.h\"\n\nnamespace P3D::Graphics {\n\ntemplate<typename Vertex, typename Command>\nclass CommandBatch : public Batch<Vertex> {\nprotected:\n\tstd::vector<Command> commandBuffer;\n\n\tsize_t currentIndexOffset;\npublic:\n\tCommandBatch(BatchConfig config) : Batch<Vertex>(config), currentIndexOffset(0) {\n\n\t}\n\n\tvirtual void pushCommand(Command command) {\n\t\tsize_t count = Batch<Vertex>::indexBuffer.size() - currentIndexOffset;\n\n\t\tif (count == 0)\n\t\t\treturn;\n\n\t\tcommandBuffer.push_back(command);\n\t\tcurrentIndexOffset += count;\n\t}\n\n\tvirtual void submit() {\n\n\t};\n\n\tvirtual void clear() {\n\t\tcurrentIndexOffset = 0;\n\t\tBatch<Vertex>::clear();\n\t\tcommandBuffer.clear();\n\t}\n};\n\n};"
  },
  {
    "path": "graphics/batch/guiBatch.h",
    "content": "#pragma once\n\n#include \"commandBatch.h\"\n#include \"batchConfig.h\"\n#include \"../gui/color.h\"\n#include \"../buffers/bufferLayout.h\"\n#include \"../shader/shaders.h\"\n\nnamespace P3D::Graphics {\n\nstruct GuiCommand {\n\t// Amount of indices to render\n\tsize_t count;\n\t// Optional texture ID\n\tGLID textureID;\n\t// Offset in index buffer\n\tsize_t indexOffset;\n};\n\nstruct GuiVertex {\n\tVec2f pos;\n\tVec2f uv;\n\tColor col;\n};\n\nclass GuiBatch : public CommandBatch<GuiVertex, GuiCommand> {\npublic:\n\tGuiBatch() : CommandBatch<GuiVertex, GuiCommand>(\n\t\tBatchConfig(\n\t\t\tBufferLayout({\n\t\t\t\tBufferElement(\"pos\", BufferDataType::FLOAT2),\n\t\t\t\tBufferElement(\"uv\", BufferDataType::FLOAT2),\n\t\t\t\tBufferElement(\"col\", BufferDataType::FLOAT4)\n\t\t\t}),\n\t\t\tRenderer::TRIANGLES\n\t\t)) {\n\n\t}\n\n\tvoid pushCommand(GLID textureID) {\n\t\tsize_t count = Batch<GuiVertex>::indexBuffer.size() - currentIndexOffset;\n\n\t\tif (count == 0)\n\t\t\treturn;\n\n\t\tGuiCommand command = { count, textureID, currentIndexOffset };\n\n\t\tCommandBatch<GuiVertex, GuiCommand>::pushCommand(command);\n\t}\n\n\tvoid submit() override {\n\t\tShaders::guiShader->bind();\n\n\t\tif (commandBuffer.empty()) \n\t\t\tpushCommand(0);\n\n\t\tBatch<GuiVertex>::vao->bind();\n\n\t\tBatch<GuiVertex>::vbo->fill((const void*) Batch<GuiVertex>::vertexBuffer.data(), Batch<GuiVertex>::vertexBuffer.size() * sizeof(GuiVertex), Renderer::STREAM_DRAW);\n\t\tBatch<GuiVertex>::ibo->fill((const unsigned int*) Batch<GuiVertex>::indexBuffer.data(), Batch<GuiVertex>::indexBuffer.size(), Renderer::STREAM_DRAW);\n\n\t\tGLID lastID = -1;\n\t\tsize_t lastCount = 0;\n\t\tsize_t lastIndexOffset = 0;\n\n\t\tfor (const GuiCommand& command : commandBuffer) {\n\t\t\tGLID ID = command.textureID;\n\t\t\tsize_t count = command.count;\n\t\t\tsize_t indexOffset = command.indexOffset;\n\n\t\t\tif (ID == lastID) {\n\t\t\t\t// merge calls, no shader update\n\t\t\t\tlastCount += count;\n\t\t\t} else {\n\t\t\t\t// render merged calls, shader update, texture bind, render this call\n\t\t\t\tRenderer::drawElements(Renderer::TRIANGLES, lastCount, Renderer::UINT, (const void*) (intptr_t) (lastIndexOffset * sizeof(unsigned int)));\n\n\t\t\t\t// update shader\n\t\t\t\tif (ID == 0) {\n\t\t\t\t\tShaders::guiShader->setTextured(false);\n\t\t\t\t} else {\n\t\t\t\t\tRenderer::bindTexture2D(ID);\n\t\t\t\t\tShaders::guiShader->setTextured(true);\n\t\t\t\t}\n\n\t\t\t\tlastCount = count;\n\t\t\t\tlastIndexOffset = indexOffset;\n\t\t\t}\n\n\t\t\t// update last ID\n\t\t\tlastID = ID;\n\t\t}\n\n\t\tRenderer::drawElements(Renderer::TRIANGLES, lastCount, Renderer::UINT, (const void*) (intptr_t) (lastIndexOffset * sizeof(unsigned int)));\n\n\t\tBatch<GuiVertex>::vbo->unbind();\n\t\tBatch<GuiVertex>::ibo->unbind();\n\t\tBatch<GuiVertex>::vao->unbind();\n\n\t\tclear();\n\t}\n\n\tvoid clear() {\n\t\tcurrentIndexOffset = 0;\n\t\tBatch<GuiVertex>::clear();\n\t\tcommandBuffer.clear();\n\t}\n};\n\n};"
  },
  {
    "path": "graphics/batch/instanceBatch.h",
    "content": "#pragma once\n\n#include <vector>\n#include <map>\n#include <set>\n\n#include \"../renderer.h\"\n#include \"../mesh/indexedMesh.h\"\n#include \"../buffers/bufferLayout.h\"\n#include \"../meshRegistry.h\"\n#include \"graphics/debug/guiDebug.h\"\n#include \"shader/shaders.h\"\n#include \"util/stringUtil.h\"\n#include \"util/systemVariables.h\"\n\nnamespace P3D::Graphics {\n\nclass InstanceBatch {\npublic:\n\tstruct Uniform {\n\t\tMat4f modelMatrix = Mat4f::IDENTITY();\n\t\tVec4f albedo = Vec4f::full(1.0f);\n\t\tfloat metalness = 1.0f;\n\t\tfloat roughness = 1.0f;\n\t\tfloat ao = 1.0f;\n\t\tunsigned textureFlags1;\n\t\tunsigned textureFlags2;\n\t};\n\nprivate:\n\tstd::size_t mesh = -1;\n\tstd::vector<Uniform> uniformBuffer;\n\tstd::map<GLID, unsigned> textureBuffer;\n\npublic:\n\tInstanceBatch(std::size_t id, const BufferLayout& uniformBufferLayout) : mesh(id) {\n\t\tif (id >= MeshRegistry::meshes.size()) {\n\t\t\tLog::error(\"Creating an instance batch for an invalid mesh: %d\", id);\n\t\t\treturn;\n\t\t}\n\n\t\tif (MeshRegistry::get(id)->uniformBuffer == nullptr) {\n\t\t\tVertexBuffer* uniformBuffer = new VertexBuffer(uniformBufferLayout, nullptr, 0);\n\t\t\tMeshRegistry::get(id)->addUniformBuffer(uniformBuffer);\n\t\t}\t\n\t}\n\n\t~InstanceBatch() = default;\n\tInstanceBatch(const InstanceBatch&) = default;\n\tInstanceBatch(InstanceBatch&&) noexcept = default;\n\tInstanceBatch& operator=(const InstanceBatch&) = default;\n\tInstanceBatch& operator=(InstanceBatch&&) noexcept = default;\n\n\tbool add(const Mat4f& modelMatrix, const Comp::Material& material) {\n\t\tusing namespace Comp;\n\n\t\tstd::uint64_t textureFlags = 0;\n\t\tint textureCount = material.getTextureCount();\n\t\tif (textureCount > 0) {\n\t\t\tint maxTextures = SystemVariables::get(\"MAX_TEXTURE_IMAGE_UNITS\");\n\t\t\tint remainingTextures = maxTextures - static_cast<int>(textureBuffer.size());\n\n\t\t\t// Check if buffer is full\n\t\t\tif (textureCount > remainingTextures) {\n\t\t\t\t// Get all new textures\n\t\t\t\tstd::set<GLID> newTextures;\n\t\t\t\tfor (std::size_t index = 0; index < Material::MAP_COUNT; index++) {\n\t\t\t\t\tSRef<Texture> texture = material.get(index);\n\t\t\t\t\tif (texture == nullptr)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tif (textureBuffer.find(texture->getID()) == textureBuffer.end())\n\t\t\t\t\t\tnewTextures.insert(texture->getID());\n\t\t\t\t}\n\n\t\t\t\t// Fail if there is not enough space\n\t\t\t\tif (static_cast<int>(newTextures.size()) > remainingTextures)\n\t\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Add all IDs\n\t\t\tfor (std::size_t index = 0; index < Material::MAP_COUNT; index++) {\n\t\t\t\tSRef<Texture> texture = material.get(index);\n\t\t\t\tif (texture == nullptr)\n\t\t\t\t\tcontinue;\n\n\t\t\t\taddTexture(texture->getID());\n\t\t\t}\n\n\t\t\t// Create texture flag\n\t\t\tfor (std::size_t index = 0; index < Material::MAP_COUNT; index++) {\n\t\t\t\ttextureFlags <<= 8;\n\t\t\t\tSRef<Texture> texture = material.get(index);\n\t\t\t\tif (texture != nullptr)\n\t\t\t\t\ttextureFlags |= static_cast<std::uint64_t>(textureBuffer[texture->getID()] + 1u);\n\t\t\t}\n\t\t}\n\n\t\tUniform uniform {\n\t\t\tmodelMatrix,\n\t\t\tmaterial.albedo,\n\t\t\tmaterial.metalness,\n\t\t\tmaterial.roughness,\n\t\t\tmaterial.ao,\n\t\t\tstatic_cast<unsigned>(textureFlags >> 32),\n\t\t\tstatic_cast<unsigned>(textureFlags & 0xFFFFFFFF)\n\t\t};\n\n\t\tuniformBuffer.push_back(uniform);\n\t\t\n\t\treturn true;\n\t}\n\n\tvoid addTexture(GLID id) {\n\t\tauto iterator = textureBuffer.find(id);\n\t\tif (iterator == textureBuffer.end())\n\t\t\ttextureBuffer[id] = static_cast<int>(textureBuffer.size());\n\t}\n\n\tvoid bindTextures() {\n\t\tfor (auto [id, unit] : textureBuffer) {\n\t\t\tRenderer::activeTexture(unit);\n\t\t\tRenderer::bindTexture2D(id);\n\t\t}\n\t}\n\n\tvoid submit() {\n\t\tif (mesh >= MeshRegistry::meshes.size()) {\n\t\t\tLog::error(\"Trying to sumbit a mesh that has not been registered in the mesh registry\");\n\t\t\treturn;\n\t\t}\n\n\t\tif (uniformBuffer.empty())\n\t\t\treturn;\n\n\t\t// Bind textures\n\t\tif (!textureBuffer.empty())\n\t\t\tbindTextures();\n\n\t\t// Draw meshes\n\t\tMeshRegistry::get(mesh)->fillUniformBuffer(uniformBuffer.data(), uniformBuffer.size() * sizeof(Uniform), Renderer::STREAM_DRAW);\n\t\tMeshRegistry::get(mesh)->renderInstanced(uniformBuffer.size());\n\n\t\tclear();\n\t}\n\n\tvoid clear() {\n\t\tuniformBuffer.clear();\n\t}\n};\n\n};"
  },
  {
    "path": "graphics/batch/instanceBatchManager.h",
    "content": "#pragma once\n\n#include <unordered_map>\n\n#include \"instanceBatch.h\"\n#include \"../util/log.h\"\n#include \"../shader/shader.h\"\n#include \"../buffers/bufferLayout.h\"\n\nnamespace P3D::Graphics {\n\nclass InstanceBatchManager {\nprivate:\n\tSRef<Shader> shader;\n\tBufferLayout uniformBufferLayout;\n\tstd::unordered_map<std::size_t, std::vector<InstanceBatch>> batches;\n\npublic:\n\tInstanceBatchManager(SRef<Shader> shader, const BufferLayout& uniformBufferLayout) : shader(shader), uniformBufferLayout(uniformBufferLayout) {}\n\n\tvoid add(std::size_t mesh, const Mat4f& modelMatrix, const Comp::Material& material) {\n\t\tif (mesh >= MeshRegistry::meshes.size()) {\n\t\t\tLog::error(\"Trying to add a mesh that has not been registered in the mesh registry\");\n\t\t\treturn;\n\t\t}\n\n\t\tauto batchIterator = batches.find(mesh);\n\t\tif (batchIterator == batches.end())\n\t\t\tbatchIterator = batches.emplace(mesh, std::vector { InstanceBatch(mesh, uniformBufferLayout) }).first;\n\n\t\tstd::vector<InstanceBatch>& currentBatches = batchIterator->second;\n\t\tInstanceBatch& currentBatch = currentBatches[currentBatches.size() - 1];\n\t\tbool success = currentBatch.add(modelMatrix, material);\n\n\t\tif (!success) {\n\t\t\tInstanceBatch newBatch(mesh, uniformBufferLayout);\n\t\t\tnewBatch.add(modelMatrix, material);\n\n\t\t\tcurrentBatches.push_back(newBatch);\n\t\t}\n\t}\t\t\t\t\t\t\t\t\t  \n\n\tvoid submit(std::size_t mesh) {\n\t\tshader->bind();\n\n\t\tauto iterator = batches.find(mesh);\n\t\tif (iterator != batches.end()) \n\t\t\tfor (InstanceBatch& batch : iterator->second)\n\t\t\t\tbatch.submit();\n\t}\n\n\tvoid submit() {\n\t\tshader->bind();\n\n\t\tfor (auto& [mesh, batches] : this->batches)\n\t\t\tfor (auto& batch : batches)\n\t\t\t\tbatch.submit();\n\t}\n\n\tvoid clear() {\n\t\tfor (auto& [mesh, batches] : this->batches)\n\t\t\tfor (auto& batch : batches)\n\t\t\t\tbatch.clear();\n\t}\n};\n\n};"
  },
  {
    "path": "graphics/bindable.cpp",
    "content": "#include \"core.h\"\n\n#include \"bindable.h\"\n\nnamespace P3D::Graphics {\n\nBindable::Bindable() : id(0) {}\n\nBindable::Bindable(GLID id) : id(id) {}\n\nGLID Bindable::getID() const {\n\treturn id;\n}\n\n};"
  },
  {
    "path": "graphics/bindable.h",
    "content": "#pragma once\n\ntypedef unsigned int GLID;\n\nnamespace P3D::Graphics {\n\nclass Bindable {\nprotected:\n\tGLID id;\n\n\tBindable();\n\tBindable(GLID id);\n\npublic:\n\t[[nodiscard]] GLID getID() const;\n\n\tvirtual void bind() = 0;\n\tvirtual void unbind() = 0;\n\tvirtual void close() = 0;\n};\n\n};"
  },
  {
    "path": "graphics/buffers/bufferLayout.cpp",
    "content": "#include \"core.h\"\n\n#include \"bufferLayout.h\"\n\n#include <GL/glew.h>\n\nnamespace P3D::Graphics {\n\nnamespace BufferDataType {\n\nconst Info NONE   = { \"none\"  , 0\t\t\t\t, 0, 0, false };\nconst Info BOOL   = { \"bool\"  , GL_BYTE\t\t\t, 1, 1, true };\nconst Info UINT   = { \"uint\"  , GL_UNSIGNED_INT , 1, 4, true };\nconst Info UINT2  = { \"vec2u\" , GL_UNSIGNED_INT\t, 2, 8, true };\nconst Info UINT3  = { \"vec3u\" , GL_UNSIGNED_INT\t, 3, 12, true };\nconst Info UINT4  = { \"vec4u\" , GL_UNSIGNED_INT\t, 4, 16, true };\nconst Info INT    = { \"int\"   , GL_INT\t\t\t, 1, 4, true };\nconst Info INT2   = { \"vec2i\" , GL_INT\t\t\t, 2, 8, true };\nconst Info INT3   = { \"vec3i\" , GL_INT\t\t\t, 3, 12, true };\nconst Info INT4   = { \"vec4i\" , GL_INT\t\t\t, 4, 16, true };\nconst Info FLOAT  = { \"float\" , GL_FLOAT\t\t\t, 1, 4, false };\nconst Info FLOAT2 = { \"vec2\"  , GL_FLOAT\t\t\t, 2, 8, false };\nconst Info FLOAT3 = { \"vec3\"  , GL_FLOAT\t\t\t, 3, 12, false };\nconst Info FLOAT4 = { \"vec4\"  , GL_FLOAT\t\t\t, 4, 16, false };\nconst Info MAT2   = { \"mat2\"  , GL_FLOAT\t\t\t, 2, 8, false }; // per row\nconst Info MAT3   = { \"mat3\"  , GL_FLOAT\t\t\t, 3, 12, false }; // per row\nconst Info MAT4   = { \"mat4\"  , GL_FLOAT\t\t\t, 4, 16, false }; // per row\n\n}\n\n};"
  },
  {
    "path": "graphics/buffers/bufferLayout.h",
    "content": "#pragma once\n\nnamespace P3D::Graphics {\n\n#define DEFAULT_UNIFORM_BUFFER_LAYOUT \\\n\tBufferLayout({ \\\n\t\tBufferElement(\"vModelMatrix\", BufferDataType::MAT4, true), \\\n\t\tBufferElement(\"vAlbedo\", BufferDataType::FLOAT4, true), \\\n\t\tBufferElement(\"vMRAo\", BufferDataType::FLOAT3, true), \\\n\t\tBufferElement(\"vTextureFlags\", BufferDataType::UINT2, true) \\\n\t})\n\nnamespace BufferDataType {\n\n\tstruct Info {\n\t\t// name of data type\n\t\tstd::string name;\n\n\t\t// data type of each component\n\t\tint type;\n\n\t\t// amount of components per attributes\n\t\tint count;\n\n\t\t// size of type in bytes\n\t\tint size;\n\n\t\t// Whether the type is integral\n\t\tbool integral;\n\n\t\tInfo(const std::string& name, int type, int count, int size, bool integral)\n\t\t\t: name(name)\n\t\t\t, type(type)\n\t\t\t, count(count)\n\t\t\t, size(size)\n\t\t\t, integral(integral) {}\n\n\t\tbool operator==(const Info& other) const {\n\t\t\treturn other.name == name;\n\t\t}\n\t};\n\n\textern const Info NONE;\n\textern const Info BOOL;\n\textern const Info UINT;\n\textern const Info UINT2;\n\textern const Info UINT3;\n\textern const Info UINT4;\n\textern const Info INT;\n\textern const Info INT2;\n\textern const Info INT3;\n\textern const Info INT4;\n\textern const Info FLOAT;\n\textern const Info FLOAT2;\n\textern const Info FLOAT3;\n\textern const Info FLOAT4;\n\textern const Info MAT2;\n\textern const Info MAT3;\n\textern const Info MAT4;\n\n};\n\nstruct BufferElement {\n\tstd::string name;\n\tBufferDataType::Info info;\n\tbool instanced;\n\tbool normalized;\n\n\tBufferElement(const std::string& name, const BufferDataType::Info& info, bool instanced = false, bool normalized = false)\n\t\t: name(name)\n\t\t, info(info)\n\t\t, instanced(instanced)\n\t\t, normalized(normalized) {}\n};\n\nstruct BufferLayout {\n\tstd::vector<BufferElement> elements;\n\tint stride;\n\n\tBufferLayout(const std::vector<BufferElement>& elements)\n\t\t: elements(elements)\n\t\t, stride(0) {\n\t\tfor (BufferElement& element : this->elements) {\n\t\t\tint multiplier = (element.info == BufferDataType::MAT2 || element.info == BufferDataType::MAT3 || element.info == BufferDataType::MAT4)\n\t\t\t\t                 ? element.info.count\n\t\t\t\t                 : 1;\n\t\t\tstride += element.info.size * multiplier;\n\t\t}\n\t}\n\n\tBufferLayout()\n\t\t: elements({})\n\t\t, stride(0) {}\n};\n\n};\n"
  },
  {
    "path": "graphics/buffers/frameBuffer.cpp",
    "content": "#include \"core.h\"\n\n#include \"frameBuffer.h\"\n\n#include <GL/glew.h>\n#include <GLFW/glfw3.h>\n\n#include \"renderer.h\"\n#include \"renderBuffer.h\"\n#include \"texture.h\"\n\nnamespace P3D::Graphics {\n\n#pragma region FrameBuffer\n\n//! FrameBuffer\n\t\nFrameBuffer::FrameBuffer(unsigned int width, unsigned int height) {\n\tglGenFramebuffers(1, &id);\n\tbind();\n\t\n\ttexture = std::make_shared<Texture>(width, height);\n\trenderBuffer = std::make_shared<RenderBuffer>(width, height);\n\n\tattach(texture);\n\tattach(renderBuffer);\n\n\tif (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)\n\t\tLog::error(\"FrameBuffer object with id (%d) not complete\", id);\n\n\tunbind();\n}\n\nFrameBuffer::FrameBuffer(SRef<Texture> colorAttachment, SRef<RenderBuffer> depthStencilAttachment) {\n\tglGenFramebuffers(1, &id);\n\tbind();\n\t\n\tattach(colorAttachment);\n\tattach(depthStencilAttachment);\n\n\tif (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)\n\t\tLog::error(\"FrameBuffer object with id (%d) not complete\", id);\n\n\tunbind();\n}\n\nFrameBuffer::~FrameBuffer() {\n\tLog::warn(\"Closing framebuffer #%d\", id);\n\n\tglDeleteFramebuffers(1, &id);\n}\n\nvoid FrameBuffer::bind() {\n\tRenderer::bindFramebuffer(id);\n}\n\nvoid FrameBuffer::unbind() {\n\tRenderer::bindFramebuffer(0);\n}\n\nvoid FrameBuffer::resize(const Vec2i& dimension) {\n\tthis->dimension = dimension;\n\n\tif (texture)\n\t\ttexture->resize(dimension.x, dimension.y);\n\tif (renderBuffer)\n\t\trenderBuffer->resize(dimension.x, dimension.y);\n}\n\nvoid FrameBuffer::attach(SRef<Texture> texture) {\n\tbind();\n\tthis->texture = texture;\n\tglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->getID(), 0);\n}\n\nvoid FrameBuffer::attach(SRef<RenderBuffer> renderBuffer) {\n\tbind();\n\tthis->renderBuffer = renderBuffer;\n\tglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderBuffer->getID());\n}\n\nvoid FrameBuffer::close() {\n\t// TODO remove\n}\n\n#pragma endregion\n\n#pragma region FrameBuffer\n\n//! MainFrameBuffer\n\nMainFrameBuffer::MainFrameBuffer(unsigned int width, unsigned int height) : Bindable() {\n\tglGenFramebuffers(1, &id);\n\tbind();\n\t\n\tfragment = std::make_shared<HDRTexture>(width, height);\n\tglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fragment->getID(), 0);\n\n\tbrightness = std::make_shared<HDRTexture>(width, height);\n\tglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, brightness->getID(), 0);\n\n\trenderBuffer = std::make_shared<RenderBuffer>(width, height);\n\tglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderBuffer->getID());\n\n\tGLID attachements[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };\n\tglDrawBuffers(2, attachements);\n\n\tif (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)\n\t\tLog::error(\"FrameBuffer object with id (%d) not complete\", id);\n\n\tunbind();\n}\n\nMainFrameBuffer::~MainFrameBuffer() {\n\tLog::warn(\"Closing main framebuffer #%d\", id);\n\tglDeleteFramebuffers(1, &id);\n}\n\nvoid MainFrameBuffer::bind() {\n\tRenderer::bindFramebuffer(id);\n}\n\nvoid MainFrameBuffer::unbind() {\n\tRenderer::bindFramebuffer(0);\n}\n\nvoid MainFrameBuffer::resize(const Vec2i& dimension) {\n\tthis->dimension = dimension;\n\n\tfragment->resize(dimension.x, dimension.y);\n\tbrightness->resize(dimension.x, dimension.y);\n\trenderBuffer->resize(dimension.x, dimension.y);\n}\n\nvoid MainFrameBuffer::close() {\n\t// TODO remove\n}\n\n#pragma endregion\n\t\n#pragma region HDRFrameBuffer\n\n//! HDRFrameBuffer\n\nHDRFrameBuffer::HDRFrameBuffer(unsigned int width, unsigned int height) {\n\tglGenFramebuffers(1, &id);\n\tbind();\n\t\n\ttexture = std::make_shared<HDRTexture>(width, height);\n\tglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->getID(), 0);\n\n\trenderBuffer = std::make_shared<RenderBuffer>(width, height);\n\tglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderBuffer->getID());\n\n\tif (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)\n\t\tLog::error(\"FrameBuffer object with id (%d) not complete\", id);\n\n\tunbind();\n};\n\nHDRFrameBuffer::~HDRFrameBuffer() {\n\tLog::warn(\"Closing HDR framebuffer #%d\", id);\n\tglDeleteFramebuffers(1, &id);\n}\n\nvoid HDRFrameBuffer::resize(const Vec2i& dimension) {\n\tthis->dimension = dimension;\n\tif (texture)\n\t\ttexture->resize(dimension.x, dimension.y);\n\tif (renderBuffer)\n\t\trenderBuffer->resize(dimension.x, dimension.y);\n};\n\nvoid HDRFrameBuffer::bind() {\n\tRenderer::bindFramebuffer(id);\n};\n\nvoid HDRFrameBuffer::unbind() {\n\tRenderer::bindFramebuffer(0);\n};\n\nvoid HDRFrameBuffer::close() {\n\t// TODO remove\n};\n\n#pragma endregion\n\n#pragma region MultisampleFrameBuffer\n\n//! MultisampleFrameBuffer\n\nMultisampleFrameBuffer::MultisampleFrameBuffer(unsigned int width, unsigned int height, int samples)  {\n\tglGenFramebuffers(1, &id);\n\tbind();\n\n\ttexture = std::make_shared<MultisampleTexture>(width, height, samples);\n\tglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, texture->getID(), 0);\n\n\trenderBuffer = std::make_shared<MultisampleRenderBuffer>(width, height, samples);\n\tglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderBuffer->getID());\n\n\tif (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)\n\t\tLog::error(\"FrameBuffer object with id (%d) not complete\", id);\n\n\tunbind();\n};\n\nMultisampleFrameBuffer::~MultisampleFrameBuffer() {\n\tLog::warn(\"Closing multisample framebuffer #%d\", id);\n\tglDeleteFramebuffers(1, &id);\n}\n\nvoid MultisampleFrameBuffer::resize(const Vec2i& dimension) {\n\tthis->dimension = dimension;\n\t\n\tif (texture)\n\t\ttexture->resize(dimension.x, dimension.y);\n\tif (renderBuffer)\n\t\trenderBuffer->resize(dimension.x, dimension.y);\n};\n\nvoid MultisampleFrameBuffer::bind() {\n\tRenderer::bindFramebuffer(id);\n};\n\nvoid MultisampleFrameBuffer::unbind() {\n\tRenderer::bindFramebuffer(0);\n};\n\nvoid MultisampleFrameBuffer::close() {\n\t// TODO remove\n};\n\n#pragma endregion\n\n#pragma region DepthFrameBuffer\n\n//! DepthFrameBuffer\n\nDepthFrameBuffer::DepthFrameBuffer(unsigned int width, unsigned int height) : width(width), height(height) {\n\tglGenFramebuffers(1, &id);\n\tbind();\n\n\ttexture = std::make_shared<DepthTexture>(width, height);\n\tglFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texture->getID(), 0);\n\t\n\tglDrawBuffer(GL_NONE);\n\tglReadBuffer(GL_NONE);\n\t\n\tunbind();\n}\n\nDepthFrameBuffer::~DepthFrameBuffer() {\n\tLog::warn(\"Closing depth framebuffer #%d\", id);\n\n\tglDeleteFramebuffers(1, &id);\n}\n\nvoid DepthFrameBuffer::bind() {\n\tRenderer::bindFramebuffer(id);\n}\n\nvoid DepthFrameBuffer::unbind() {\n\tRenderer::bindFramebuffer(0);\n}\n\nvoid DepthFrameBuffer::close() {\n\t// TODO remove\n}\n\n#pragma endregion\n\n}"
  },
  {
    "path": "graphics/buffers/frameBuffer.h",
    "content": "#pragma once\n\n#include \"../bindable.h\"\n\nnamespace P3D::Graphics {\n\nclass Texture;\nclass RenderBuffer;\n\nclass FrameBuffer : public Bindable {\nprivate:\n\tFrameBuffer();\n\npublic:\n\tVec2i dimension;\n\n\tSRef<Texture> texture;\n\tSRef<RenderBuffer> renderBuffer;\n\n\tFrameBuffer(unsigned int width, unsigned int height);\n\tFrameBuffer(SRef<Texture> colorAttachment, SRef<RenderBuffer> depthStencilAttachment);\n\tvirtual ~FrameBuffer();\n\n\tvoid bind() override;\n\tvoid unbind() override;\n\tvoid close() override;\n\t\n\tvoid resize(const Vec2i& dimension);\n\tvoid attach(SRef<Texture> texture);\n\tvoid attach(SRef<RenderBuffer> renderBuffer);\n};\n\nclass MainFrameBuffer : public Bindable {\nprivate:\n\tMainFrameBuffer();\n\npublic:\n\tVec2i dimension;\n\n\tSRef<Texture> fragment;\n\tSRef<Texture> brightness;\n\tSRef<RenderBuffer> renderBuffer;\n\n\tMainFrameBuffer(unsigned int width, unsigned int height);\n\tvirtual ~MainFrameBuffer();\n\n\tvoid bind() override;\n\tvoid unbind() override;\n\tvoid close() override;\n\t\n\tvoid resize(const Vec2i& dimension);\n};\n\nclass HDRTexture;\n\nclass HDRFrameBuffer : public Bindable {\npublic:\n\tVec2i dimension;\n\n\tSRef<HDRTexture> texture;\n\tSRef<RenderBuffer> renderBuffer;\n\n\tHDRFrameBuffer();\n\tHDRFrameBuffer(unsigned int width, unsigned int height);\n\tvirtual ~HDRFrameBuffer();\n\t\n\tvoid bind() override;\n\tvoid unbind() override;\n\tvoid close() override;\n\n\tvoid resize(const Vec2i& dimension);\n};\n\n\nclass MultisampleTexture;\nclass MultisampleRenderBuffer;\n\nclass MultisampleFrameBuffer : public Bindable {\npublic:\n\tVec2i dimension;\n\n\tSRef<MultisampleTexture> texture;\n\tSRef<MultisampleRenderBuffer> renderBuffer;\n\n\tMultisampleFrameBuffer();\n\tMultisampleFrameBuffer(unsigned int width, unsigned int height, int samples);\n\t~MultisampleFrameBuffer();\n\n\tvoid bind() override;\n\tvoid unbind() override;\n\tvoid close() override;\n\n\tvoid resize(const Vec2i& dimension);\n};\n\nclass DepthTexture;\n\nclass DepthFrameBuffer : public Bindable {\npublic:\n\tunsigned int width;\n\tunsigned int height;\n\tSRef<DepthTexture> texture;\n\n\tDepthFrameBuffer(unsigned int width, unsigned int height);\n\t~DepthFrameBuffer();\n\n\tvoid bind() override;\n\tvoid unbind() override;\n\tvoid close() override;\n};\n\n};"
  },
  {
    "path": "graphics/buffers/indexBuffer.cpp",
    "content": "#include \"core.h\"\n\n#include \"indexBuffer.h\"\n\n#include <GL/glew.h>\n\nnamespace P3D::Graphics {\n\nIndexBuffer::IndexBuffer() : Bindable() {\n\tLog::debug(\"Created empty index buffer\");\n};\n\nIndexBuffer::IndexBuffer(const unsigned int* data, size_t size, GLFLAG mode) {\n\tglGenBuffers(1, &id);\n\tbind();\n\tif (size != 0)\n\t\tfill(data, size, mode);\n}\n\nIndexBuffer::IndexBuffer(const unsigned int* data, size_t size) : IndexBuffer(data, size, GL_STATIC_DRAW) {}\n\nIndexBuffer::~IndexBuffer() {\n\tclose();\n\tLog::warn(\"Deleted index buffer with id (%d)\", id);\n}\n\nIndexBuffer::IndexBuffer(IndexBuffer&& other) {\n\tid = other.id;\n\tother.id = 0;\n}\n\nIndexBuffer& IndexBuffer::operator=(IndexBuffer&& other) {\n\tif (this != &other) {\n\t\tclose();\n\t\tstd::swap(id, other.id);\n\t}\n\n\treturn *this;\n}\n\nvoid IndexBuffer::fill(const unsigned int* data, size_t size, GLFLAG mode) {\n\tbind();\n\tglBufferData(GL_ELEMENT_ARRAY_BUFFER, size * sizeof(unsigned int), data, mode);\n}\n\nvoid IndexBuffer::update(const unsigned int* data, size_t size, int offset) {\n\tbind();\n\tglBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, size * sizeof(unsigned int), data);\n}\n\nvoid IndexBuffer::bind() {\n\tglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, id);\n}\n\nvoid IndexBuffer::unbind() {\n\tglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n}\n\nvoid IndexBuffer::close() {\n\tunbind();\n\tglDeleteBuffers(1, &id);\n\tid = 0;\n}\n\n};"
  },
  {
    "path": "graphics/buffers/indexBuffer.h",
    "content": "#pragma once\n\n#include \"../bindable.h\"\n#include \"../renderer.h\"\n\nnamespace P3D::Graphics {\n\nclass IndexBuffer : public Bindable {\npublic:\n\tIndexBuffer();\n\tIndexBuffer(const unsigned int* data, size_t size, GLFLAG mode);\n\tIndexBuffer(const unsigned int* data, size_t size);\n\n\t~IndexBuffer();\n\tIndexBuffer(IndexBuffer&& other);\n\tIndexBuffer(const IndexBuffer&) = delete;\n\tIndexBuffer& operator=(IndexBuffer&& other);\n\tIndexBuffer& operator=(const IndexBuffer&) = delete;\n\n\tvoid fill(const unsigned int* data, size_t size, GLFLAG mode);\n\tvoid update(const unsigned int* data, size_t size, int offset);\n\n\tvoid bind() override;\n\tvoid unbind() override;\n\tvoid close() override;\n};\n\n};"
  },
  {
    "path": "graphics/buffers/renderBuffer.cpp",
    "content": "#include \"core.h\"\n\n#include \"renderBuffer.h\"\n\n#include <GL/glew.h>\n#include <GLFW/glfw3.h>\n\n#include \"renderer.h\"\n\nnamespace P3D::Graphics {\n\nRenderBuffer::RenderBuffer(unsigned int width, unsigned int height) : width(width), height(height) {\n\tglGenRenderbuffers(1, &id);\n\n\tbind();\n\tglRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);\n\tunbind();\n}\n\nRenderBuffer::~RenderBuffer() {\n\tclose();\n}\n\nRenderBuffer::RenderBuffer(RenderBuffer&& other) {\n\tid = other.id;\n\tother.id = 0;\n}\n\nRenderBuffer& RenderBuffer::operator=(RenderBuffer&& other) {\n\tif (this != &other) {\n\t\tclose();\n\t\tstd::swap(id, other.id);\n\t}\n\n\treturn *this;\n}\n\n\nvoid RenderBuffer::resize(unsigned int width, unsigned int height) {\n\tbind();\n\tthis->width = width;\n\tthis->height = height;\n\tglRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);\n\tunbind();\n}\n\nvoid RenderBuffer::bind() {\n\tRenderer::bindRenderbuffer(id);\n}\n\nvoid RenderBuffer::unbind() {\n\tRenderer::bindRenderbuffer(0);\n}\n\nvoid RenderBuffer::close() {\n\tglDeleteRenderbuffers(1, &id);\n\tid = 0;\n}\n\n\n// MultisampleRenderBuffer\n\nMultisampleRenderBuffer::MultisampleRenderBuffer(unsigned int width, unsigned int height, unsigned int samples) : width(width), height(height), samples(samples) {\n\tglGenRenderbuffers(1, &id);\n\n\tbind();\n\tglRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_DEPTH24_STENCIL8, width, height);\n\tunbind();\n}\n\nMultisampleRenderBuffer::~MultisampleRenderBuffer() {\n\tclose();\n}\n\nMultisampleRenderBuffer::MultisampleRenderBuffer(MultisampleRenderBuffer&& other) {\n\tid = other.id;\n\tother.id = 0;\n}\n\nMultisampleRenderBuffer& MultisampleRenderBuffer::operator=(MultisampleRenderBuffer&& other) {\n\tif (this != &other) {\n\t\tclose();\n\t\tstd::swap(id, other.id);\n\t}\n\n\treturn *this;\n}\n\nvoid MultisampleRenderBuffer::resize(unsigned int width, unsigned int height) {\n\tbind();\n\tthis->width = width;\n\tthis->height = height;\n\tglRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_DEPTH24_STENCIL8, width, height);\n\tunbind();\n}\n\nvoid MultisampleRenderBuffer::bind() {\n\tRenderer::bindRenderbuffer(id);\n}\n\nvoid MultisampleRenderBuffer::unbind() {\n\tRenderer::bindRenderbuffer(0);\n}\n\nvoid MultisampleRenderBuffer::close() {\n\tglDeleteRenderbuffers(1, &id);\n\tid = 0;\n}\n\n};"
  },
  {
    "path": "graphics/buffers/renderBuffer.h",
    "content": "#pragma once\n\n#include \"../bindable.h\"\n\nnamespace P3D::Graphics {\n\nclass RenderBuffer : public Bindable {\npublic:\n\tunsigned int width;\n\tunsigned int height;\n\n\tRenderBuffer(unsigned int width, unsigned int height);\n\n\t~RenderBuffer();\n\tRenderBuffer(RenderBuffer&& other);\n\tRenderBuffer(const RenderBuffer&) = delete;\n\tRenderBuffer& operator=(RenderBuffer&& other);\n\tRenderBuffer& operator=(const RenderBuffer&) = delete;\n\n\tvoid bind() override;\n\tvoid unbind() override;\n\tvoid close() override;\n\n\tvoid resize(unsigned int width, unsigned int height);\n\n};\n\nclass MultisampleRenderBuffer : public Bindable {\npublic:\n\tunsigned int width;\n\tunsigned int height;\n\tunsigned int samples;\n\n\tMultisampleRenderBuffer(unsigned int width, unsigned int height, unsigned int samples);\n\n\t~MultisampleRenderBuffer();\n\tMultisampleRenderBuffer(MultisampleRenderBuffer&& other);\n\tMultisampleRenderBuffer(const MultisampleRenderBuffer&) = delete;\n\tMultisampleRenderBuffer& operator=(MultisampleRenderBuffer&& other);\n\tMultisampleRenderBuffer& operator=(const MultisampleRenderBuffer&) = delete;\n\n\tvoid bind() override;\n\tvoid unbind() override;\n\tvoid close() override;\n\n\tvoid resize(unsigned int width, unsigned int height);\n};\n\n};"
  },
  {
    "path": "graphics/buffers/vertexArray.cpp",
    "content": "#include \"core.h\"\n\n#include \"vertexArray.h\"\n\n#include <GL/glew.h>\n\n#include \"vertexBuffer.h\"\n#include \"bufferLayout.h\"\n\nnamespace P3D::Graphics {\n\nVertexArray::VertexArray() : attributeArrayOffset(0) {\n\tglGenVertexArrays(1, &id);\n\tglBindVertexArray(id);\n}\n\nVertexArray::~VertexArray() {\n\tclose();\n\tLog::debug(\"Deleted vertex array with id (%d)\", id);\n}\n\nVertexArray::VertexArray(VertexArray&& other) {\n\tattributeArrayOffset = other.attributeArrayOffset;\n\tother.attributeArrayOffset = 0;\n\n\tid = other.id;\n\tother.id = 0;\n}\n\nVertexArray& VertexArray::operator=(VertexArray&& other) {\n\tif (this != &other) {\n\t\tclose();\n\t\tstd::swap(id, other.id);\n\t}\n\n\treturn *this;\n}\n\nvoid VertexArray::bind() {\n\tglBindVertexArray(id);\n}\n\nvoid VertexArray::unbind() {\n\tglBindVertexArray(0);\n}\n\nvoid VertexArray::addBuffer(VertexBuffer* buffer) {\n\tbind();\n\tbuffer->bind();\n\n\tsize_t offset = 0;\n\tfor (size_t i = 0; i < buffer->layout.elements.size(); i++) {\n\t\tauto& element = buffer->layout.elements[i];\n\n\t\tint iterations = (element.info == BufferDataType::MAT2 || element.info == BufferDataType::MAT3 || element.info == BufferDataType::MAT4) ? element.info.count : 1;\n\n\t\tfor (size_t j = 0; j < iterations; j++) {\n\t\t\tglEnableVertexAttribArray(attributeArrayOffset);\n\t\t\tif (element.info.integral)\n\t\t\t\tglVertexAttribIPointer(attributeArrayOffset, element.info.count, element.info.type, buffer->layout.stride, (const void*) offset);\n\t\t\telse\n\t\t\t\tglVertexAttribPointer(attributeArrayOffset, element.info.count, element.info.type, element.normalized, buffer->layout.stride, (const void*) offset);\n\n\t\t\tif (element.instanced)\n\t\t\t\tglVertexAttribDivisor(attributeArrayOffset, 1);\n\n\t\t\toffset += element.info.size;\n\t\t\tattributeArrayOffset++;\n\t\t}\n\t}\n}\n\nvoid VertexArray::close() {\n\tunbind();\n\tglDeleteVertexArrays(1, &id);\n\tid = 0;\n}\n\n};"
  },
  {
    "path": "graphics/buffers/vertexArray.h",
    "content": "#pragma once\n\n#include \"../bindable.h\"\n\nnamespace P3D::Graphics {\n\nstruct BufferLayout;\nclass VertexBuffer;\n\nclass VertexArray : public Bindable {\npublic:\n\tunsigned attributeArrayOffset;\n\n\tVertexArray();\n\n\t~VertexArray();\n\tVertexArray(VertexArray&& other);\n\tVertexArray(const VertexArray&) = delete;\n\tVertexArray& operator=(VertexArray&& other);\n\tVertexArray& operator=(const VertexArray&) = delete;\n\n\tvoid bind() override;\n\tvoid unbind() override;\n\tvoid close() override;\n\n\tvoid addBuffer(VertexBuffer* buffer);\n};\n\n};"
  },
  {
    "path": "graphics/buffers/vertexBuffer.cpp",
    "content": "#include \"core.h\"\n\n#include \"vertexBuffer.h\"\n\n#include <GL/glew.h>\n\nnamespace P3D::Graphics {\n\nVertexBuffer::VertexBuffer() : Bindable(), currentSize(0), currentCapacity(0), layout(BufferLayout()) {\n\tLog::debug(\"Created empty vertex buffer\");\n};\n\nVertexBuffer::VertexBuffer(const BufferLayout& layout, const void* data, size_t sizeInBytes, GLFLAG mode) : Bindable(), currentSize(sizeInBytes), currentCapacity(sizeInBytes), layout(layout) {\n\tglGenBuffers(1, &id);\n\n\tbind();\n\tif (sizeInBytes != 0)\n\t\tfill(data, sizeInBytes, mode);\n}\n\nVertexBuffer::VertexBuffer(const BufferLayout& layout, const void* data, size_t sizeInBytes) : VertexBuffer(layout, data, sizeInBytes, GL_STATIC_DRAW) {}\n\n\nVertexBuffer::~VertexBuffer() {\n\tclose();\n\tLog::warn(\"Deleted vertex buffer with id (%d)\", id);\n}\n\nVertexBuffer::VertexBuffer(VertexBuffer&& other) :\n\tBindable(other.id),\n\tcurrentSize(other.currentSize), \n\tcurrentCapacity(other.currentCapacity),\n\tlayout(std::move(other.layout)) {\n\n\t// Reset to prevent destruction by rvalue\n\tother.id = 0;\n}\n\nVertexBuffer& VertexBuffer::operator=(VertexBuffer&& other) {\n\tif (this != &other) {\n\t\tclose();\n\t\tstd::swap(id, other.id);\n\t\tstd::swap(layout, other.layout);\n\t\tstd::swap(currentSize, other.currentSize);\n\t\tstd::swap(currentCapacity, other.currentCapacity);\n\t}\n\n\treturn *this;\n}\n\nvoid VertexBuffer::fill(const void* data, std::size_t sizeInBytes, GLFLAG mode) {\n\tcurrentSize = sizeInBytes;\n\tcurrentCapacity = sizeInBytes;\n\n\tif (currentSize == 0)\n\t\treturn;\n\n\tbind();\n\tglBufferData(GL_ARRAY_BUFFER, sizeInBytes, data, mode);\n}\n\nvoid VertexBuffer::update(const void* data, std::size_t sizeInBytes, std::size_t offset) {\n\tsize_t newCapacity = offset + sizeInBytes;\n\t\n\tbind();\n\tif (newCapacity > currentCapacity) {\n\t\tLog::error(\"Buffer update exceeds buffer capacity: buffer=%d, size=%d, capacity=%d\", id, sizeInBytes + offset, currentCapacity);\n\t\treturn;\n\t}\n\n\tglBufferSubData(GL_ARRAY_BUFFER, offset, sizeInBytes, data);\n}\n\nsize_t VertexBuffer::size() const {\n\treturn currentSize;\n}\n\nsize_t VertexBuffer::capacity() const {\n\treturn currentCapacity;\n}\n\nvoid VertexBuffer::bind() {\n\tglBindBuffer(GL_ARRAY_BUFFER, id);\n}\n\nvoid VertexBuffer::unbind() {\n\tglBindBuffer(GL_ARRAY_BUFFER, 0);\n}\n\nvoid VertexBuffer::close() {\n\tunbind();\n\tglDeleteBuffers(1, &id);\n\t\n\tid = 0;\n\tlayout = BufferLayout();\n\tcurrentCapacity = 0;\n\tcurrentCapacity = 0;\n}\n\n};"
  },
  {
    "path": "graphics/buffers/vertexBuffer.h",
    "content": "#pragma once\n\n#include \"../bindable.h\"\n#include \"../renderer.h\"\n#include \"bufferLayout.h\"\n\nnamespace P3D::Graphics {\n\nclass VertexBuffer : public Bindable {\nprivate:\n\tstd::size_t currentSize;\n\tstd::size_t currentCapacity;\n\npublic:\n\tBufferLayout layout;\n\t\n\tVertexBuffer();\n\tVertexBuffer(const BufferLayout& layout, const void* data, std::size_t sizeInBytes, GLFLAG mode);\n\tVertexBuffer(const BufferLayout& layout, const void* data, std::size_t sizeInBytes);\n\n\t~VertexBuffer();\n\tVertexBuffer(VertexBuffer&& other);\n\tVertexBuffer(const VertexBuffer&) = delete;\n\tVertexBuffer& operator=(VertexBuffer&& other);\n\tVertexBuffer& operator=(const VertexBuffer&) = delete;\n\n\tvoid fill(const void* data, std::size_t sizeInBytes, GLFLAG mode);\n\tvoid update(const void* data, std::size_t sizeInBytes, std::size_t offset);\n\tstd::size_t size() const;\n\tstd::size_t capacity() const;\n\n\tvoid bind() override;\n\tvoid unbind() override;\n\tvoid close() override;\n};\n\n\n};"
  },
  {
    "path": "graphics/component.natvis",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?> \n<AutoVisualizer xmlns=\"http://schemas.microsoft.com/vstudio/debugger/natvis/2010\">\n  <Type Name=\"Component\">\n    <DisplayString Condition=\"parent != 0xFFFFFFFFFFFFFFFF\">pos={position}, dim={dimension}, parent=yes, visible={visible}, disabled={disabled}, resizing={resizing}, align={align,en}</DisplayString>\n    <DisplayString Condition=\"parent == 0xFFFFFFFFFFFFFFFF\">pos={position}, dim={dimension}, parent=no, visible={visible}, disabled={disabled}, resizing={resizing}, align={align,en}</DisplayString>\n  </Type>\n\n  <Type Name=\"Container\">\n    <DisplayString Condition=\"parent != 0xFFFFFFFFFFFFFFFF\">size={children.elements.size()}, pos={position}, dim={dimension}, parent=yes, visible={visible}, disabled={disabled}, resizing={resizing}, align={align,en}</DisplayString>\n    <DisplayString Condition=\"parent == 0xFFFFFFFFFFFFFFFF\">size={children.elements.size()}, pos={position}, dim={dimension}, parent=no, visible={visible}, disabled={disabled}, resizing={resizing}, align={align,en}</DisplayString>\n  </Type>\n\n  <Type Name=\"Button\">\n    <DisplayString Condition=\"text.size()==0\">textured={textured}, pos={position}, dim={dimension}, parent={parent}</DisplayString>\n    <DisplayString Condition=\"text.size()!=0\">text={text}, textured={textured}, pos={position}, dim={dimension}, parent={parent}</DisplayString>\n    <Expand>\n      <Item Name=\"Component\">*(Component*)this,nd</Item>\n      <Item Name=\"text\">text</Item>\n      <Item Name=\"textured\">textured</Item>\n    </Expand>\n  </Type>\n\n  <Type Name=\"Image\">\n    <DisplayString Condition=\"texture != 0xFFFFFFFFFFFFFFFF\">texture={texture}, pos={position}, dim={dimension}, parent=yes, visible={visible}, disabled={disabled}, resizing={resizing}, align={align,en}</DisplayString>\n    <DisplayString Condition=\"texture == 0xFFFFFFFFFFFFFFFF\">texture=none, pos={position}, dim={dimension}, parent=no, visible={visible}, disabled={disabled}, resizing={resizing}, align={align,en}</DisplayString>\n    <Expand>\n      <Item Name=\"Component\">*(Component*)this,nd</Item>\n      <Item Name=\"texture\">texture</Item>\n    </Expand>\n  </Type>\n  \n  <Type Name=\"Label\">\n    <DisplayString>text={text}, pos={position}, dim={dimension}, parent={parent}</DisplayString>\n    <Expand>\n      <Item Name=\"Component\">*(Component*)this,nd</Item>\n      <Item Name=\"text\">text</Item>\n      <Item Name=\"scale\">scale</Item>\n      <Item Name=\"foreground\">foregroundColor</Item>\n      <Item Name=\"background\">backgroundColor</Item>\n    </Expand>\n  </Type>\n\n  <Type Name=\"CheckBox\">\n    <DisplayString Condition=\"label->text.size()!=0\">text={label->text}, checked={checked}, pos={position}, dim={dimension}, parent={parent}</DisplayString>\n    <DisplayString Condition=\"label->text.size()==0\">checked={checked}, pos={position}, dim={dimension}, parent={parent}</DisplayString>\n    <Expand>\n      <Item Name=\"Component\">*(Component*)this,nd</Item>\n      <Item Name=\"label\">label</Item>\n      <Item Name=\"textured\">textured</Item>\n    </Expand>\n  </Type>\n\n  <Type Name=\"Slider\">\n    <DisplayString>value={value,g}, range=({min,g} ... {max,g}), pos={position}, dim={dimension}, parent={parent}</DisplayString>\n    <Expand>\n      <Item Name=\"Component\">*(Component*)this,nd</Item>\n      <Item Name=\"value\">value</Item>\n      <Item Name=\"min\">min</Item>\n      <Item Name=\"max\">max</Item>\n    </Expand>\n  </Type>\n\n  <Type Name=\"Frame\">\n    <DisplayString >title={title->text}, pos={position}, dim={dimension}, anchor={parent, g}</DisplayString>\n    <Expand>\n      <Item Name=\"Container\">*(Container*)this,nd</Item>\n      <Item Name=\"title\">title</Item>\n      <Item Name=\"minimized\">minimized</Item>\n      <Item Name=\"anchor\">anchor</Item>\n    </Expand>\n  </Type>\n\n  <Type Name=\"OrderedVector&lt;*&gt;\">\n    <DisplayString>size={elements.size()}</DisplayString>\n  </Type>\n</AutoVisualizer>\n"
  },
  {
    "path": "graphics/core.cpp",
    "content": "#include \"core.h\""
  },
  {
    "path": "graphics/core.h",
    "content": "#pragma once\n\n#include <unordered_map>\n#include <functional>\n#include <algorithm>\n#include <optional>\n#include <utility>\n#include <string>\n#include <vector>\n#include <cmath>\n#include <map>\n\n#include <Physics3D/math/linalg/vec.h>\n#include <Physics3D/math/fix.h>\n#include <Physics3D/math/linalg/mat.h>\n#include <Physics3D/math/linalg/trigonometry.h>\n#include <Physics3D/math/position.h>\n#include <Physics3D/datastructures/smartPointers.h>\n\n#include \"../util/log.h\"\n\n#ifdef _MSC_VER\n#define P3D_DEBUGBREAK __debugbreak()\n#else\n#define P3D_DEBUGBREAK raise(SIGTRAP)\n#endif"
  },
  {
    "path": "graphics/debug/guiDebug.cpp",
    "content": "#include \"core.h\"\n\n#include \"guiDebug.h\"\n#include \"threePhaseBuffer.h\"\n#include <Physics3D/misc/debug.h>\n#include <Physics3D/geometry/shape.h>\n#include <Physics3D/math/mathUtil.h>\n#include <Physics3D/geometry/polyhedron.h>\n#include \"../util/log.h\"\n\n#include <GL/glew.h>\n\n\nnamespace P3D::Graphics {\n\nvoid renderQuad() {\n\tstatic unsigned int VAO = 0;\n\tstatic unsigned int VBO;\n\tif (VAO == 0) {\n\t\tfloat vertices[] = {\n\t\t\t// positions        // texture Coords\n\t\t\t-1.0f,  1.0f, 0.0f, 1.0f,\n\t\t\t-1.0f, -1.0f, 0.0f, 0.0f,\n\t\t\t 1.0f,  1.0f, 1.0f, 1.0f,\n\t\t\t 1.0f, -1.0f, 1.0f, 0.0f,\n\t\t};\n\t\t// setup plane VAO\n\t\tglGenVertexArrays(1, &VAO);\n\t\tglGenBuffers(1, &VBO);\n\t\tglBindVertexArray(VAO);\n\t\tglBindBuffer(GL_ARRAY_BUFFER, VBO);\n\t\tglBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices, GL_STATIC_DRAW);\n\t\tglEnableVertexAttribArray(0);\n\t\tglVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*) 0);\n\t}\n\tglBindVertexArray(VAO);\n\tglDrawArrays(GL_TRIANGLE_STRIP, 0, 4);\n\tglBindVertexArray(0);\n}\n\nvoid clearError() {\n\twhile (glGetError() != GL_NO_ERROR);\n}\n\nbool logCall(const char* func, const char* file, int line) {\n\tbool response = true;\n\tunsigned int error = glGetError();\n\twhile (error != GL_NO_ERROR) {\n\t\tLog::error(\"[OpenGL error 0x%x] %s:%d at %s\", error, file, line, func);\n\t\terror = glGetError();\n\t\tresponse = false;\n\t}\n\treturn response;\n}\n\nnamespace AppDebug {\n\nThreePhaseBuffer<ColoredVector> vecBuf(256);\nThreePhaseBuffer<ColoredPoint> pointBuf(256);\n\nnamespace Logging {\nusing namespace Debug;\n\nvoid logVector(Position origin, Vec3 vec, VectorType type) {\n\tvecBuf.add(ColoredVector(origin, vec, type));\n}\n\nvoid logPoint(Position point, PointType type) {\n\tpointBuf.add(ColoredPoint(point, type));\n}\n\nvoid logCFrame(CFrame frame, CFrameType type) {\n\tswitch (type) {\n\t\tcase OBJECT_CFRAME: {\n\t\t\t\tVec3 pos = frame.position;\n\t\t\t\tRotation rot = frame.rotation;\n\t\t\t\t// buf.add(ColoredVec(frame.position, rot * Vec3(1.0, 0.0, 0.0), 0.0));\n\t\t\t\t// buf.add(ColoredVec(frame.position, rot * Vec3(0.0, 1.0, 0.0), 0.3));\n\t\t\t\t// buf.add(ColoredVec(frame.position, rot * Vec3(0.0, 0.0, 1.0), 0.6));\n\t\t\t}\n\t\t\t\t\t\t  break;\n\t\tcase INERTIAL_CFRAME: {\n\t\t\t\tVec3 pos = frame.position;\n\t\t\t\tRotation rot = frame.rotation;\n\t\t\t\t// buf.add(ColoredVec(frame.position, rot * Vec3(1.0, 0.0, 0.0), 0.1));\n\t\t\t\t// buf.add(ColoredVec(frame.position, rot * Vec3(0.0, 1.0, 0.0), 0.4));\n\t\t\t\t// buf.add(ColoredVec(frame.position, rot * Vec3(0.0, 0.0, 1.0), 0.7));\n\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t}\n}\n\nvoid logShape(const Polyhedron& shape, const GlobalCFrame& location) {\n\tfor (int i = 0; i < shape.triangleCount; i++) {\n\t\tTriangle t = shape.getTriangle(i);\n\t\tfor (int j = 0; j < 3; j++) {\n\t\t\tDebug::logVector(location.localToGlobal(shape.getVertex(t[j])), location.localToRelative(shape.getVertex(t[(j + 1) % 3]) - shape.getVertex(t[j])), Debug::INFO_VEC);\n\t\t}\n\t}\n}\n};\n\nvoid logTickStart() {\n\n}\n\nvoid logTickEnd(WorldPrototype* world) {\n\tvecBuf.pushWriteBuffer();\n\tpointBuf.pushWriteBuffer();\n}\n\nvoid logFrameStart() {\n\n}\n\nvoid logFrameEnd() {\n\n}\n\nvoid setupDebugHooks() {\n\tLog::info(\"Set up debug hooks!\");\n\tDebug::setVectorLogAction(Logging::logVector);\n\tDebug::setPointLogAction(Logging::logPoint);\n\tDebug::setCFrameLogAction(Logging::logCFrame);\n\tDebug::setShapeLogAction(Logging::logShape);\n\t// leave physics logging default printf\n\t//Debug::setLogAction([](const char* format, std::va_list args) {Log::debug(format, ); })\n}\n\n/*\n\tReturns a copy of the current vec buffer\n*/\nAddableBuffer<ColoredVector>& getVectorBuffer() {\n\treturn vecBuf.pullOutputBuffer();\n}\n\n/*\n\tReturns a copy of the current point buffer\n*/\nAddableBuffer<ColoredPoint>& getPointBuffer() {\n\treturn pointBuf.pullOutputBuffer();\n}\n}\n\n};"
  },
  {
    "path": "graphics/debug/guiDebug.h",
    "content": "#pragma once\n\n#include <Physics3D/misc/debug.h>\n#include \"../util/log.h\"\n\n#include \"threePhaseBuffer.h\"\n\n#include <stdexcept>\n\nnamespace P3D {\nclass WorldPrototype;\n};\n\nnamespace P3D::Graphics {\n\n#define ASSERT(x) if (!(x)) throw std::logic_error(\"Assert failed\")\n#define glCall(x) {Graphics::clearError(); x; ASSERT(Graphics::logCall(#x, __FILE__, __LINE__));}\n\nvoid clearError();\nbool logCall(const char* func, const char* file, int line);\n\nnamespace AppDebug {\nstruct ColoredVector {\n\tVec3 origin, vector;\n\tP3D::Debug::VectorType type;\n\tColoredVector() = default;\n\tColoredVector(Vec3 origin, Vec3 vector, P3D::Debug::VectorType type) : origin(origin), vector(vector), type(type) {}\n\tColoredVector(Position origin, Vec3 vector, P3D::Debug::VectorType type) : origin(castPositionToVec3(origin)), vector(vector), type(type) {}\n};\nstruct ColoredPoint {\n\tVec3 point;\n\tP3D::Debug::PointType type;\n\tColoredPoint() = default;\n\tColoredPoint(Vec3 point, P3D::Debug::PointType type) : point(point), type(type) {}\n\tColoredPoint(Position point, P3D::Debug::PointType type) : point(castPositionToVec3(point)), type(type) {}\n};\n\nvoid setupDebugHooks();\n\nvoid logTickEnd(WorldPrototype* world);\n\nvoid logFrameStart();\nvoid logFrameEnd();\n\nvoid renderQuad();\n\nAddableBuffer<ColoredVector>& getVectorBuffer();\nAddableBuffer<ColoredPoint>& getPointBuffer();\n}\n\n};"
  },
  {
    "path": "graphics/debug/profilerUI.cpp",
    "content": "#include \"core.h\"\n\n#include \"profilerUI.h\"\n\n#include \"../application/picker/selection.h\"\n#include \"../application/picker/tools/selectionTool.h\"\n#include \"../application/extendedPart.h\"\n\n#include <sstream>\n#include <GL/glew.h>\n\n#include \"texture.h\"\n#include \"path/path.h\"\n#include \"gui/gui.h\"\n#include \"font.h\"\n#include <Physics3D/math/constants.h>\n#include <Physics3D/boundstree/boundsTree.h>\n\nnamespace P3D::Graphics {\n\n#pragma region PieChart\n\n//! PieChart\n\n#define MAX_ANGLE 0.1f\n\nconst Color pieColors[30] {\n\tColor(0.2f,0.2f,1),\n\tColor(1,0.5f,0),\n\tColor(1,1,0),\n\tColor(1,0,1),\n\tColor(0,1,0),\n\tColor(0,1,1),\n\tColor(1,1,1),\n\tColor(1,0,0),\n\tColor(0.5f,0,0),\n\tColor(0,0.5f,0),\n\tColor(0,0,0.5f),\n\tColor(0.5f,0.5f,0),\n\tColor(0.5f,0,0.5f),\n\tColor(0,0.5f,0.5f),\n\tColor(0.5f,0.5f,0.5f),\n};\n\nvoid PieChart::renderPie() const {\n\tVec2f cursorPosition = Vec2f(pieSize, 0);\n\n\tfloat oldAngle = 0.0f;\n\tfloat newAngle = 0.0f;\n\tfloat totalWeight = getTotal();\n\n\tif (totalWeight == 0.0)\n\t\treturn;\n\n\tfor (DataPoint dataPoint : parts) {\n\t\tfloat angle = float(PI * 2 * dataPoint.weight / totalWeight);\n\t\tint subdivisions = int(angle / MAX_ANGLE + 1);\n\t\tnewAngle += angle;\n\n\t\tPath::circleSegmentFilled(piePosition, pieSize, oldAngle, newAngle, dataPoint.color, subdivisions);\n\n\t\toldAngle = newAngle;\n\t}\n}\n\nvoid PieChart::renderText(Graphics::Font* font) const {\n\n\t// Title\n\tVec2f titlePosition = piePosition + Vec2f(pieSize * 1.3f, pieSize * 1.1f);\n\tPath::text(font, title, 0.001, Vec2(titlePosition.x, titlePosition.y), Vec4f(1, 1, 1, 1));\n\n\tVec2f textPosition = Vec2(piePosition + Vec2f(pieSize * 1.3f, pieSize * 1.1f - 0.05f));\n\tfloat totalWeight = getTotal();\n\n\tPath::text(font, totalValue, 0.0006, textPosition + Vec2(0.50, 0.035), Color(1, 1, 1, 1));\n\n\tfor (int i = 0; i < parts.size(); i++) {\n\t\tconst DataPoint& p = parts[i];\n\t\tVec2 linePosition = textPosition + Vec2(0, -i * 0.035);\n\t\tPath::text(font, p.label, 0.0006, linePosition, p.color);\n\n\t\tstd::stringstream percent;\n\t\tpercent.precision(4);\n\t\tpercent << p.weight / totalWeight * 100;\n\t\tpercent << \"%\";\n\t\tPath::text(font, percent.str(), 0.0006, linePosition + Vec2(0.35, 0), p.color);\n\t\tPath::text(font, p.value, 0.0006, linePosition + Vec2(0.50, 0), p.color);\n\t}\n}\n\nvoid PieChart::add(DataPoint& dataPoint) {\n\tthis->parts.push_back(dataPoint);\n}\n\nfloat PieChart::getTotal() const {\n\tfloat totalWeight = 0;\n\tfor (DataPoint p : parts)\n\t\ttotalWeight += p.weight;\n\treturn totalWeight;\n}\n\n#pragma endregion\n\n#pragma region BarChart\n\n//! BarChart\n\nvoid BarChart::render() {\n\tfloat titleHeight = 0.045f;\n\tfloat marginLeft = 0.0f;\n\tfloat marginBottom = this->dimension.y * 0.045f;\n\tfloat marginTop = titleHeight + 0.05f;\n\tfloat max = getMaxWeight();\n\n\tVec2f drawingPosition = position + Vec2f(marginLeft, marginBottom);\n\tVec2f drawingSize = this->dimension - Vec2f(marginLeft, marginBottom + marginTop);\n\n\tfloat categoryWidth = drawingSize.x / data.w;\n\tfloat barWidth = drawingSize.x / ((data.h + 0.5f) * data.w);\n\n\tfor (int cl = 0; cl < data.h; cl++) {\n\t\tconst BarChartClassInfo& info = classes[cl];\n\n\t\tfor (int i = 0; i < data.w; i++) {\n\t\t\tconst WeightValue& dataPoint = data(cl, i);\n\n\t\t\tfloat height = drawingSize.y * dataPoint.weight / max;\n\t\t\tVec2f bottomLeft = drawingPosition + Vec2f(categoryWidth * i + barWidth * cl, 0);\n\n\t\t\tPath::rectFilled(bottomLeft, Vec2f(barWidth, height), 0.0f, info.color);\n\t\t}\n\t}\n\n\tPath::text(GUI::font, title, 0.001, position + Vec2f(0, this->dimension.y - titleHeight), Colors::WHITE);\n\n\tfor (int cl = 0; cl < data.h; cl++) {\n\t\tconst BarChartClassInfo& info = classes[cl];\n\n\t\tfor (int i = 0; i < data.w; i++) {\n\t\t\tconst WeightValue& dataPoint = data(cl, i);\n\n\t\t\tVec2f bottomLeft = drawingPosition + Vec2f(categoryWidth * i + barWidth * cl, 0);\n\t\t\tfloat height = drawingSize.y * dataPoint.weight / max;\n\n\t\t\tVec2f topTextPosition = bottomLeft + Vec2(0, height + drawingSize.y * 0.02);\n\t\t\t//topTextPosition.x *= GUI::screen->dimension.x / GUI::screen->dimension.y;\n\n\t\t\tPath::text(GUI::font, dataPoint.value, 0.0005, topTextPosition, info.color);\n\t\t}\n\t}\n\n\tfor (int i = 0; i < data.w; i++) {\n\t\tVec2f botLeft = position + Vec2f(marginLeft, 0) + Vec2f(categoryWidth * i, 0);\n\t\tPath::text(GUI::font, labels[i], 0.0005, botLeft, Colors::WHITE);\n\t}\n\n\tfor (int cl = 0; cl < data.h; cl++)\n\t\tPath::text(GUI::font, classes[cl].name, 0.0007, drawingPosition + Vec2f(this->dimension.x - 0.3f, drawingSize.y - 0.035f * cl), classes[cl].color);\n}\n\nfloat BarChart::getMaxWeight() const {\n\tfloat best = 0;\n\tfor (const WeightValue& wv : data) {\n\t\tif (wv.weight > best)\n\t\t\tbest = wv.weight;\n\t}\n\treturn best;\n}\n\n#pragma endregion\n\n#pragma region Tree\n\n//! Tree\nstatic void recursiveRenderTree(const P3D::TreeTrunk& curTrunk, int curTrunkSize, const Color& treeColor, Vec2f origin, float allottedWidth, float maxCost) {\n\tfor(int i = 0; i < curTrunkSize; i++) {\n\t\tconst P3D::TreeNodeRef& subNode = curTrunk.subNodes[i];\n\n\t\tVec2f nextStep = origin + Vec2f(-allottedWidth / 2 + allottedWidth * ((curTrunkSize != 1) ? (float(i) / (curTrunkSize - 1)) : 0.5f), -0.1f);\n\t\tfloat colorDarkning = pow(1.0f * P3D::computeCost(curTrunk.getBoundsOfSubNode(i)) / maxCost, 0.25f);\n\n\t\t//Path::bezierVertical(origin, nextStep, 1.0f, Vec4f(treeColor * colorDarkning, 1.0f), 15);\n\t\tPath::line(origin, nextStep, Color(treeColor.r * colorDarkning, treeColor.g * colorDarkning, treeColor.b * colorDarkning), 0.5f);\n\n\t\tif(subNode.isTrunkNode()) {\n\t\t\trecursiveRenderTree(subNode.asTrunk(), subNode.getTrunkSize(), treeColor, nextStep, allottedWidth / curTrunkSize, maxCost);\n\n\t\t\tif(subNode.isGroupHead()) {\n\t\t\t\tPath::circleFilled(nextStep, 0.006f, Colors::RED, 8);\n\t\t\t}\n\t\t} else {\n\t\t\tP3D::Application::ExtendedPart* extPart = reinterpret_cast<Application::ExtendedPart*>(subNode.asObject());\n\t\t\tif(P3D::Application::SelectionTool::selection.contains(extPart->entity)) {\n\t\t\t\tPath::circleFilled(nextStep, 0.012f, Colors::YELLOW, 8);\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid renderTreeStructure(const P3D::BoundsTree<Part>& tree, const Color& treeColor, Vec2f origin, float allottedWidth) {\n\tif(tree.isEmpty()) {\n\t\treturn;\n\t}\n\tauto base = tree.getPrototype().getBaseTrunk();\n\tfloat maxCost = P3D::computeCost(base.first.getBoundsOfSubNode(0));\n\tfor(int i = 1; i < base.second; i++) {\n\t\tfloat subCost = P3D::computeCost(base.first.getBoundsOfSubNode(i));\n\t\tif(subCost > maxCost) maxCost = subCost;\n\t}\n\n\trecursiveRenderTree(base.first, base.second, treeColor, origin, allottedWidth, maxCost);\n}\n\n#pragma endregion\n\n#pragma region SlidingDataChart\n\n//! SlidingDataChart\n\nvoid SlidingChartDataSetInfo::add(float value) {\n\tif (data.size() == 0) {\n\t\tdeviation = 1.0f;\n\t\tmean = value;\n\n\t\tdata.add(value);\n\n\t\treturn;\n\t}\n\n\tdata.add(value);\n\n\tfloat variance = deviation * deviation;\n\tfloat newVariance = variance;\n\tfloat newMean = mean;\n\n\tif (data.size() == size) {\n\t\tfloat s = size;\n\t\tfloat s1 = s - 1.0f;\n\n\t\tnewMean = mean + (value - data.front()) / s;\n\t\tfloat diffMean = newMean - mean;\n\n\t\tnewVariance = variance + diffMean * s / s1 * (2.0f * (data.front() - mean) + s1 * diffMean);\n\t} else {\n\t\tfloat s = data.size();\n\n\t\tfloat s1 = s - 1.0f;\n\t\tfloat s2 = s - 2.0f;\n\n\t\tnewMean = (mean * s1 + value) / s;\n\t\tnewVariance = (s2 * variance + (value - newMean) * (value - mean)) / s1;\n\t}\n\n\tmean = newMean;\n\tdeviation = sqrt(newVariance);\n}\n\nSlidingChart::SlidingChart(const std::string& title, const Vec2& position, const Vec2& dimension) : title(title), position(position), dimension(dimension) {}\n\nvoid SlidingChart::add(const SlidingChartDataSetInfo& dataSet) {\n\tdataSets[dataSet.title] = dataSet;\n}\n\nvoid SlidingChart::add(const std::string& title, float value) {\n\treturn dataSets.at(title).add(value);\n}\n\nSlidingChartDataSetInfo SlidingChart::get(const std::string& title) {\n\treturn dataSets.at(title);\n}\n\nvoid SlidingChart::render() {\n\tfloat axisOffset = 0.03;\n\n\tPath::rect(position, dimension, 0.0f, Vec4f(0.4f, 0.4f, 0.4f, 1.0f));\n\tPath::line(position + Vec2f(-axisOffset, -dimension.y), position + Vec2f(dimension.x + axisOffset, -dimension.y), Colors::WHITE, 2.0f);\n\tPath::line(position + Vec2f(0, axisOffset), position + Vec2f(0, -dimension.y - axisOffset), Colors::WHITE, 2.0f);\n\n\tfor (auto dataSetIterator : dataSets) {\n\t\tSlidingChartDataSetInfo& dataSet = dataSetIterator.second;\n\n\t\tfloat usedDeviaton = fmax(dataSet.deviation, 0.1 * dataSet.mean);\n\t\tfloat stepX = dimension.x / dataSet.size;\n\t\tfloat stepY = dimension.y / usedDeviaton / 6.82f;\n\t\tfloat startY = dataSet.mean - usedDeviaton;\n\n\t\tVec2f bottomLeft = position - Vec2f(0.0f, dimension.y);\n\n\t\tint i = 0;\n\t\tfor (float value : dataSet.data) {\n\t\t\tVec2f point = bottomLeft + Vec2f(i * stepX, (value - startY) * stepY);\n\n\t\t\tPath::lineTo(point);\n\n\t\t\ti++;\n\t\t}\n\n\t\tPath::stroke(dataSet.color, dataSet.lineSize);\n\n\t\tfloat lastValue = dataSet.data.front();\n\t\tfloat lastY = (lastValue - startY) * stepY;\n\t\tPath::text(GUI::font, std::to_string(lastValue), 0.0008f, Vec2f((bottomLeft.x + dimension.x) * 1.01f, bottomLeft.y + lastY), dataSet.color, Path::TextPivotVC);\n\t}\n\n\tVec2f titleSize = GUI::font->size(title, 0.001f);\n\tPath::text(GUI::font, title, 0.001f, Vec2f(position.x + dimension.x / 2.0f, position.y + axisOffset), Colors::WHITE, Path::TextPivotHC);\n}\n\nVec2 SlidingChart::resize() {\n\treturn Vec2(dimension);\n}\n\n#pragma endregion\n\n};\n"
  },
  {
    "path": "graphics/debug/profilerUI.h",
    "content": "#pragma once\n\n#include \"../gui/color.h\"\n#include <Physics3D/misc/profiling.h>\n#include <Physics3D/math/linalg/largeMatrix.h>\n\nnamespace P3D {\ntemplate<typename T>\nstruct BoundsTree;\nclass Part;\n}\n\nnamespace P3D::Graphics {\n\nclass Font;\n\nextern const Color pieColors[30];\n\nstruct WeightValue {\n\tfloat weight;\n\tstd::string value;\n};\n\nstruct DataPoint {\n\tfloat weight;\n\tstd::string value;\n\tColor color;\n\tconst char* label;\n\tDataPoint() : color(), weight(0) {}\n\tDataPoint(float weight, std::string value, Vec3f color, const char* label) : weight(weight), value(value), color(color), label(label) {}\n};\n\nstruct PieChart {\n\tconst char* title;\n\tVec2f piePosition;\n\tfloat pieSize;\n\tstd::vector<DataPoint> parts;\n\tstd::string totalValue;\n\n\tinline PieChart(const char* title, std::string totalValue, Vec2f piePosition, float pieSize) : title(title), totalValue(totalValue), piePosition(piePosition), pieSize(pieSize) {}\n\tvoid renderPie() const;\n\tvoid renderText(Graphics::Font* font) const;\n\tvoid add(DataPoint& p);\n\tfloat getTotal() const;\n};\n\nstruct BarChartClassInfo {\n\tstd::string name;\n\tColor color;\n};\n\nstruct BarChart {\n\tVec2f position;\n\tVec2f dimension;\n\tconst char* title;\n\tconst char** labels;\n\tBarChartClassInfo* classes;\n\tLargeMatrix<WeightValue> data;\n\tstd::string totalValue;\n\n\tinline BarChart(const char* title, std::string totalValue, const char** labels, BarChartClassInfo* classes, Vec2f chartPosition, Vec2f chartSize, int classCount, int barCount) :\n\t\ttitle(title), totalValue(totalValue), classes(classes), labels(labels), data(barCount, classCount), position(chartPosition), dimension(chartSize) {}\n\tvoid render();\n\n\tfloat getMaxWeight() const;\n};\n\nstruct SlidingChartDataSetInfo {\n\tint size;\n\tstd::string title;\n\tCircularBuffer<float> data;\n\tColor color;\n\tfloat lineSize;\n\n\tfloat mean;\n\tfloat deviation;\n\n\tSlidingChartDataSetInfo() : title(\"\"), size(0), mean(0), deviation(1), color(Colors::ALPHA), lineSize(0), data() {}\n\tSlidingChartDataSetInfo(const std::string& title, int size, Color color = Colors::ACCENT, float lineSize = 1.0f) : title(title), size(size), mean(0), deviation(1), color(color), lineSize(lineSize), data(size) {}\n\n\tvoid add(float value);\n};\n\nstruct SlidingChart {\n\tVec2 position;\n\tVec2 dimension;\n\tstd::string title;\n\tstd::map<std::string, SlidingChartDataSetInfo> dataSets;\n\n\tSlidingChart(const std::string& title, const Vec2& position, const Vec2& dimension);\n\n\tvoid add(const std::string& title, float value);\n\tvoid add(const SlidingChartDataSetInfo& dataSet);\n\n\tSlidingChartDataSetInfo get(const std::string& title);\n\n\tvoid render();\n\tVec2 resize();\n};\n\nvoid renderTreeStructure(const P3D::BoundsTree<Part>& tree, const Color& treeColor, Vec2f origin, float allottedWidth);\n\n};"
  },
  {
    "path": "graphics/debug/threePhaseBuffer.h",
    "content": "#pragma once\n\n#include <Physics3D/datastructures/buffers.h>\n\n#include <mutex>\n\nnamespace P3D {\ntemplate<typename T>\nclass ThreePhaseBuffer {\n\tAddableBuffer<T> writeBuf;\n\tBufferWithCapacity<T> readyBuf;\n\tsize_t readySize = 0;\n\tbool newDataAvailable = false;\npublic:\n\tAddableBuffer<T> outputBuf;\n\tstd::mutex swapLock;\n\n\tThreePhaseBuffer(size_t initialCapacity) : writeBuf(initialCapacity), readyBuf(initialCapacity), outputBuf(initialCapacity) {}\n\n\t~ThreePhaseBuffer() {}\n\n\tThreePhaseBuffer(const ThreePhaseBuffer&) = delete;\n\tThreePhaseBuffer(const ThreePhaseBuffer&&) = delete;\n\tThreePhaseBuffer& operator=(const ThreePhaseBuffer&) = delete;\n\tThreePhaseBuffer& operator=(const ThreePhaseBuffer&&) = delete;\n\n\tinline void add(const T& obj) {\n\t\twriteBuf.add(obj);\n\t}\n\n\tinline void pushWriteBuffer() {\n\t\tstd::lock_guard<std::mutex> lg(swapLock);\n\n\t\treadySize = writeBuf.size;\n\t\tstd::swap(static_cast<BufferWithCapacity<T>&>(writeBuf), readyBuf);\n\t\twriteBuf.clear();\n\n\t\tnewDataAvailable = true;\n\t}\n\n\tinline AddableBuffer<T>& pullOutputBuffer() {\n\t\tstd::lock_guard<std::mutex> lg(swapLock);\n\n\t\tif(newDataAvailable) {\n\t\t\tstd::swap(static_cast<BufferWithCapacity<T>&>(readyBuf), static_cast<BufferWithCapacity<T>&>(outputBuf));\n\n\t\t\tnewDataAvailable = false;\n\t\t}\n\n\t\toutputBuf.size = readySize;\n\n\t\treturn outputBuf;\n\t}\n};\n};\n"
  },
  {
    "path": "graphics/debug/visualDebug.cpp",
    "content": "#include \"core.h\"\n\n#include \"visualDebug.h\"\n\n#include \"mesh/vectorMesh.h\"\n#include \"mesh/pointMesh.h\"\n\n#include \"font.h\"\n#include \"batch/commandBatch.h\"\n#include \"batch/guiBatch.h\"\n#include \"path/path.h\"\n#include \"gui/gui.h\"\n\n#include \"threePhaseBuffer.h\"\n#include \"batch/commandBatch.h\"\n\n#include <sstream>\n\nnamespace P3D::Graphics {\n\nconst char* const graphicsDebugLabels[] {\n\t\t\"Update\",\n\t\t\"Skybox\",\n\t\t\"Vectors\",\n\t\t\"Lighting\",\n\t\t\"Wait For Lock\",\n\t\t\"Physicals\",\n\t\t\"Origin\",\n\t\t\"Picker\",\n\t\t\"Profiler\",\n\t\t\"Finalize\",\n\t\t\"Other\"\n};\n\nBreakdownAverageProfiler<GraphicsProcess> graphicsMeasure(graphicsDebugLabels, 60);\n\nnamespace VisualDebug {\n\nstd::map<P3D::Debug::VectorType, bool> vectorDebugEnabled {\n\t{ P3D::Debug::INFO_VEC        , false },\n\t{ P3D::Debug::VELOCITY        , false },\n\t{ P3D::Debug::ACCELERATION    , false },\n\t{ P3D::Debug::FORCE           , false },\n\t{ P3D::Debug::ANGULAR_IMPULSE , false },\n\t{ P3D::Debug::POSITION        , false },\n\t{ P3D::Debug::MOMENT          , false },\n\t{ P3D::Debug::IMPULSE         , false },\n\t{ P3D::Debug::ANGULAR_VELOCITY, false }\n};\n\nstd::map<P3D::Debug::PointType, bool> pointDebugEnabled {\n\t{ P3D::Debug::INFO_POINT    , false },\n\t{ P3D::Debug::CENTER_OF_MASS, false },\n\t{ P3D::Debug::INTERSECTION  , false },\n};\n\nstruct PointColorPair {\n\tVec3f color1;\n\tVec3f color2;\n};\n\nstd::map<P3D::Debug::VectorType, Vec3f> vectorColors {\n\t{ P3D::Debug::INFO_VEC        , Vec3f(0, 1, 0) },\n\t{ P3D::Debug::VELOCITY        , Vec3f(0, 0, 1) },\n\t{ P3D::Debug::ACCELERATION    , Vec3f(0, 1, 1) },\n\t{ P3D::Debug::FORCE           , Vec3f(1, 0, 0) },\n\t{ P3D::Debug::POSITION        , Vec3f(1, 1, 0) },\n\t{ P3D::Debug::MOMENT          , Vec3f(1, 0, 1) },\n\t{ P3D::Debug::IMPULSE         , Vec3f(0.5, 0.7, 1) },\n\t{ P3D::Debug::ANGULAR_VELOCITY, Vec3f(0.75, 0.75, 0.75) },\n\t{ P3D::Debug::ANGULAR_IMPULSE , Vec3f(0.8, 0.1, 0.4) }\n};\n\nstd::map<P3D::Debug::PointType, PointColorPair> pointColors {\n\t{ P3D::Debug::INFO_POINT    , PointColorPair { Vec3f(1.0f, 0.5f, 0.0f), Vec3f(1.0f, 0.2f, 0.0f) }},\n\t{ P3D::Debug::CENTER_OF_MASS, PointColorPair { Vec3f(1.0f, 1.0f, 0.0f), Vec3f(0.0f, 0.0f, 0.0f) }},\n\t{ P3D::Debug::INTERSECTION  , PointColorPair { Vec3f(0.0f, 0.0f, 1.0f), Vec3f(0.0f, 1.0f, 0.0f) }},\n};\n\nAddableBuffer<float> visibleVectors(900);\nAddableBuffer<float> visiblePoints(1000);\n\nSphereColissionRenderMode colissionSpheresMode;\nint colTreeRenderMode = -1; // -2 for selected, -1 for none, n >= 0 for layer tree n\n\n\nbool renderPiesEnabled = false;\nint fieldIndex = 0;\n\nvoid toggleVectorType(P3D::Debug::VectorType type) {\n\tvectorDebugEnabled[type] = !vectorDebugEnabled[type];\n}\n\nvoid togglePointType(P3D::Debug::PointType type) {\n\tpointDebugEnabled[type] = !pointDebugEnabled[type];\n}\n\nstd::string toString(std::chrono::nanoseconds time) {\n\tstd::stringstream string;\n\tstring.precision(4);\n\tstring << time.count() * 0.000001f;\n\tstring << \"ms\";\n\treturn string.str();\n}\n\nsize_t getTheoreticalNumberOfIntersections(size_t objectCount) {\n\treturn (objectCount - 1) * objectCount / 2;\n}\n\nvoid updateVectorMesh(Graphics::VectorMesh* vectorMesh, AppDebug::ColoredVector* data, size_t size) {\n\tvisibleVectors.clear();\n\n\tfor (size_t i = 0; i < size; i++) {\n\t\tconst AppDebug::ColoredVector& vector = data[i];\n\t\tif (vectorDebugEnabled[vector.type]) {\n\t\t\tvisibleVectors.add(vector.origin.x);\n\t\t\tvisibleVectors.add(vector.origin.y);\n\t\t\tvisibleVectors.add(vector.origin.z);\n\t\t\tvisibleVectors.add(vector.vector.x);\n\t\t\tvisibleVectors.add(vector.vector.y);\n\t\t\tvisibleVectors.add(vector.vector.z);\n\t\t\tvisibleVectors.add(vectorColors[vector.type].x);\n\t\t\tvisibleVectors.add(vectorColors[vector.type].y);\n\t\t\tvisibleVectors.add(vectorColors[vector.type].z);\n\t\t}\n\t}\n\n\tvectorMesh->update(visibleVectors.data, visibleVectors.size / 9);\n}\n\nvoid updatePointMesh(Graphics::PointMesh* pointMesh, AppDebug::ColoredPoint* data, size_t size) {\n\tvisiblePoints.clear();\n\n\tfor (size_t i = 0; i < size; i++) {\n\t\tconst AppDebug::ColoredPoint& point = data[i];\n\t\tif (pointDebugEnabled[point.type]) {\n\t\t\tVec3f color1 = pointColors[point.type].color1;\n\t\t\tVec3f color2 = pointColors[point.type].color2;\n\n\t\t\tvisiblePoints.add(point.point.x);\n\t\t\tvisiblePoints.add(point.point.y);\n\t\t\tvisiblePoints.add(point.point.z);\n\t\t\tvisiblePoints.add(0.025);\n\t\t\tvisiblePoints.add(color1.x);\n\t\t\tvisiblePoints.add(color1.y);\n\t\t\tvisiblePoints.add(color1.z);\n\t\t\tvisiblePoints.add(color2.x);\n\t\t\tvisiblePoints.add(color2.y);\n\t\t\tvisiblePoints.add(color2.z);\n\t\t}\n\t}\n\n\tpointMesh->update(visiblePoints.data, visiblePoints.size / 10);\n}\n\nvoid addDebugField(Vec2 dimension, Graphics::Font* font, const char* varName, std::string value, const char* unit) {\n\tstd::stringstream string;\n\tstring.precision(4);\n\tstring << varName << \": \" << value << unit;\n\tPath::text(font, string.str(), 0.001, Vec2(-dimension.x / dimension.y * 0.99, (1 - fieldIndex * 0.05) * 0.95), Color(1, 1, 1, 1));\n\tfieldIndex++;\n}\n}\n\n};"
  },
  {
    "path": "graphics/debug/visualDebug.h",
    "content": "#pragma once\n\n#include \"profilerUI.h\"\n#include \"guiDebug.h\"\n#include <Physics3D/datastructures/buffers.h>\n\nnamespace P3D::Graphics {\n\nclass PointMesh;\nclass VectorMesh;\nclass Font;\n\nenum GraphicsProcess {\n\tUPDATE,\n\tSKYBOX,\n\tVECTORS,\n\tLIGHTING,\n\tWAIT_FOR_LOCK,\n\tPHYSICALS,\n\tORIGIN,\n\tPICKER,\n\tPROFILER,\n\tFINALIZE,\n\tOTHER,\n\tCOUNT\n};\n\nextern const char* const graphicsDebugLabels[];\nextern BreakdownAverageProfiler<GraphicsProcess> graphicsMeasure;\n\nnamespace VisualDebug {\n\nenum class SphereColissionRenderMode : int {\n\tNONE,\n\tSELECTED,\n\tALL\n};\n\nextern bool renderPiesEnabled;\nextern AddableBuffer<float> visibleVectors;\nextern std::map<P3D::Debug::VectorType, bool> vectorDebugEnabled;\nextern std::map<P3D::Debug::PointType, bool> pointDebugEnabled;\n\nextern SphereColissionRenderMode colissionSpheresMode;\nextern int colTreeRenderMode;\nextern int fieldIndex;\n\nvoid toggleVectorType(P3D::Debug::VectorType type);\nvoid togglePointType(P3D::Debug::PointType type);\nvoid updateVectorMesh(Graphics::VectorMesh* vectorMesh, AppDebug::ColoredVector* data, size_t size);\nvoid updatePointMesh(Graphics::PointMesh* pointMesh, AppDebug::ColoredPoint* data, size_t size);\n\nvoid addDebugField(Vec2 dimension, Graphics::Font* font, const char* varName, std::string value, const char* unit);\nsize_t getTheoreticalNumberOfIntersections(size_t objCount);\nstd::string toString(std::chrono::nanoseconds t);\n\ntemplate<typename T>\nvoid addDebugField(Vec2 dimension, Graphics::Font* font, const char* varName, T value, const char* unit) {\n\taddDebugField(dimension, font, varName, std::to_string(value), unit);\n}\n\ntemplate<typename EnumType>\nPieChart toPieChart(BreakdownAverageProfiler<EnumType>& profiler, const char* title, Vec2f piePosition, float pieSize) {\n\tauto results = profiler.history.avg();\n\tauto averageTotalTime = results.sum();\n\n\tPieChart chart(title, toString(averageTotalTime), piePosition, pieSize);\n\n\tfor (size_t i = 0; i < profiler.size(); i++) {\n\t\tDataPoint p = DataPoint(static_cast<float>(results[i].count()), toString(results[i]), pieColors[i], profiler.labels[i]);\n\t\tchart.add(p);\n\t}\n\n\treturn chart;\n}\n\ntemplate<typename Unit, typename EnumType>\nPieChart toPieChart(HistoricTally<Unit, EnumType>& tally, const char* title, Vec2f piePosition, float pieSize) {\n\tint sum = 0;\n\tfor (auto entry : tally.history)\n\t\tsum += (int) entry.sum();\n\n\tauto results = tally.history.avg();\n\tUnit avgTotal = (tally.history.size() != 0) ? (sum / tally.history.size()) : 0;\n\n\tPieChart chart(title, std::to_string(avgTotal), piePosition, pieSize);\n\n\tfor (size_t i = 0; i < tally.size(); i++) {\n\t\tDataPoint p = DataPoint(static_cast<float>(results[i]), std::to_string(results[i]), pieColors[i], tally.labels[i]);\n\t\tchart.add(p);\n\t}\n\n\treturn chart;\n}\n}\n\n};"
  },
  {
    "path": "graphics/ecs/components.h",
    "content": "#pragma once\n\n#include <set>\n\n#include \"../graphics/texture.h\"\n#include \"../graphics/gui/color.h\"\n#include \"Physics3D/datastructures/smartPointers.h\"\n#include \"Physics3D/math/mathUtil.h\"\n\nnamespace P3D::Graphics::Comp {\n\n// The mesh of an entity, as it is rendered\nstruct Mesh : public RC {\n\ttypedef int Flags;\n\n\tinline static Flags Flags_None = 0 << 0;\n\tinline static Flags Flags_Normal = 1 << 0;\n\tinline static Flags Flags_UV = 1 << 1;\n\tinline static Flags Flags_Tangent = 1 << 2;\n\tinline static Flags Flags_Bitangent = 1 << 3;\n\n\t// The mesh id in the mesh registry\n\tstd::size_t id;\n\n\t// Flags indicated the type of data this mesh contains\n\tFlags flags;\n\n\t// Whether the mesh is visible\n\tbool visible;\n\n\tMesh()\n\t\t: id(-1)\n\t\t, flags(Flags_None)\n\t\t, visible(false) {}\n\n\tMesh(std::size_t id, Flags flags = Flags_None)\n\t\t: id(id)\n\t\t, flags(flags)\n\t\t, visible(true) {}\n\n\tbool valid() const {\n\t\treturn id != -1;\n\t}\n};\n\nstruct Material : public RC {\n\tstatic constexpr std::size_t MAP_COUNT = 8;\n\nprivate:\n\tSRef<Graphics::Texture> maps[MAP_COUNT];\n\npublic:\n\ttypedef int Map;\n\tinline static Map Map_None = 0 << 0;\n\tinline static Map Map_Albedo = 1 << 0;\n\tinline static Map Map_Normal = 1 << 1;\n\tinline static Map Map_Metalness = 1 << 2;\n\tinline static Map Map_Roughness = 1 << 3;\n\tinline static Map Map_AO = 1 << 4;\n\tinline static Map Map_Gloss = 1 << 5;\n\tinline static Map Map_Specular = 1 << 6;\n\tinline static Map Map_Displacement = 1 << 7;\n\n\tColor albedo;\n\tfloat metalness;\n\tfloat roughness;\n\tfloat ao;\n\n\tconstexpr Material(Color albedo = Color(1), float metalness = 0.0f, float roughness = 1.0f, float ao = 1.0f)\n\t\t: albedo(albedo)\n\t\t, metalness(metalness)\n\t\t, roughness(roughness)\n\t\t, ao(ao)\n\t\t, maps{} {}\n\n\t~Material() override = default;\n\n\tvoid set(Map map, SRef<Graphics::Texture> texture) {\n\t\tmaps[ctz(map)] = texture;\n\t}\n\n\tvoid reset(Map map) {\n\t\tif (map == Map_None)\n\t\t\treturn;\n\n\t\tmaps[ctz(map)] = nullptr;\n\t}\n\n\t[[nodiscard]] SRef<Graphics::Texture> get(Map map) const {\n\t\tif (map == Map_None)\n\t\t\treturn nullptr;\n\n\t\treturn maps[ctz(map)];\n\t}\n\n\t[[nodiscard]] SRef<Graphics::Texture> get(std::size_t index) const {\n\t\tif (index >= MAP_COUNT)\n\t\t\treturn nullptr;\n\n\t\treturn maps[index];\n\t}\n\n\t/*[[nodiscard]] std::map<Map, Graphics::Texture*> getTextures() const {\n\t\tstd::map<Map, Graphics::Texture*> result;\n\n\t\tfor (std::size_t index = 0; index < MAP_COUNT; index++)\n\t\t\tif (maps[index] != nullptr)\n\t\t\t\tresult.emplace(1 << index, maps[index]);\n\n\t\treturn result;\n\t}*/\n\n\t[[nodiscard]] int getTextureCount() const {\n\t\treturn has(Map_Albedo) + has(Map_Normal) + has(Map_Metalness) + has(Map_Roughness) + has(Map_AO) + has(Map_Gloss) + has(Map_Specular) +\n\t\t\thas(Map_Displacement);\n\t}\n\n\t[[nodiscard]] bool has(Map map) const {\n\t\tif (map == Map_None)\n\t\t\treturn false;\n\n\t\treturn maps[ctz(map)] != nullptr;\n\t}\n\n\t[[nodiscard]] Map getMaps() const {\n\t\treturn Map_None | (has(Map_Albedo) ? Map_Albedo : Map_None) | (has(Map_Normal) ? Map_Normal : Map_None) | (\n\t\t\thas(Map_Metalness) ? Map_Metalness : Map_None) | (has(Map_Roughness) ? Map_Roughness : Map_None) | (has(Map_AO) ? Map_AO : Map_None) | (\n\t\t\thas(Map_Gloss) ? Map_Gloss : Map_None) | (has(Map_Specular) ? Map_Specular : Map_None) | (has(Map_Displacement)\n\t\t\t? Map_Displacement\n\t\t\t: Map_None);\n\t}\n};\n\n\n}\n"
  },
  {
    "path": "graphics/ecs/materials.h",
    "content": "#pragma once\n\n#include \"components.h\"\n\nnamespace P3D::Graphics {\n\tnamespace Materials {\n\t\tinline Comp::Material metal(const Color& color) {\n\t\t\treturn Comp::Material(color, 1.0, 0.2, 1.0);\n\t\t}\n\n\t\tinline Comp::Material metalRough(const Color& color) {\n\t\t\treturn Comp::Material(color, 1.0, 0.65, 1.0);\n\t\t}\n\n\t\tinline Comp::Material metalDiffuse(const Color& color) {\n\t\t\treturn Comp::Material(color, 0.75, 0.35, 1.0);\n\t\t}\n\n\t\tinline Comp::Material metalNoReflection(const Color& color) {\n\t\t\treturn Comp::Material(color, 1.0, 0.0, 1.0);\n\t\t}\n\n\t\tinline Comp::Material plastic(const Color& color) {\n\t\t\treturn Comp::Material(color, 0.0, 0.35, 1.0);\n\t\t}\n\n\t\tinline Comp::Material plasticDiffuse(const Color& color) {\n\t\t\treturn Comp::Material(color, 0.0, 0.8, 0.8);\n\t\t}\n\n\t\tinline Comp::Material plasticDark(const Color& color) {\n\t\t\treturn Comp::Material(color, 0.0, 0.0, 0.0);\n\t\t}\n\n\t\tinline Comp::Material plasticNoReflection(const Color& color) {\n\t\t\treturn Comp::Material(color, 0.0, 0.0, 1.0);\n\t\t}\n\n\t\tinline static Comp::Material COPPER = metal(Color::get<0xB24819>());\n\t\tinline static Comp::Material GOLD = metal(Color::get<0xFFDE00>());\n\t\tinline static Comp::Material SILVER = metal(Color::get<0xD9D9D9>());\n\t\tinline static Comp::Material IRON = metalDiffuse(Color::get<0xAAAAAA>());\n\t\tinline static Comp::Material WHITE = plastic(Color::get<0xFFFFFF>());\n\t\tinline static Comp::Material RED = plasticDiffuse(Color::get<0xFF0000>());\n\t\tinline static Comp::Material GREEN = plasticDiffuse(Color::get<0x00FF00>());\n\t\tinline static Comp::Material BLUE = plasticDiffuse(Color::get<0x0000FF>());\n\t}\n};"
  },
  {
    "path": "graphics/extendedTriangleMesh.cpp",
    "content": "#include \"core.h\"\n#include \"extendedTriangleMesh.h\"\n\n#include <Physics3D/geometry/polyhedron.h>\n\nnamespace P3D::Graphics {\n\n// Todo move to TriangleMesh\nExtendedTriangleMesh ExtendedTriangleMesh::generateSmoothNormalsShape(const TriangleMesh& underlyingMesh) {\n\tVec3f* normalBuffer = new Vec3f[underlyingMesh.vertexCount];\n\tunderlyingMesh.computeNormals(normalBuffer);\n\n\tExtendedTriangleMesh result(underlyingMesh);\n\tresult.setNormalBuffer(SRef<const Vec3f[]>(normalBuffer));\n\n\treturn result;\n}\n\n// Todo move to TriangleMesh\nExtendedTriangleMesh ExtendedTriangleMesh::generateSplitNormalsShape(const TriangleMesh& underlyingMesh) {\n\tVec3f* newVertices = new Vec3f[underlyingMesh.triangleCount * 3];\n\tVec3f* newNormals = new Vec3f[underlyingMesh.triangleCount * 3];\n\tTriangle* newTriangles = new Triangle[underlyingMesh.triangleCount];\n\n\tfor (int i = 0; i < underlyingMesh.triangleCount; i++) {\n\t\tTriangle t = underlyingMesh.getTriangle(i);\n\n\t\tVec3f a = underlyingMesh.getVertex(t.firstIndex);\n\t\tVec3f b = underlyingMesh.getVertex(t.secondIndex);\n\t\tVec3f c = underlyingMesh.getVertex(t.thirdIndex);\n\n\t\tVec3f normal = normalize(underlyingMesh.getNormalVecOfTriangle(t));\n\n\t\tnewVertices[i * 3] = a;\n\t\tnewVertices[i * 3 + 1] = b;\n\t\tnewVertices[i * 3 + 2] = c;\n\n\n\t\tnewNormals[i * 3] = normal;\n\t\tnewNormals[i * 3 + 1] = normal;\n\t\tnewNormals[i * 3 + 2] = normal;\n\n\t\tnewTriangles[i] = Triangle{i * 3, i * 3 + 1, i * 3 + 2};\n\t}\n\n\tExtendedTriangleMesh result(TriangleMesh(underlyingMesh.triangleCount * 3, underlyingMesh.triangleCount, newVertices, newTriangles));\n\tresult.setNormalBuffer(SRef<const Vec3f[]>(newNormals));\n\n\treturn result;\n}\n\n}\n"
  },
  {
    "path": "graphics/extendedTriangleMesh.h",
    "content": "#pragma once\n\n#include <Physics3D/math/linalg/vec.h>\n#include <Physics3D/geometry/triangleMesh.h>\n#include <Physics3D/datastructures/sharedArray.h>\n\n#include \"ecs/components.h\"\n\nclass Polyhedron;\n\nnamespace P3D::Graphics {\n\nstruct ExtendedTriangleMesh : public TriangleMesh {\n\tSRef<const Vec3f[]> normals;\n\tSRef<const Vec2f[]> uvs;\n\tSRef<const Vec3f[]> tangents;\n\tSRef<const Vec3f[]> bitangents;\n\n\tExtendedTriangleMesh()\n\t\t: TriangleMesh()\n\t\t, normals(nullptr)\n\t\t, uvs(nullptr)\n\t\t, tangents(nullptr)\n\t\t, bitangents(nullptr) {}\n\n\tExtendedTriangleMesh(const Vec3f* vertices, int vertexCount, const Triangle* triangles, int triangleCount)\n\t\t: TriangleMesh(vertexCount, triangleCount, vertices, triangles) {\n\t}\n\n\texplicit ExtendedTriangleMesh(const TriangleMesh& shape) : TriangleMesh(shape) {}\n\n\tvoid setNormalBuffer(const SRef<const Vec3f[]>& normals) {\n\t\tthis->normals = normals;\n\t}\n\n\tvoid setUVBuffer(const SRef<const Vec2f[]>& uvs) {\n\t\tthis->uvs = uvs;\n\t}\n\n\tvoid setTangentBuffer(const SRef<const Vec3f[]>& tangents) {\n\t\tthis->tangents = tangents;\n\t}\n\n\tvoid setBitangentBuffer(const SRef<const Vec3f[]>& bitangents) {\n\t\tthis->bitangents = bitangents;\n\t}\n\n\tComp::Mesh::Flags getFlags() const {\n\t\tusing namespace Comp;\n\t\treturn Mesh::Flags_None\n\t\t\t| (normals != nullptr ? Mesh::Flags_Normal : Mesh::Flags_None)\n\t\t\t| (uvs != nullptr ? Mesh::Flags_UV : Mesh::Flags_None)\n\t\t\t| (tangents != nullptr ? Mesh::Flags_Tangent : Mesh::Flags_None)\n\t\t\t| (bitangents != nullptr ? Mesh::Flags_Bitangent : Mesh::Flags_None);\n\t}\n\n\tstatic ExtendedTriangleMesh generateSmoothNormalsShape(const TriangleMesh& underlyingMesh);\n\tstatic ExtendedTriangleMesh generateSplitNormalsShape(const TriangleMesh& underlyingMesh);\n};\n\n};\n"
  },
  {
    "path": "graphics/font.cpp",
    "content": "#include \"core.h\"\n\n#include \"font.h\"\n\n#include <GL/glew.h>\n#include <GLFW/glfw3.h>\n\n#include \"gui/gui.h\"\n#include \"mesh/primitive.h\"\n\n#include \"path/path.h\"\n\n#include <string>\n\nnamespace P3D::Graphics {\n\n#pragma region Character\n\nCharacter::Character() : id(0), x(0), y(0), width(0), height(0), bx(0), by(0), advance(0) {\n\n};\n\nCharacter::Character(unsigned int id, int x, int y, int width, int height, int bx, int by, unsigned int advance) : id(id), x(x), y(y), width(width), height(height), bx(bx), by(by), advance(advance) {\n\n};\n\n#pragma endregion\n\n#pragma region Font\n\nFont::Font() {\n\n}\n\nFont::Font(std::string font) {\n\tFT_Library library;\n\tFT_Face face;\n\tFT_Error error;\n\n\tLog::subject s(font);\n\n\t// Init\n\terror = FT_Init_FreeType(&library);\n\tif (error) {\n\t\tLog::error(\"Error loading freetype library\");\n\n\t\treturn;\n\t}\n\n\terror = FT_New_Face(library, font.c_str(), 0, &face);\n\n\tif (error) {\n\t\tLog::error(\"FREETYTPE: Failed to read font (%s)\", font.c_str());\n\t\tif (error == FT_Err_Unknown_File_Format)\n\t\t\tLog::error(\"FREETYTPE: Font format not supported\", font.c_str());\n\n\t\treturn;\n\t}\n\n\tFT_Set_Pixel_Sizes(face, 0, 48);\n\tglPixelStorei(GL_UNPACK_ALIGNMENT, 1);\n\n\t// Calculate atlas dimension\n\tint maxCharacterHeight = (face->size->metrics.height >> 6);\n\tint maxDimension = maxCharacterHeight * ceil(sqrt(CHARACTER_COUNT));\n\tint atlasDimension = 1;\n\n\t// Resize atlas to maxDimension with powers of 2\n\twhile (atlasDimension < maxDimension)\n\t\tatlasDimension <<= 1;\n\n\t// Allocate memory\n\tint penX = 0;\n\tint penY = 0;\n\tchar* pixels = (char*) calloc(atlasDimension * atlasDimension * 4, 1);\n\n\t// Render glyphs to atlas\n\tfor (unsigned char character = 0; character < CHARACTER_COUNT; character++) {\n\t\tif (FT_Load_Char(face, character, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT)) {\n\t\t\tLog::error(\"FREETYTPE: Failed to load Glyph\");\n\t\t\tcontinue;\n\t\t}\n\n\t\tFT_Bitmap* bitmap = &face->glyph->bitmap;\n\n\t\tif (penX + static_cast<int>(bitmap->width) >= atlasDimension) {\n\t\t\tpenX = 0;\n\t\t\tpenY += maxCharacterHeight;\n\t\t}\n\n\t\tfor (int row = 0; row < static_cast<int>(bitmap->rows); row++) {\n\t\t\tfor (int col = 0; col < static_cast<int>(bitmap->width); col++) {\n\t\t\t\tint x = penX + col;\n\t\t\t\tint y = penY + row;\n\t\t\t\tpixels[(x + y * atlasDimension) * 4 + 0] = 0xff;\n\t\t\t\tpixels[(x + y * atlasDimension) * 4 + 1] = 0xff;\n\t\t\t\tpixels[(x + y * atlasDimension) * 4 + 2] = 0xff;\n\t\t\t\tpixels[(x + y * atlasDimension) * 4 + 3] = bitmap->buffer[col + row * bitmap->pitch];\n\t\t\t}\n\t\t}\n\n\t\tcharacters[character] = Character(\n\t\t\tcharacter,\n\t\t\tpenX,\n\t\t\tpenY,\n\t\t\tbitmap->width,\n\t\t\tbitmap->rows + 1,\n\t\t\tface->glyph->bitmap_left,\n\t\t\tface->glyph->bitmap_top,\n\t\t\tface->glyph->advance.x\n\t\t);\n\n\t\tpenX += maxCharacterHeight;\n\t}\n\n\tFT_Done_Face(face);\n\tFT_Done_FreeType(library);\n\n\tatlas = std::make_shared<Texture>(atlasDimension, atlasDimension, pixels, GL_RGBA);\n}\n\nvoid Font::close() {\n\t// TODO remove\n}\n\nVec2f Font::size(const std::string& text, double fontSize) {\n\tstd::string::const_iterator iterator;\n\tfloat width = 0.0f;\n\tfloat height = 0.0f;\n\n\tfor (iterator = text.begin(); iterator != text.end(); iterator++) {\n\t\tCharacter& character = characters[*iterator];\n\t\tfloat advance = character.advance >> 6;\n\t\tif (iterator == text.begin())\n\t\t\twidth += (advance - character.bearing.x) * fontSize;\n\t\telse if (iterator == text.end() - 1)\n\t\t\twidth += (character.bearing.x + character.size.x) * fontSize;\n\t\telse\n\t\t\twidth += advance * fontSize;\n\n\t\theight = fmax(character.size.y * fontSize, height);\n\t}\n\n\treturn Vec2f(width, height);\n}\n\nCharacter& Font::getCharacter(unsigned int id) {\n\tif (id >= CHARACTER_COUNT)\n\t\treturn characters[32];\n\n\treturn characters[id];\n}\n\nunsigned int Font::getAtlasID() const {\n\treturn atlas->getID();\n}\n\nunsigned int Font::getAtlasWidth() const {\n\treturn atlas->getWidth();\n}\n\nunsigned int Font::getAtlasHeight() const {\n\treturn atlas->getHeight();\n}\n\nSRef<Texture> Font::getAtlas() {\n\treturn atlas;\n}\n\n#pragma endregion\n\n};"
  },
  {
    "path": "graphics/font.h",
    "content": "#pragma once\n\n#include <ft2build.h>\n#include FT_FREETYPE_H\n#include \"texture.h\"\n#include <string>\n\n#define CHARACTER_COUNT 128\n\nnamespace P3D::Graphics {\n\nstruct Character {\n\tunion {\n\t\tstruct {\n\t\t\tint x;\n\t\t\tint y;\n\t\t};\n\t\tVec2i origin;\n\t};\n\n\tunion {\n\t\tstruct {\n\t\t\tint width;\n\t\t\tint height;\n\t\t};\n\t\tVec2i size;\n\t};\n\n\tunion {\n\t\tstruct {\n\t\t\tint bx;\n\t\t\tint by;\n\t\t};\n\t\tVec2i bearing;\n\t};\n\n\tunsigned int advance;\n\tunsigned int id;\n\n\tCharacter();\n\tCharacter(unsigned int id, int x, int y, int width, int height, int bx, int by, unsigned int advance);\n};\n\nclass Font {\nprivate:\n\tSRef<Texture> atlas;\n\tCharacter characters[CHARACTER_COUNT];\n\npublic:\n\tFont();\n\tFont(std::string font);\n\n\tvoid close();\n\n\tVec2f size(const std::string& text, double scale);\n\n\tSRef<Texture> getAtlas();\n\tCharacter& getCharacter(unsigned int id);\n\tunsigned int getAtlasID() const;\n\tunsigned int getAtlasWidth() const;\n\tunsigned int getAtlasHeight() const;\n};\n\n};"
  },
  {
    "path": "graphics/glfwUtils.cpp",
    "content": "#include \"core.h\"\n\n#include \"glfwUtils.h\"\n\n#include <GLFW/glfw3.h>\n\n//#define STB_IMAGE_IMPLEMENTATION\n#include <stb_image.h>\n\n#include <stdexcept>\n\nnamespace P3D::Graphics {\n\nnamespace GLFW {\n\nnamespace Cursor {\n\tint ARROW = GLFW_ARROW_CURSOR;\n\tint IBEAM = GLFW_IBEAM_CURSOR;\n\tint CROSSHAIR = GLFW_CROSSHAIR_CURSOR;\n\tint HAND = GLFW_HAND_CURSOR;\n\tint HRESIZE = GLFW_HRESIZE_CURSOR;\n\tint VRESIZE = GLFW_VRESIZE_CURSOR;\n}\n\nGLFWwindow* currentContext = nullptr;\nGLFWmonitor* currentMonitor = nullptr;\nint windowPosition[2] { 0, 0 };\nint windowSize[2] { 0, 0 };\n\t\nGLFWcursor* currentCursor;\nint currentCursorType;\n\nbool init() {\n\treturn glfwInit();\n}\n\nvoid terminate() {\n\tglfwTerminate();\n}\n\nvoid setCurrentContext(GLFWwindow* context) {\n\tcurrentContext = context;\n\tglfwMakeContextCurrent(currentContext);\n\n\tcurrentMonitor = glfwGetPrimaryMonitor();\n\tglfwGetWindowPos(currentContext, &windowPosition[0], &windowPosition[1]);\n\tglfwGetWindowSize(currentContext, &windowSize[0], &windowSize[1]);\n}\n\nGLFWwindow* createContext(int width, int height, const char* title) {\n\tGLFWwindow* context = glfwCreateWindow(width, height, title, nullptr, nullptr);\n\t\n\treturn context;\n}\n\nbool validContext(GLFWwindow* context) {\n\treturn context != nullptr;\n}\n\nGLFWwindow* getCurrentContext() {\n\treturn currentContext;\n}\n\nbool isFullScreen() {\n\treturn glfwGetWindowMonitor(currentContext) != nullptr;\n}\n\nvoid setFullScreen(bool fullscreen) {\n\tif (isFullScreen() == fullscreen)\n\t\treturn;\n\n\tif (fullscreen) {\n\t\tglfwGetWindowPos(currentContext, &windowPosition[0], &windowPosition[1]);\n\t\tglfwGetWindowSize(currentContext, &windowSize[0], &windowSize[1]);\n\n\t\tconst GLFWvidmode* mode = glfwGetVideoMode(glfwGetPrimaryMonitor());\n\t\tglfwSetWindowMonitor(currentContext, currentMonitor, 0, 0, mode->width, mode->height, 0);\n\t} else {\n\t\tglfwSetWindowMonitor(currentContext, nullptr, windowPosition[0], windowPosition[1], windowSize[0], windowSize[1], 0);\n\t}\n}\n\nvoid swapFullScreen() {\n\tsetFullScreen(!isFullScreen());\n}\n\nvoid swapInterval(int interval) {\n\tglfwSwapInterval(interval);\n}\n\nvoid swapBuffers() {\n\tglfwSwapBuffers(currentContext);\n}\n\nvoid pollEvents() {\n\tglfwPollEvents();\n}\n\nvoid closeWindow() {\n\tglfwSetWindowShouldClose(currentContext, GLFW_TRUE);\n}\n\nbool isWindowClosed() {\n\treturn glfwWindowShouldClose(currentContext);\n}\n\nvoid setMultisampleSamples(int samples) {\n\tglfwWindowHint(GLFW_SAMPLES, samples);\n};\n\nVec2i getWindowSize() {\n\tint width;\n\tint height;\n\tglfwGetWindowSize(currentContext, &width, &height);\n\treturn Vec2i(width, height);\n}\n\nVec4i getFrameSize() {\n\tint left;\n\tint top;\n\tint right;\n\tint bottom;\n\tglfwGetWindowFrameSize(currentContext, &left, &top, &right, &bottom);\n\treturn Vec4i(left, top, right, bottom);\n}\n\nvoid enableCursor() {\n\tglfwSetInputMode(currentContext, GLFW_CURSOR, GLFW_CURSOR_NORMAL);\n}\n\nvoid disableCursor() {\n\tglfwSetInputMode(currentContext, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);\n}\n\nvoid setCursor(int type) {\n\tif (currentCursorType == type)\n\t\treturn;\n\n\tif (currentCursor)\n\t\tglfwDestroyCursor(currentCursor);\n\t\n\tcurrentCursorType = type;\n\tcurrentCursor = glfwCreateStandardCursor(type);\n\n\tglfwSetCursor(currentContext, currentCursor);\n}\n\n\nvoid setWindowIcon(const GLFWimage* image) {\n\tglfwSetWindowIcon(currentContext, 1, image);\n}\n\nvoid setWindowIconFromPath(const char* path) {\n\tGLFWimage img;\n\tint channels;\n\timg.pixels = stbi_load(path, &img.width, &img.height, &channels, STBI_rgb_alpha);\n\n\tif(img.pixels != nullptr) {\n\t\tGraphics::GLFW::setWindowIcon(&img);\n\t\tstbi_image_free(img.pixels);\n\t} else {\n\t\tthrow std::runtime_error(\"Logo not found!\");\n\t}\n}\n\n}\n\n};"
  },
  {
    "path": "graphics/glfwUtils.h",
    "content": "#pragma once\n\nstruct GLFWwindow;\nstruct GLFWimage;\n\nnamespace P3D::Graphics {\n\nnamespace GLFW {\n\nnamespace Cursor {\n\textern int ARROW;\n\textern int IBEAM;\n\textern int CROSSHAIR;\n\textern int HAND;\n\textern int HRESIZE;\n\textern int VRESIZE;\n}\n\nextern bool init();\nextern void terminate();\n\nextern GLFWwindow* getCurrentContext();\nextern GLFWwindow* createContext(int width, int height, const char* title);\nextern void setCurrentContext(GLFWwindow* context);\nextern bool validContext(GLFWwindow* context);\n\nextern void swapInterval(int interval);\nextern void swapBuffers();\nextern void pollEvents();\n\nextern bool isFullScreen();\nextern void setFullScreen(bool fullscreen);\nextern void swapFullScreen();\n\t\nextern void closeWindow();\nextern bool isWindowClosed();\n\nextern Vec2i getWindowSize();\nextern Vec4i getFrameSize();\n\nextern void enableCursor();\nextern void disableCursor();\nextern void setCursor(int type);\n\nextern void setMultisampleSamples(int samples);\n\nextern void setWindowIcon(const GLFWimage* image);\nextern void setWindowIconFromPath(const char* path);\n}\n\n};"
  },
  {
    "path": "graphics/graphics.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <VCProjectVersion>15.0</VCProjectVersion>\n    <ProjectGuid>{13E417C8-0C80-482C-A415-8C11A5C770DA}</ProjectGuid>\n    <RootNamespace>graphics</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>MultiByte</CharacterSet>\n    <WholeProgramOptimization>false</WholeProgramOptimization>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup />\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalIncludeDirectories>$(SolutionDir)include;$(SolutionDir)graphics;$(SolutionDir);</AdditionalIncludeDirectories>\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <PrecompiledHeaderFile>core.h</PrecompiledHeaderFile>\n      <PreprocessorDefinitions>FT2_BUILD_LIBRARY;GLEW_STATIC;_MBCS;NDEBUG;%(PreprocessorDefinitions);</PreprocessorDefinitions>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n      <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n    <Lib>\n      <AdditionalDependencies>freetype.lib;glfw3.lib;glew32s.lib;opengl32.lib;</AdditionalDependencies>\n    </Lib>\n    <Lib>\n      <AdditionalLibraryDirectories>$(SolutionDir)lib;$(OutDir)</AdditionalLibraryDirectories>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalIncludeDirectories>$(SolutionDir)include;$(SolutionDir)graphics;$(SolutionDir);</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>GLEW_STATIC;_MBCS;%(PreprocessorDefinitions);FT2_BUILD_LIBRARY;</PreprocessorDefinitions>\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <PrecompiledHeaderFile>core.h</PrecompiledHeaderFile>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>\n    </ClCompile>\n    <Lib>\n      <AdditionalDependencies>freetype.lib;glfw3.lib;glew32s.lib;opengl32.lib;</AdditionalDependencies>\n      <AdditionalLibraryDirectories>$(SolutionDir)lib;$(OutDir)</AdditionalLibraryDirectories>\n      <LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>\n    </Lib>\n    <ProjectReference>\n      <LinkLibraryDependencies>false</LinkLibraryDependencies>\n    </ProjectReference>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <Link>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"..\\include\\imgui\\imgui.cpp\">\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">NotUsing</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"..\\include\\imgui\\imgui_demo.cpp\">\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">NotUsing</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"..\\include\\imgui\\imgui_draw.cpp\">\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">NotUsing</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"..\\include\\imgui\\imgui_impl_glfw.cpp\" />\n    <ClCompile Include=\"..\\include\\imgui\\imgui_impl_opengl3.cpp\" />\n    <ClCompile Include=\"..\\include\\imgui\\imgui_widgets.cpp\">\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">NotUsing</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"bindable.cpp\" />\n    <ClCompile Include=\"buffers\\bufferLayout.cpp\" />\n    <ClCompile Include=\"buffers\\frameBuffer.cpp\" />\n    <ClCompile Include=\"buffers\\indexBuffer.cpp\" />\n    <ClCompile Include=\"buffers\\renderBuffer.cpp\" />\n    <ClCompile Include=\"buffers\\vertexArray.cpp\" />\n    <ClCompile Include=\"buffers\\vertexBuffer.cpp\" />\n    <ClCompile Include=\"core.cpp\">\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeaderFile Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">core.h</PrecompiledHeaderFile>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Create</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"debug\\guiDebug.cpp\" />\n    <ClCompile Include=\"debug\\profilerUI.cpp\" />\n    <ClCompile Include=\"font.cpp\" />\n    <ClCompile Include=\"gui\\gui.cpp\" />\n    <ClCompile Include=\"gui\\guiUtils.cpp\" />\n    <ClCompile Include=\"gui\\imgui\\imguiStyle.cpp\" />\n    <ClCompile Include=\"meshRegistry.cpp\" />\n    <ClCompile Include=\"mesh\\abstractMesh.cpp\" />\n    <ClCompile Include=\"mesh\\arrayMesh.cpp\" />\n    <ClCompile Include=\"mesh\\indexedMesh.cpp\" />\n    <ClCompile Include=\"mesh\\pointMesh.cpp\" />\n    <ClCompile Include=\"mesh\\vectorMesh.cpp\" />\n    <ClCompile Include=\"path\\path.cpp\" />\n    <ClCompile Include=\"path\\path3D.cpp\" />\n    <ClCompile Include=\"glfwUtils.cpp\" />\n    <ClCompile Include=\"resource\\fontResource.cpp\" />\n    <ClCompile Include=\"resource\\shaderResource.cpp\" />\n    <ClCompile Include=\"resource\\textureResource.cpp\" />\n    <ClCompile Include=\"shader\\propertiesParser.cpp\" />\n    <ClCompile Include=\"shader\\shader.cpp\" />\n    <ClCompile Include=\"shader\\lexer.cpp\" />\n    <ClCompile Include=\"shader\\parser.cpp\" />\n    <ClCompile Include=\"shader\\shaders.cpp\" />\n    <ClCompile Include=\"renderer.cpp\" />\n    <ClCompile Include=\"texture.cpp\" />\n    <ClCompile Include=\"debug\\visualDebug.cpp\" />\n    <ClCompile Include=\"extendedTriangleMesh.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"..\\include\\imgui\\imconfig.h\" />\n    <ClInclude Include=\"..\\include\\imgui\\imgui.h\" />\n    <ClInclude Include=\"..\\include\\imgui\\imgui_impl_glfw.h\" />\n    <ClInclude Include=\"..\\include\\imgui\\imgui_impl_opengl3.h\" />\n    <ClInclude Include=\"..\\include\\imgui\\imgui_internal.h\" />\n    <ClInclude Include=\"..\\include\\imgui\\imstb_rectpack.h\" />\n    <ClInclude Include=\"..\\include\\imgui\\imstb_textedit.h\" />\n    <ClInclude Include=\"..\\include\\imgui\\imstb_truetype.h\" />\n    <ClInclude Include=\"batch\\batch.h\" />\n    <ClInclude Include=\"batch\\batchConfig.h\" />\n    <ClInclude Include=\"batch\\commandBatch.h\" />\n    <ClInclude Include=\"batch\\guiBatch.h\" />\n    <ClInclude Include=\"batch\\instanceBatch.h\" />\n    <ClInclude Include=\"batch\\instanceBatchManager.h\" />\n    <ClInclude Include=\"bindable.h\" />\n    <ClInclude Include=\"buffers\\bufferLayout.h\" />\n    <ClInclude Include=\"buffers\\frameBuffer.h\" />\n    <ClInclude Include=\"buffers\\indexBuffer.h\" />\n    <ClInclude Include=\"buffers\\renderBuffer.h\" />\n    <ClInclude Include=\"buffers\\vertexArray.h\" />\n    <ClInclude Include=\"buffers\\vertexBuffer.h\" />\n    <ClInclude Include=\"core.h\" />\n    <ClInclude Include=\"debug\\guiDebug.h\" />\n    <ClInclude Include=\"debug\\profilerUI.h\" />\n    <ClInclude Include=\"ecs\\components.h\" />\n    <ClInclude Include=\"ecs\\materials.h\" />\n    <ClInclude Include=\"font.h\" />\n    <ClInclude Include=\"gui\\color.h\" />\n    <ClInclude Include=\"gui\\gui.h\" />\n    <ClInclude Include=\"gui\\guiUtils.h\" />\n    <ClInclude Include=\"gui\\imgui\\imguiStyle.h\" />\n    <ClInclude Include=\"gui\\imgui\\imguiExtension.h\" />\n    <ClInclude Include=\"gui\\orderedVector.h\" />\n    <ClInclude Include=\"meshRegistry.h\" />\n    <ClInclude Include=\"mesh\\abstractMesh.h\" />\n    <ClInclude Include=\"mesh\\arrayMesh.h\" />\n    <ClInclude Include=\"mesh\\indexedMesh.h\" />\n    <ClInclude Include=\"mesh\\pointMesh.h\" />\n    <ClInclude Include=\"mesh\\primitive.h\" />\n    <ClInclude Include=\"mesh\\vectorMesh.h\" />\n    <ClInclude Include=\"path\\path.h\" />\n    <ClInclude Include=\"path\\path3D.h\" />\n    <ClInclude Include=\"renderer.h\" />\n    <ClInclude Include=\"glfwUtils.h\" />\n    <ClInclude Include=\"resource\\fontResource.h\" />\n    <ClInclude Include=\"resource\\shaderResource.h\" />\n    <ClInclude Include=\"resource\\textureResource.h\" />\n    <ClInclude Include=\"shader\\propertiesParser.h\" />\n    <ClInclude Include=\"shader\\shader.h\" />\n    <ClInclude Include=\"shader\\lexer.h\" />\n    <ClInclude Include=\"shader\\parser.h\" />\n    <ClInclude Include=\"shader\\shaders.h\" />\n    <ClInclude Include=\"texture.h\" />\n    <ClInclude Include=\"debug\\threePhaseBuffer.h\" />\n    <ClInclude Include=\"debug\\visualDebug.h\" />\n    <ClInclude Include=\"extendedTriangleMesh.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"..\\res\\shaders\\gui.shader\" />\n    <None Include=\"..\\res\\shaders\\quad.shader\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Natvis Include=\"component.natvis\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "graphics/gui/color.h",
    "content": "#pragma once\n\n#include <Physics3D/math/linalg/vec.h>\n\nnamespace P3D::Graphics {\n\ntemplate<typename T>\nstruct ColorTemplate {\n\tunion {\n\t\tstruct {\n\t\t\tT r;\n\t\t\tT g;\n\t\t\tT b;\n\t\t\tT a;\n\t\t};\n\n\t\tT data[4];\n\t};\n\n\tconstexpr ColorTemplate() : r(static_cast<T>(0)), g(static_cast<T>(0)), b(static_cast<T>(0)), a(static_cast<T>(1)) {}\n\tconstexpr ColorTemplate(T r, T g, T b) : r(r), g(g), b(b), a(a) {}\n\tconstexpr ColorTemplate(T r, T g, T b, T a) : r(r), g(g), b(b), a(a) {}\n\tconstexpr ColorTemplate(T value) : r(value), g(value), b(value), a(static_cast<T>(1)) {}\n\tconstexpr ColorTemplate(T value, T a) : r(value), g(value), b(value), a(a) {}\n\tconstexpr ColorTemplate(const Vector<T, 3>& rgb) : r(rgb.x), g(rgb.y), b(rgb.z), a(static_cast<T>(1)) {}\n\tconstexpr ColorTemplate(const Vector<T, 4> rgba) : r(rgba.x), g(rgba.y), b(rgba.z), a(rgba.w) {}\n\n\t~ColorTemplate() = default;\n\n\tconstexpr operator Vector<T, 3>() const {\n\t\treturn Vector<T, 3> { r, g, b };\n\t}\n\n\tconstexpr operator Vector<T, 4>() const {\n\t\treturn Vector<T, 4> { r, g, b, a };\n\t}\n\n\tconstexpr T& operator[](size_t index) noexcept {\n\t\treturn data[index];\n\t}\n\n\t// format: 0xRRGGBBAA\n\ttemplate<int Hex, bool Alpha = false>\n\tconstexpr static ColorTemplate<T> get() {\n\t\tif constexpr (Alpha == true) {\n\t\t\tconstexpr int value = Hex;\n\t\t\treturn ColorTemplate<T> {\n\t\t\t\tstatic_cast<T>(value >> 24 & 0xFF) / static_cast<T>(255),\n\t\t\t\tstatic_cast<T>(value >> 16 & 0xFF) / static_cast<T>(255),\n\t\t\t\tstatic_cast<T>(value >> 8 & 0xFF) / static_cast<T>(255),\n\t\t\t\tstatic_cast<T>(value & 0xFF) / static_cast<T>(255)\n\t\t\t};\n\t\t} else {\n\t\t\tconstexpr int value = Hex << 8 | 0xFF;\n\t\t\treturn ColorTemplate<T> {\n\t\t\t\tstatic_cast<T>(value >> 24 & 0xFF) / static_cast<T>(255),\n\t\t\t\tstatic_cast<T>(value >> 16 & 0xFF) / static_cast<T>(255),\n\t\t\t\tstatic_cast<T>(value >> 8 & 0xFF) / static_cast<T>(255),\n\t\t\t\tstatic_cast<T>(value & 0xFF) / static_cast<T>(255)\n\t\t\t};\n\t\t}\n\t}\n\n\tconstexpr static ColorTemplate<T> hsvaToRgba(const ColorTemplate<T>& hsva) {\n\t\tconstexpr T h = hsva.r * static_cast<T>(360);\n\t\tconstexpr T s = hsva.g;\n\t\tconstexpr T v = hsva.b;\n\t\tconstexpr T a = hsva.a;\n\n\t\tif (s == static_cast<T>(0))\n\t\t\treturn ColorTemplate<T>(v, v, v, a);\n\n\t\tconstexpr int hi = static_cast<int>(h / static_cast<T>(60)) % 6;\n\t\tconstexpr T f = h / static_cast<T>(60) - static_cast<float>(hi);\n\t\tconstexpr T p = v * (static_cast<T>(1) - s);\n\t\tconstexpr T q = v * (static_cast<T>(1) - s * f);\n\t\tconstexpr T t = v * (static_cast<T>(1) - s * (static_cast<T>(1) - f));\n\n\t\tswitch (hi) {\n\t\t\tcase 0:\n\t\t\t\treturn ColorTemplate<T>(v, t, p, a);\n\t\t\tcase 1:\n\t\t\t\treturn ColorTemplate<T>(q, v, p, a);\n\t\t\tcase 2:\n\t\t\t\treturn ColorTemplate<T>(p, v, t, a);\n\t\t\tcase 3:\n\t\t\t\treturn ColorTemplate<T>(p, q, v, a);\n\t\t\tcase 4:\n\t\t\t\treturn ColorTemplate<T>(t, p, v, a);\n\t\t\tcase 5:\n\t\t\t\treturn ColorTemplate<T>(v, p, q, a);\n\t\t\tdefault:\n\t\t\t\treturn ColorTemplate<T>();\n\t\t}\n\t}\n\n\tconstexpr static ColorTemplate<T> rgbaToHsva(const ColorTemplate<T>& rgba) {\n\t\tconstexpr T r = rgba.r;\n\t\tconstexpr T g = rgba.g;\n\t\tconstexpr T b = rgba.b;\n\t\tconstexpr T a = rgba.a;\n\n\t\t\n\t\tconstexpr T min = fmin(fmin(r, g), b);\n\t\tconstexpr T max = fmax(fmax(r, g), b);\n\t\tconstexpr T d = max - min;\n\t\t\n\t\tif (d == static_cast<T>(0))\n\t\t\treturn ColorTemplate<T>(static_cast<T>(0), static_cast<T>(0), max);\n\t\t\n\t\tconstexpr T dr = ((max - r) / static_cast<T>(6) + max / static_cast<T>(2)) / d;\n\t\tconstexpr T dg = ((max - g) / static_cast<T>(6) + max / static_cast<T>(2)) / d;\n\t\tconstexpr T db = ((max - b) / static_cast<T>(6) + max / static_cast<T>(2)) / d;\n\n\t\tT h = static_cast<T>(0);\n\t\tif (r == max)\n\t\t\th = db - dg;\n\t\telse if (g == max)\n\t\t\th = static_cast<T>(1) / static_cast<T>(3) + dr - db;\n\t\telse if (b == max)\n\t\t\th = static_cast<T>(2) / static_cast<T>(3) + dg - dr;\n\n\t\tif (h < static_cast<T>(0))\n\t\t\th += static_cast<T>(1);\n\t\tif (h > static_cast<T>(1))\n\t\t\th -= static_cast<T>(1);\n\n\t\treturn ColorTemplate<T>(h, d / max, max);\n\t}\n\n\tconstexpr static ColorTemplate<T> blend(const ColorTemplate<T>& color1, const ColorTemplate<T>& color2, T blend) {\n\t\treturn (static_cast<T>(1) - blend) * color1 + blend * color2;\n\t}\n};\n\ntemplate<typename T>\nconstexpr ColorTemplate<T>& operator+=(ColorTemplate<T>& first, const ColorTemplate<T>& second) {\n\tfirst.r += second.r;\n\tfirst.g += second.g;\n\tfirst.b += second.b;\n\tfirst.a += second.a;\n\treturn first;\n}\n\ntemplate<typename T>\nconstexpr ColorTemplate<T> operator+(const ColorTemplate<T>& first, const \nColorTemplate<T>& second) {\n\treturn ColorTemplate<T> {\n\t\tfirst.r + second.r,\n\t\tfirst.g + second.g,\n\t\tfirst.b + second.b,\n\t\tfirst.a + second.a\n\t};\n}\n\ntemplate<typename T>\nconstexpr ColorTemplate<T> operator*(const ColorTemplate<T>& color, T factor) {\n\treturn ColorTemplate<T> {\n\t\tcolor.r * factor,\n\t\tcolor.g * factor,\n\t\tcolor.b * factor,\n\t\tcolor.a * factor\n\t};\n}\n\ntemplate<typename T>\nconstexpr ColorTemplate<T> operator*(T factor, const ColorTemplate<T>& color) {\n\treturn ColorTemplate<T> {\n\t\tfactor * color.r,\n\t\tfactor * color.g,\n\t\tfactor * color.b,\n\t\tfactor * color.a\n\t};\n}\n\t\ntypedef ColorTemplate<float> Color;\n\nnamespace Colors {\n\tconstexpr static Color DISABLED = Color::get<0xA0A0A0>();\n\tconstexpr static Color ACCENT   = Color::get<0x1F6678>();\n\tconstexpr static Color BACK     = Color::get<0x4D4D4D>();\n\tconstexpr static Color ALPHA    = Color::get<0x0, true>();\n\t\t\t\t\t \t\t\t\t\t\t\t\n\tconstexpr static Color RGB_R    = Color::get<0xFF0000>();\n\tconstexpr static Color RGB_G    = Color::get<0x00FF00>();\n\tconstexpr static Color RGB_B    = Color::get<0x0000FF>();\n\tconstexpr static Color A        = Color::get<0x0, true>();\n\t\t\t\t\t \t\t\t\t\t\t\t\n\tconstexpr static Color NAVY     = Color::get<0x001F3F>();\n\tconstexpr static Color BLUE     = Color::get<0x0074D9>();\n\tconstexpr static Color AQUA     = Color::get<0x7FDBFF>();\n\tconstexpr static Color TEAL     = Color::get<0x39CCCC>();\n\tconstexpr static Color OLIVE    = Color::get<0x3D9970>();\n\tconstexpr static Color GREEN    = Color::get<0x2ECC40>();\n\tconstexpr static Color LIME     = Color::get<0x01FF70>();\n\tconstexpr static Color YELLOW   = Color::get<0xFFDC00>();\n\tconstexpr static Color ORANGE   = Color::get<0xFF851B>();\n\tconstexpr static Color RED      = Color::get<0xFF4136>();\n\tconstexpr static Color MAROON   = Color::get<0x85144b>();\n\tconstexpr static Color FUCHSIA  = Color::get<0xF012BE>();\n\tconstexpr static Color PURPLE   = Color::get<0xB10DC9>();\n\tconstexpr static Color BLACK    = Color::get<0x111111>();\n\tconstexpr static Color GRAY     = Color::get<0xAAAAAA>();\n\tconstexpr static Color SILVER   = Color::get<0xDDDDDD>();\n\tconstexpr static Color WHITE    = Color::get<0xFFFFFF>();\n}\n\n};"
  },
  {
    "path": "graphics/gui/gui.cpp",
    "content": "#include \"core.h\"\n\n#include \"gui.h\"\n#include \"../util/resource/resourceManager.h\"\n\nnamespace P3D::Graphics {\n\nnamespace GUI {\n\n// Global\nWindowInfo windowInfo;\nFont* font = nullptr;\n\n// Batch\nGuiBatch* batch;\n\nvoid onInit(const WindowInfo& info) {\n\t// Init\n\tShaders::onInit();\n\n\tGUI::windowInfo = info;\n\tGUI::batch = new GuiBatch();\n\n\t// font\n\tGUI::font = ResourceManager::add<FontResource>(\"font\", \"../res/fonts/droid.ttf\");\n\t//font->getAtlas()->generateMipmap();\n}\n\nbool onWindowResize(const WindowInfo& info) {\n\tGUI::windowInfo = info;\n\n\treturn false;\n}\n\nvoid onUpdate(const Mat4f& orthoMatrix) {\n\tShaders::quadShader->updateProjection(orthoMatrix);\n}\n\nvoid onClose() {\n\t// Shaders\n\tShaders::onClose();\n\n\t// Fonts\n\tfont->close();\n}\n\t\n}\n\n}"
  },
  {
    "path": "graphics/gui/gui.h",
    "content": "#pragma once\n\n#include \"../batch/guiBatch.h\"\n#include \"../resource/fontResource.h\"\n\nnamespace P3D::Graphics {\n\t\nclass Font;\n\nnamespace GUI {\n\n// Window\nstruct WindowInfo {\n\tVec2i dimension;\n\tfloat aspect;\n};\n\n// Global\nextern WindowInfo windowInfo;\nextern Font* font;\n\t\n// Batch\nextern GuiBatch* batch;\n\t\nvoid onInit(const WindowInfo& info);\nbool onWindowResize(const WindowInfo& info);\nvoid onUpdate(const Mat4f& orthoMatrix);\nvoid onClose();\n\n}\n\t\n};"
  },
  {
    "path": "graphics/gui/guiUtils.cpp",
    "content": "#include \"core.h\"\n\n#include \"guiUtils.h\"\n\n#include \"gui.h\"\n\nnamespace P3D::Graphics {\n\nnamespace GUI {\n\ndouble clamp(double value, double min, double max) {\n\tif (value < min)\n\t\treturn min;\n\tif (value > max)\n\t\treturn max;\n\treturn value;\n}\nfloat clamp(float value, float min, float max) {\n\tif(value < min)\n\t\treturn min;\n\tif(value > max)\n\t\treturn max;\n\treturn value;\n}\n\ndouble smoothstep(double start, double end, double x) {\n\tdouble t = clamp((x - start) / (end - start), 0.0, 1.0);\n\treturn t * t * (3.0 - 2.0 * t);\n}\n\nfloat smoothstep(float start, float end, float x) {\n\tfloat t = clamp((x - start) / (end - start), 0.0f, 1.0f);\n\treturn t * t * (3.0f - 2.0f * t);\n}\n\ndouble map(double x, double minIn, double maxIn, double minOut, double maxOut) {\n\treturn (x - minIn) * (maxOut - minOut) / (maxIn - minIn) + minOut;\n}\n\nVec2 map(const Vec2& point) {\n\treturn Vec2(\n\t\tmap(point.x, 0, GUI::windowInfo.dimension.x, -GUI::windowInfo.aspect, GUI::windowInfo.aspect),\n\t\tmap(GUI::windowInfo.dimension.y - point.y, 0, GUI::windowInfo.dimension.y, -1, 1));\n}\n\nVec4 mapRegion(const Vec4& region, const Vec2& inXDimension, const Vec2& inYDimension, const Vec2& outXDimension, const Vec2& outYDimension) {\n\tVec2 inPoint1 = Vec2(region.x, region.y);\n\tVec2 inPoint2 = Vec2(region.z, region.w);\n\tVec2 outPoint1 = mapDimension(inPoint1, inXDimension, inYDimension, outXDimension, outYDimension);\n\tVec2 outPoint2 = mapDimension(inPoint2, inXDimension, inYDimension, outXDimension, outYDimension);\n\n\treturn Vec4(outPoint1.x, outPoint1.y, outPoint2.x, outPoint2.y);\n}\n\nVec2 mapDimension(const Vec2& point, const Vec2& inXDimension, const Vec2& inYDimension, const Vec2& outXDimension, const Vec2& outYDimension) {\n\treturn Vec2(map(point.x, inXDimension.x, inXDimension.y, outXDimension.x, outXDimension.y), map(point.y, inYDimension.x, inYDimension.y, outYDimension.x, outYDimension.y));\n}\n\nVec2 unmap(const Vec2& point) {\n\treturn Vec2(map(point.x, -GUI::windowInfo.aspect, GUI::windowInfo.aspect, 0, GUI::windowInfo.dimension.x), GUI::windowInfo.dimension.y - map(point.y, -1, 1, 0, GUI::windowInfo.dimension.y));\n}\n\nVec2 mapDimension(const Vec2& dimension) {\n\treturn Vec2(map(dimension.x, 0, GUI::windowInfo.dimension.x, 0, 2 * GUI::windowInfo.aspect), map(dimension.y, 0, GUI::windowInfo.dimension.y, 0, 2));\n}\n\nVec2 unmapDimension(const Vec2& dimension) {\n\treturn Vec2(map(dimension.x, 0, 2 * GUI::windowInfo.aspect, 0, GUI::windowInfo.dimension.x), map(dimension.y, 0, 2, 0, GUI::windowInfo.dimension.y));\n}\n\nbool between(double value, double min, double max) {\n\treturn min <= value && value <= max;\n}\n\nstd::pair<double, double> minmax(double value1, double value2) {\n\treturn (value1 < value2) ? std::pair { value1, value2 } : std::pair { value2, value1 };\n}\n\n}\n\n};"
  },
  {
    "path": "graphics/gui/guiUtils.h",
    "content": "#pragma once\n\nnamespace P3D::Graphics {\n\nnamespace GUI {\n\n// Clamps a value between a range\ndouble clamp(double value, double min, double max);\nfloat clamp(float value, float min, float max);\n\n// Performs a smooth Hermite interpolation between 0 and 1 when start < x < end\ndouble smoothstep(double start, double end, double x);\nfloat smoothstep(float start, float end, float x);\n\n// Maps a value from an input range to an output range\ndouble map(double x, double minIn, double maxIn, double minOut, double maxOut);\n\n// Maps a point from screen space to view space\nVec2 map(const Vec2& point);\n\n// Maps a point from view space to screen space\nVec2 unmap(const Vec2& point);\n\n// Maps a dimension from screen space to view space\nVec2 mapDimension(const Vec2& dimension);\n\n// Maps a region to a given range\nVec4 mapRegion(const Vec4& region, const Vec2& inXDimension, const Vec2& inYDimension, const Vec2& outXDimension, const Vec2& outYDimension);\n\n// Maps a point from the input range to the output range\nVec2 mapDimension(const Vec2& point, const Vec2& inXDimension, const Vec2& inYDimension, const Vec2& outXDimension, const Vec2& outYDimension);\n\n// Maps a dimension from view space to screen space\nVec2 unmapDimension(const Vec2& dimension);\n\n// Return whether the given value is between min and max\nbool between(double value, double min, double max);\n\n// Returns the min and max of two numbers\nstd::pair<double, double> minmax(double value1, double value2);\n\n}\n\n};"
  },
  {
    "path": "graphics/gui/imgui/imguiExtension.h",
    "content": "#pragma once\n\n#include \"../../resource/textureResource.h\"\n#include \"../util/resource/resourceManager.h\"\n#include \"imgui/imgui.h\"\n#include \"imgui/imgui_internal.h\"\n#include \"../engine/tool/tool.h\"\n\nnamespace ImGui {\n\n\tinline void DrawLineBetween(const ImRect& button1, const ImRect& button2, float yExtent = 0) {\n\t\tImVec2 pos1 = ImVec2(\n\t\t\tbutton1.Max.x + (button2.Min.x - button1.Max.x) / 2,\n\t\t\tImMin(button1.Min.y, button2.Min.y) - yExtent / 2\n\t\t);\n\t\tImVec2 pos2 = ImVec2(\n\t\t\tpos1.x,\n\t\t\tImMax(button1.Max.y, button2.Max.y) + yExtent / 2\n\t\t);\n\n\t\tGImGui->CurrentWindow->DrawList->AddLine(pos1, pos2, ImGui::GetColorU32(ImVec4(0.7f, 0.7f, 0.7f, 0.3f)));\n\t}\n\n\tinline void DrawLine(const ImVec2& pos1, const ImVec2& pos2) {\n\t\tGImGui->CurrentWindow->DrawList->AddLine(pos1, pos2, ImGui::GetColorU32(ImVec4(0.7f, 0.7f, 0.7f, 0.3f)));\n\t}\n\n\t// Draw buttons\n\tinline void DrawButton(const ImRect& button, bool even, bool selected, bool held, bool hovered, float rounding = 0.0f) {\n\t\tImU32 color = even ? ImGui::GetColorU32(ImVec4(0, 0, 0, 0)) : ImGui::GetColorU32(ImVec4(0.4f, 0.4f, 0.4f, 0.1f));\n\t\tif (held || selected)\n\t\t\tcolor = ImGui::GetColorU32(ImGuiCol_ButtonActive);\n\t\telse if (hovered)\n\t\t\tcolor = ImGui::GetColorU32(ImGuiCol_ButtonHovered);\n\n\t\tGImGui->CurrentWindow->DrawList->AddRectFilled(ImVec2(button.Min.x, button.Min.y - GImGui->Style.ItemSpacing.y / 2), ImVec2(button.Max.x, button.Max.y + GImGui->Style.ItemSpacing.y / 2), color, rounding);\n\t}\n\n\t// Draw icons\n\tinline void DrawIcon(GLID icon, const ImVec2& min, const ImVec2& max) {\n\t\tif (icon == 0)\n\t\t\treturn;\n\n\t\tGImGui->CurrentWindow->DrawList->AddImage(reinterpret_cast<ImTextureID>(icon), min, max);\n\t}\n\n\tinline ImU32 HexToImU32(const char* hex) {\n\t\tint i[4];\n\t\tsscanf(hex, \"%02X%02X%02X%02X\", (unsigned int*) &i[0], (unsigned int*) &i[1], (unsigned int*) &i[2], (unsigned int*) &i[3]);\n\n\t\tImVec4 col = {\n\t\t\ti[0] / 255.0f,\n\t\t\ti[1] / 255.0f,\n\t\t\ti[2] / 255.0f,\n\t\t\ti[3] / 255.0f,\n\t\t};\n\n\t\treturn ImGui::ColorConvertFloat4ToU32(col);\n\t}\n\n    inline bool InputDouble3(const char* label, double v[3], ImGuiInputTextFlags flags) {\n        char format[16] = \"%f\";\n        return InputScalarN(label, ImGuiDataType_Double, v, 3, NULL, NULL, format, flags);\n    }\n\n    inline bool InputFloat9(const char* label, float v[9], ImGuiInputTextFlags flags) {\n        char format[16] = \"%f\";\n        bool i1 = InputFloat3(\"\", v);\n        bool i2 = InputFloat3(\"\", v + 3);\n        bool i3 = InputFloat3(\"\", v + 6);\n\n        return i1 | i2 | i3;\n    }\n\n    inline bool DragVecN(const char* id, const char** labels, float* data, int components, float resetValue = 0.0f, float* speed = nullptr, bool resetAll = false, float** min = nullptr, float** max = nullptr, ImU32* colors = nullptr) {\n        ImGuiWindow* window = GetCurrentWindow();\n        if (window->SkipItems)\n            return false;\n\n\t\tif (data == nullptr)\n\t\t\treturn false;\n\n        bool result = false;\n    \t\n        float size = GImGui->Style.ItemInnerSpacing.x * 2.0f;\n        for (int i = 0; i < components; i++) {\n            float label_size = CalcTextSize(labels[i], nullptr, true).x;\n            float padding_size = GImGui->Style.FramePadding.x * 2.0f;\n            float spacing_size = GImGui->Style.ItemInnerSpacing.x * 2.0f;\n            size += label_size + padding_size + spacing_size;\n        }\n\n\t\tif (resetAll) {\n            float label_size = CalcTextSize(\"Reset\", nullptr, true).x;\n            float padding_size = GImGui->Style.FramePadding.x * 2.0f;\n            float spacing_size = GImGui->Style.ItemInnerSpacing.x * 2.0f;\n            size += label_size + padding_size + spacing_size;\n\t\t}\n    \t\n        BeginGroup();\n    \t\n        PushMultiItemsWidths(components, GetColumnWidth() - size);\n\n        PushID(id);\n\n    \tfor (int i = 0; i < components; i++) {\n            if (i > 0)\n                SameLine(0, GImGui->Style.ItemInnerSpacing.x);\n\n    \t\tif (colors) {\n\t\t\t\tPushStyleColor(ImGuiCol_Button, colors[3 * i + 0]);\n\t\t\t\tPushStyleColor(ImGuiCol_ButtonHovered, colors[3 * i + 1]);\n\t\t\t\tPushStyleColor(ImGuiCol_ButtonActive, colors[3 * i + 2]);\n\t\t\t}\n\n            if(Button(labels[i])) {\n                *(data + i) = resetValue;\n                result = true;\n            }\n\n\t\t\tif (colors)\n\t\t\t\tPopStyleColor(3);\n\n\t\t\tSameLine(0, GImGui->Style.ItemInnerSpacing.x);\n\n            PushID(i);\n            result |= DragScalar(\"\", ImGuiDataType_Float, data + i, speed == nullptr ? 0.1f : *(speed + i), min == nullptr ? nullptr : *(min + i), max == nullptr ? nullptr : *(max + i), \"%.2f\");\n            PopID();\n\n\t\n    \t\t\n            PopItemWidth();\n    \t}\n\n\t\tif (resetAll) {\n            SameLine(0, GImGui->Style.ItemInnerSpacing.x);\n\n            PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, -1));\n\t\t\tif (ImageButton((ImTextureID) ResourceManager::get<P3D::Graphics::TextureResource>(\"reset\")->getID(), ImVec2(20, 20), ImVec2(0, 1), ImVec2(1, 0))) {\n\t\t\t\tfor (int i = 0; i < components; i++)\n                    *(data + i) = resetValue;\n                result = true;\n\t\t\t}\n\t\t\t\n            PopStyleVar(1);\n\t\t}\n\n        PopID();\n\n        EndGroup();\n    \t\n        return result;\n    }\n\n    inline bool DragVec3(const char* id, float values[3], float resetValue = 0.0f, float* speed = nullptr, bool resetAll = false, float** min = nullptr, float** max = nullptr) {\n        const char* labels[] = { \"X\", \"Y\", \"Z\" };\n\t\tImU32 colors[] = {\n\t\t\t4280887473, // Red Idle\n\t\t\t4280097889, // Red Hover\n\t\t\t4280821893, // Red Active\n\n\t\t\t4281503782, // Green Idle\n\t\t\t4280574236, // Green Hover\n\t\t\t4281566504, // Green Active\n\t\t\t\n\t\t\t4289808168, // Blue Idle\n\t\t\t4284558364, // Blue Hover\n\t\t\t4286922280, // Blue Active\n\t\t};\n\n        return DragVecN(id, labels, values, 3, resetValue, speed, resetAll, min, max, colors);\n    }\n\n    inline void HelpMarker(const char* description) {\n        TextDisabled(\"(?)\");\n        if (IsItemHovered()) {\n            BeginTooltip();\n            PushTextWrapPos(GetFontSize() * 35.0f);\n            TextUnformatted(description);\n            PopTextWrapPos();\n            EndTooltip();\n        }\n    }\n\n    inline void BeginToolbar(const char* name) {\n        Begin(name, 0, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize);\n\t}\n\n    inline bool ToolBarButton(const char* name, const char* description, const char* resource, bool selected = false) {\n        P3D::Graphics::TextureResource* image = ResourceManager::get<P3D::Graphics::TextureResource>(resource);\n        if (image == nullptr)\n            return false;\n\n        PushStyleVar(ImGuiStyleVar_FrameRounding, 0);\n        PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, -1));\n\n\t\tSameLine();\n        ImVec4 bg = selected ? ImVec4(0.2, 0.2, 0.2, 0.5) : ImVec4(0, 0, 0, 0);\n        ImGui::PushID(name);\n        bool result = ImageButton((ImTextureID) image->getID(), ImVec2(25, 25), ImVec2(0, 0), ImVec2(1, 1), 2, bg);\n        ImGui::PopID();\n\t\t\n\t\tPopStyleVar(2);\n\t\t\n        if (IsItemHovered()) {\n            BeginTooltip();\n            Text(name);\n            TextDisabled(description);\n            EndTooltip();\n        }\n\n        return result;\n    }\n\n    inline bool ToolBarButton(P3D::Engine::Tool* tool, bool selected = false) {\n        return ToolBarButton(tool->getName().c_str(), tool->getDescription().c_str(), tool->getName().c_str(), selected);\n    }\n\n    inline void ToolBarSpacing() {\n        SameLine(0, 30);\n        Spacing();\n\t}\n\t\n    inline void EndToolBar() {\n        End();\n\t}\n\t\n}\n\n#define PROPERTY_FRAME_START(label) \\\n\tif (ImGui::CollapsingHeader((label), ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_AllowItemOverlap)) { \\\n\t\tImGui::Columns(2)\n\n#define PROPERTY_FRAME_END\\\n\t\tImGui::Columns(1); \\\n\t}\n\n#define PROPERTY_DESC_IF(text, desc, widget, code) \\\n\t{ \\\n\t\tImGui::TextUnformatted(text); \\\n\t\tImGui::SameLine(); \\\n\t\tImGui::HelpMarker(desc); \\\n\t\tImGui::NextColumn(); \\\n\t\tImGui::SetNextItemWidth(-1); \\\n\t\tif (widget) { \\\n\t\t\tcode \\\n\t\t}; \\\n\t\tImGui::NextColumn(); \\\n\t}\n\n#define PROPERTY_IF(text, widget, code) \\\n\t{ \\\n\t\tImGui::TextUnformatted(text); \\\n\t\tImGui::NextColumn(); \\\n\t\tImGui::SetNextItemWidth(-1); \\\n\t\tif (widget) { \\\n\t\t\tcode \\\n\t\t}; \\\n\t\tImGui::NextColumn(); \\\n\t}\n\n#define PROPERTY_DESC_IF_LOCK(text, desc, widget, code) \\\n\t{ \\\n\t\tImGui::TextUnformatted(text); \\\n\t\tImGui::SameLine(); \\\n\t\tImGui::HelpMarker(desc); \\\n\t\tImGui::NextColumn(); \\\n\t\tImGui::SetNextItemWidth(-1); \\\n\t\tif (widget) { \\\n\t\t\tscreen.worldMutex->lock() \\\n\t\t\tcode \\\n\t\t\tscreen.worldMutex->unlock() \\\n\t\t}; \\\n\t\tImGui::NextColumn(); \\\n\t}\n\n#define PROPERTY_IF_LOCK(text, widget, code) \\\n\t{ \\\n\t\tImGui::TextUnformatted(text); \\\n\t\tImGui::NextColumn(); \\\n\t\tImGui::SetNextItemWidth(-1); \\\n\t\tif (widget) { \\\n\t\t\tscreen.worldMutex->lock(); \\\n\t\t\tcode \\\n\t\t\tscreen.worldMutex->unlock(); \\\n\t\t}; \\\n\t\tImGui::NextColumn(); \\\n\t}\n\n#define PROPERTY_DESC(text, desc, widget) \\\n\t{ \\\n\t\tImGui::TextUnformatted(text); \\\n\t\tImGui::SameLine(); \\\n\t\tImGui::HelpMarker(desc); \\\n\t\tImGui::NextColumn(); \\\n\t\tImGui::SetNextItemWidth(-1); \\\n\t\twidget; \\\n\t\tImGui::NextColumn(); \\\n\t} \n\n#define PROPERTY(text, widget) \\\n\t{ \\\n\t\tImGui::TextUnformatted(text); \\\n\t\tImGui::NextColumn(); \\\n\t\tImGui::SetNextItemWidth(-1); \\\n\t\twidget; \\\n\t\tImGui::NextColumn(); \\\n\t} \n\n#define TITLE_DESC(text, desc, newline) \\\n\t{ \\\n\t\tif (newline) { \\\n\t\t\tECS_PROPERTY(\"\", ); \\\n\t\t} \\\n\t\tImGui::TextColored(GImGui->Style.Colors[ImGuiCol_ButtonActive], text); \\\n\t\tImGui::SameLine(); \\\n\t\tImGui::HelpMarker(desc); \\\n\t\tImGui::NextColumn(); \\\n\t\tImGui::SetNextItemWidth(-1); \\\n\t\tImGui::NextColumn(); \\\n\t}\n\n#define TITLE(text, newline) \\\n\t{ \\\n\t\tif (newline) { \\\n\t\t\tPROPERTY(\"\", ); \\\n\t\t} \\\n\t\tImGui::TextColored(GImGui->Style.Colors[ImGuiCol_ButtonActive], text); \\\n\t\tImGui::NextColumn(); \\\n\t\tImGui::SetNextItemWidth(-1); \\\n\t\tImGui::NextColumn(); \\\n\t}"
  },
  {
    "path": "graphics/gui/imgui/imguiStyle.cpp",
    "content": "#include \"core.h\"\n#include \"imguiStyle.h\"\n\nnamespace P3D::Graphics {\n\nImGuiColors theme = Dark;\nImVec4 text = ImVec4(0.80f, 0.80f, 0.83f, 1.00f);\nImVec4 idle = ImVec4(0.28f, 0.56f, 1.00f, 1.00f);\nImVec4 hover = ImVec4(0.10f, 0.40f, 0.75f, 0.75f);\nImVec4 active = ImVec4(0.10f, 0.40f, 0.75f, 1.00f);\nImVec4 dark = ImVec4(0.176f, 0.228f, 0.435f, 1.00f);\n\nvoid renderImGuiStyleEditor() {\n    ImGui::Begin(\"Style\");\n    ImGuiStyle* style = &ImGui::GetStyle();\n\n    const char* themes[] = { \"Classic\", \"Classic Light\", \"Classic Dark\", \"Light\", \"Gray\", \"Dark\" };\n    const char* current = themes[theme];\n    ImGui::Text(\"Theme\");\n    if (ImGui::BeginCombo(\"Theme\", current)) {\n        for (int i = 0; i < IM_ARRAYSIZE(themes); i++) {\n            bool is_selected = i == theme;\n            if (ImGui::Selectable(themes[i], is_selected)) {\n                theme = static_cast<ImGuiColors>(i);\n                setupImGuiColors(style, theme);\n\n            \tif (i >= 3) \n                    setupImGuiAccent(style);\n            }\n\n            if (is_selected)\n                ImGui::SetItemDefaultFocus();\n        }\n        ImGui::EndCombo();\n    }\n\n    bool edited = false;\n    if (theme >= 3) {\n        ImGui::Text(\"Accent\");\n        edited |= ImGui::ColorEdit4(\"Text\", (float*) &text, ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_AlphaBar);\n        edited |= ImGui::ColorEdit4(\"Idle\", (float*) &idle, ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_AlphaBar);\n        edited |= ImGui::ColorEdit4(\"Hover\", (float*) &hover, ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_AlphaBar);\n        edited |= ImGui::ColorEdit4(\"Active\", (float*) &active, ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_AlphaBar);\n        edited |= ImGui::ColorEdit4(\"Dark\", (float*) &dark, ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_AlphaBar);\n\n        if (edited)\n            setupImGuiAccent(style);\n    }\n\t\n    ImGui::End();\n}\n\t\nvoid setupImGuiLayoutStyle(ImGuiStyle* style) {\n    ImGuiIO& io = ImGui::GetIO();\n\n    io.Fonts->AddFontFromFileTTF(\"../res/fonts/droid.ttf\", 20);\n\n    style->WindowPadding = ImVec2(8, 10);\n    style->FramePadding = ImVec2(10, 5);\n    style->ItemSpacing = ImVec2(15, 8);\n    style->ItemInnerSpacing = ImVec2(6, 6);\n    style->IndentSpacing = 20.0f;\n    style->ScrollbarSize = 20.0f;\n    style->GrabMinSize = 20.0f;\n\n    style->WindowBorderSize = 0.0f;\n    style->ChildBorderSize = 1.0f;\n    style->FrameBorderSize = 0.0f;\n    style->PopupBorderSize = 0.0f;\n    style->TabBorderSize = 0.0f;\n\n    style->WindowRounding = 6.0f;\n    style->ChildRounding = 10.0f;\n    style->FrameRounding = 6.0f;\n    style->PopupRounding = 6.0f;\n    style->ScrollbarRounding = 3.0f;\n    style->GrabRounding = 5.0f;\n\n    style->WindowTitleAlign = ImVec2(0.5f, 0.5f);\n    style->WindowMenuButtonPosition = ImGuiDir_Right;\n}\n\nvoid setupImGuiAccent(ImGuiStyle* style) {\n\tstyle->Colors[ImGuiCol_Text] = text;\n\tstyle->Colors[ImGuiCol_FrameBgHovered] = idle;\n    style->Colors[ImGuiCol_CheckMark] = active;\n    style->Colors[ImGuiCol_SliderGrab] = active;\n    style->Colors[ImGuiCol_SliderGrabActive] = active;\n    style->Colors[ImGuiCol_Button] = idle;\n    style->Colors[ImGuiCol_ButtonHovered] = hover;\n    style->Colors[ImGuiCol_ButtonActive] = active;\n    style->Colors[ImGuiCol_HeaderHovered] = hover;\n    style->Colors[ImGuiCol_HeaderActive] = active;\n    style->Colors[ImGuiCol_SeparatorHovered] = hover;\n    style->Colors[ImGuiCol_SeparatorActive] = active;\n    style->Colors[ImGuiCol_ResizeGrip] = idle;\n    style->Colors[ImGuiCol_ResizeGripHovered] = hover;\n    style->Colors[ImGuiCol_ResizeGripActive] = active;\n    style->Colors[ImGuiCol_TabHovered] = hover;\n    style->Colors[ImGuiCol_TabActive] = active;\n    style->Colors[ImGuiCol_DockingPreview] = hover;\n    style->Colors[ImGuiCol_TextSelectedBg] = hover;\n    style->Colors[ImGuiCol_NavHighlight] = active;\n    style->Colors[ImGuiCol_Tab] = idle;\n    style->Colors[ImGuiCol_TabUnfocusedActive] = dark;\n    style->Colors[ImGuiCol_TabUnfocused] = active;\n}\n\nvoid setupImGuiColors(ImGuiStyle* style, ImGuiColors colors) {\n    switch (colors) {\n        case Light:\n\n            break;\n        case Gray:\n            style->Colors[ImGuiCol_TextDisabled] = ImVec4(0.36f, 0.42f, 0.47f, 1.00f);\n            style->Colors[ImGuiCol_WindowBg] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f);\n            style->Colors[ImGuiCol_ChildBg] = ImVec4(0.15f, 0.18f, 0.22f, 1.00f);\n            style->Colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f);\n            style->Colors[ImGuiCol_Border] = ImVec4(0.08f, 0.10f, 0.12f, 1.00f);\n            style->Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);\n            style->Colors[ImGuiCol_FrameBg] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f);\n            style->Colors[ImGuiCol_FrameBgActive] = ImVec4(0.09f, 0.12f, 0.14f, 1.00f);\n            style->Colors[ImGuiCol_TitleBg] = ImVec4(0.09f, 0.12f, 0.14f, 0.65f);\n            style->Colors[ImGuiCol_TitleBgActive] = ImVec4(0.08f, 0.10f, 0.12f, 1.00f);\n            style->Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f);\n            style->Colors[ImGuiCol_MenuBarBg] = ImVec4(0.15f, 0.18f, 0.22f, 1.00f);\n            style->Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.39f);\n            style->Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f);\n            style->Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.18f, 0.22f, 0.25f, 1.00f);\n            style->Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.09f, 0.21f, 0.31f, 1.00f);\n            style->Colors[ImGuiCol_Header] = ImVec4(0.20f, 0.25f, 0.29f, 0.55f);\n            style->Colors[ImGuiCol_Separator] = ImVec4(0.20f, 0.25f, 0.29f, 1.00f);\n            style->Colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);\n            style->Colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);\n            style->Colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);\n            style->Colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);\n            style->Colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);\n            style->Colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);\n            style->Colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);\n            style->Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);\n            break;\n        case Dark:\n            style->Colors[ImGuiCol_TextDisabled] = ImVec4(0.24f, 0.23f, 0.29f, 1.00f);\n            style->Colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.05f, 0.07f, 1.00f);\n            style->Colors[ImGuiCol_ChildBg] = ImVec4(0.07f, 0.07f, 0.09f, 1.00f);\n            style->Colors[ImGuiCol_PopupBg] = ImVec4(0.07f, 0.07f, 0.09f, 1.00f);\n            style->Colors[ImGuiCol_Border] = ImVec4(0.80f, 0.80f, 0.83f, 0.88f);\n            style->Colors[ImGuiCol_BorderShadow] = ImVec4(0.92f, 0.91f, 0.88f, 0.00f);\n            style->Colors[ImGuiCol_FrameBg] = ImVec4(0.10f, 0.09f, 0.12f, 1.00f);\n            style->Colors[ImGuiCol_FrameBgActive] = ImVec4(0.56f, 0.56f, 0.58f, 1.00f);\n            style->Colors[ImGuiCol_TitleBg] = ImVec4(0.10f, 0.09f, 0.12f, 1.00f);\n            style->Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(1.00f, 0.98f, 0.95f, 0.75f);\n            style->Colors[ImGuiCol_TitleBgActive] = ImVec4(0.07f, 0.07f, 0.09f, 1.00f);\n            style->Colors[ImGuiCol_MenuBarBg] = ImVec4(0.10f, 0.09f, 0.12f, 1.00f);\n            style->Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.10f, 0.09f, 0.12f, 1.00f);\n            style->Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.80f, 0.80f, 0.83f, 0.31f);\n            style->Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.56f, 0.56f, 0.58f, 1.00f);\n            style->Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.06f, 0.05f, 0.07f, 1.00f);\n            style->Colors[ImGuiCol_Header] = ImVec4(0.10f, 0.09f, 0.12f, 1.00f);\n            style->Colors[ImGuiCol_PlotLines] = ImVec4(0.40f, 0.39f, 0.38f, 0.63f);\n            style->Colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.25f, 1.00f, 0.00f, 1.00f);\n            style->Colors[ImGuiCol_PlotHistogram] = ImVec4(0.40f, 0.39f, 0.38f, 0.63f);\n            style->Colors[ImGuiCol_PlotHistogramHovered] = ImVec4(0.25f, 1.00f, 0.00f, 1.00f);\n            style->Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.2f, 0.2f, 0.2f, 0.75f);\n            break;\n        case ClassicLight:\n            ImGui::StyleColorsLight(style);\n            break;\n        case ClassicDark:\n            ImGui::StyleColorsDark(style);\n            break;\n        case Classic:\n            ImGui::StyleColorsClassic(style);\n    }\n}\n\nvoid setupImGuiStyle() {\n    ImGuiStyle* style = &ImGui::GetStyle();\n    setupImGuiLayoutStyle(style);\n    setupImGuiAccent(style);\n    setupImGuiColors(style, ImGuiColors::Dark);\n}\n\n}\n"
  },
  {
    "path": "graphics/gui/imgui/imguiStyle.h",
    "content": "#pragma once\n#include \"imgui/imgui.h\"\n\nnamespace P3D::Graphics {\n\nenum ImGuiColors {\n\tClassic,\n\tClassicLight,\n\tClassicDark,\n    Light,\n    Gray,\n    Dark\n};\n\nextern ImGuiColors theme;\nextern ImVec4 text;\nextern ImVec4 idle;\nextern ImVec4 hover;\nextern ImVec4 active;\nextern ImVec4 dark;\n\nvoid setupImGuiLayoutStyle(ImGuiStyle* style);\nvoid setupImGuiAccent(ImGuiStyle* style);\nvoid setupImGuiColors(ImGuiStyle* style, ImGuiColors colors);\nvoid setupImGuiStyle();\nvoid renderImGuiStyleEditor();\n\t\n}"
  },
  {
    "path": "graphics/gui/imgui/legacy_imgui_impl_glfw.cpp",
    "content": "#include \"imgui/imgui.h\"\n#include \"imgui_impl_glfw.h\"\n\n// GLFW\n#include <GLFW/glfw3.h>\n#ifdef _WIN32\n#undef APIENTRY\n#define GLFW_EXPOSE_NATIVE_WIN32\n#include <GLFW/glfw3native.h>   // for glfwGetWin32Window\n#endif\n#define GLFW_HAS_WINDOW_TOPMOST       (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ GLFW_FLOATING\n#define GLFW_HAS_WINDOW_HOVERED       (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_HOVERED\n#define GLFW_HAS_WINDOW_ALPHA         (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwSetWindowOpacity\n#define GLFW_HAS_PER_MONITOR_DPI      (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorContentScale\n#define GLFW_HAS_VULKAN               (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwCreateWindowSurface\n\n// Data\nenum GlfwClientApi {\n    GlfwClientApi_Unknown,\n    GlfwClientApi_OpenGL\n};\n\nstatic GLFWwindow*          g_Window = NULL;\nstatic GlfwClientApi        g_ClientApi = GlfwClientApi_Unknown;\nstatic double               g_Time = 0.0;\nstatic bool                 g_MouseJustPressed[5] = { false, false, false, false, false };\nstatic GLFWcursor*          g_MouseCursors[ImGuiMouseCursor_COUNT] = {};\nstatic bool                 g_InstalledCallbacks = false;\nstatic GLFWmousebuttonfun   g_PrevUserCallbackMousebutton = NULL;\nstatic GLFWscrollfun        g_PrevUserCallbackScroll = NULL;\nstatic GLFWkeyfun           g_PrevUserCallbackKey = NULL;\nstatic GLFWcharfun          g_PrevUserCallbackChar = NULL;\n\nstatic const char* ImGuiGetClipboardText(void* user_data) {\n    return glfwGetClipboardString((GLFWwindow*) user_data);\n}\n\nstatic void ImGuiSetClipboardText(void* user_data, const char* text) {\n    glfwSetClipboardString((GLFWwindow*) user_data, text);\n}\n\nvoid ImGuiMouseButtonCallback(GLFWwindow* window, int button, int action, int mods) {\n    if (g_PrevUserCallbackMousebutton != NULL)\n        g_PrevUserCallbackMousebutton(window, button, action, mods);\n\n    if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(g_MouseJustPressed))\n        g_MouseJustPressed[button] = true;\n}\n\nvoid ImGuiScrollCallback(GLFWwindow* window, double xoffset, double yoffset) {\n    if (g_PrevUserCallbackScroll != NULL)\n        g_PrevUserCallbackScroll(window, xoffset, yoffset);\n\n    ImGuiIO& io = ImGui::GetIO();\n    io.MouseWheelH += (float)xoffset;\n    io.MouseWheel += (float)yoffset;\n}\n\nvoid ImGuiKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {\n    if (g_PrevUserCallbackKey != NULL)\n        g_PrevUserCallbackKey(window, key, scancode, action, mods);\n\n    ImGuiIO& io = ImGui::GetIO();\n    if (action == GLFW_PRESS)\n        io.KeysDown[key] = true;\n    if (action == GLFW_RELEASE)\n        io.KeysDown[key] = false;\n\n    // Modifiers are not reliable across systems\n    io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL];\n    io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT];\n    io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT];\n    io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];\n}\n\nvoid ImGuiCharCallback(GLFWwindow* window, unsigned int c) {\n    if (g_PrevUserCallbackChar != NULL)\n        g_PrevUserCallbackChar(window, c);\n\n    ImGuiIO& io = ImGui::GetIO();\n    io.AddInputCharacter(c);\n}\n\nbool ImGuiInitGLFW(GLFWwindow* window, bool install_callbacks) {\n    g_Window = window;\n    g_Time = 0.0;\n\n    // Setup back-end capabilities flags\n    ImGuiIO& io = ImGui::GetIO();\n    io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors;         // We can honor GetMouseCursor() values (optional)\n    io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;          // We can honor io.WantSetMousePos requests (optional, rarely used)\n    io.BackendPlatformName = \"imgui_impl_glfw\";\n\n    // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array.\n    io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;\n    io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;\n    io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;\n    io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;\n    io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;\n    io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP;\n    io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN;\n    io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;\n    io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;\n    io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT;\n    io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;\n    io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;\n    io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE;\n    io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;\n    io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;\n    io.KeyMap[ImGuiKey_KeyPadEnter] = GLFW_KEY_KP_ENTER;\n    io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;\n    io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;\n    io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;\n    io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;\n    io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;\n    io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;\n\n    io.SetClipboardTextFn = ImGuiSetClipboardText;\n    io.GetClipboardTextFn = ImGuiGetClipboardText;\n    io.ClipboardUserData = g_Window;\n#if defined(_WIN32)\n    io.ImeWindowHandle = (void*)glfwGetWin32Window(g_Window);\n#endif\n\n    g_MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);\n    g_MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);\n    g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);   // FIXME: GLFW doesn't have this.\n    g_MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR);\n    g_MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR);\n    g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);  // FIXME: GLFW doesn't have this.\n    g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);  // FIXME: GLFW doesn't have this.\n    g_MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);\n\n    // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.\n    g_PrevUserCallbackMousebutton = NULL;\n    g_PrevUserCallbackScroll = NULL;\n    g_PrevUserCallbackKey = NULL;\n    g_PrevUserCallbackChar = NULL;\n\n    if (install_callbacks) {\n        g_InstalledCallbacks = true;\n        g_PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGuiMouseButtonCallback);\n        g_PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGuiScrollCallback);\n        g_PrevUserCallbackKey = glfwSetKeyCallback(window, ImGuiKeyCallback);\n        g_PrevUserCallbackChar = glfwSetCharCallback(window, ImGuiCharCallback);\n    }\n\n    g_ClientApi = GlfwClientApi_OpenGL;\n    return true;\n}\n\nvoid ImGuiShutdownGLFW() {\n    if (g_InstalledCallbacks) {\n        glfwSetMouseButtonCallback(g_Window, g_PrevUserCallbackMousebutton);\n        glfwSetScrollCallback(g_Window, g_PrevUserCallbackScroll);\n        glfwSetKeyCallback(g_Window, g_PrevUserCallbackKey);\n        glfwSetCharCallback(g_Window, g_PrevUserCallbackChar);\n        g_InstalledCallbacks = false;\n    }\n\n    for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++) {\n        glfwDestroyCursor(g_MouseCursors[cursor_n]);\n        g_MouseCursors[cursor_n] = NULL;\n    }\n\n    g_ClientApi = GlfwClientApi_Unknown;\n}\n\nstatic void ImGuiUpdateMousePosAndButtons() {\n    // Update buttons\n    ImGuiIO& io = ImGui::GetIO();\n    for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) {\n        // If a mouse press event came, always pass it as \"mouse held this frame\", so we don't miss click-release events that are shorter than 1 frame.\n        io.MouseDown[i] = g_MouseJustPressed[i] || glfwGetMouseButton(g_Window, i) != 0;\n        g_MouseJustPressed[i] = false;\n    }\n\n    // Update mouse position\n    const ImVec2 mouse_pos_backup = io.MousePos;\n    io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);\n\n    const bool focused = glfwGetWindowAttrib(g_Window, GLFW_FOCUSED) != 0;\n\n\tif (focused) {\n        if (io.WantSetMousePos) {\n            glfwSetCursorPos(g_Window, (double)mouse_pos_backup.x, (double)mouse_pos_backup.y);\n        } else {\n            double mouse_x, mouse_y;\n            glfwGetCursorPos(g_Window, &mouse_x, &mouse_y);\n            io.MousePos = ImVec2((float)mouse_x, (float)mouse_y);\n        }\n    }\n}\n\nstatic void ImGuiUpdateMouseCursor() {\n    ImGuiIO& io = ImGui::GetIO();\n    if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(g_Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)\n        return;\n\n    ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();\n    if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor) {\n        // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor\n        glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);\n    } else {\n        // Show OS mouse cursor\n        // FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.\n        glfwSetCursor(g_Window, g_MouseCursors[imgui_cursor] ? g_MouseCursors[imgui_cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]);\n        glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);\n    }\n}\n\nvoid ImGuiNewFrameGLFW() {\n    ImGuiIO& io = ImGui::GetIO();\n\t\n    IM_ASSERT(io.Fonts->IsBuilt() && \"Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().\");\n\n    // Setup display size (every frame to accommodate for window resizing)\n    int w, h;\n    int display_w, display_h;\n    glfwGetWindowSize(g_Window, &w, &h);\n    glfwGetFramebufferSize(g_Window, &display_w, &display_h);\n    io.DisplaySize = ImVec2((float)w, (float)h);\n    if (w > 0 && h > 0)\n        io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);\n\n    // Setup time step\n    double current_time = glfwGetTime();\n    io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f/60.0f);\n    g_Time = current_time;\n\n    ImGuiUpdateMousePosAndButtons();\n    ImGuiUpdateMouseCursor();\n}\n"
  },
  {
    "path": "graphics/gui/imgui/legacy_imgui_impl_glfw.h",
    "content": "#pragma once\n\nstruct GLFWwindow;\n\nbool ImGuiInitGLFW(GLFWwindow* window, bool install_callbacks);\nvoid ImGuiShutdownGLFW();\nvoid ImGuiNewFrameGLFW();\nvoid ImGuiMouseButtonCallback(GLFWwindow* window, int button, int action, int mods);\nvoid ImGuiScrollCallback(GLFWwindow* window, double xoffset, double yoffset);\nvoid ImGuiKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);\nvoid ImGuiCharCallback(GLFWwindow* window, unsigned int c);\n"
  },
  {
    "path": "graphics/gui/imgui/legacy_imgui_impl_opengl3.cpp",
    "content": "// dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline\n// - Desktop GL: 2.x 3.x 4.x\n// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)\n// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)\n\n// Implemented features:\n//  [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!\n//  [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.\n\n// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.\n// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.\n// https://github.com/ocornut/imgui\n\n// CHANGELOG\n// (minor and older changes stripped away, please see git history for details)\n//  2019-10-25: OpenGL: Using a combination of GL define and runtime GL version to decide whether to use glDrawElementsBaseVertex(). Fix building with pre-3.2 GL loaders.\n//  2019-09-22: OpenGL: Detect default GL loader using __has_include compiler facility.\n//  2019-09-16: OpenGL: Tweak initialization code to allow application calling ImGui_ImplOpenGL3_CreateFontsTexture() before the first NewFrame() call.\n//  2019-05-29: OpenGL: Desktop GL only: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.\n//  2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.\n//  2019-03-29: OpenGL: Not calling glBindBuffer more than necessary in the render loop.\n//  2019-03-15: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early.\n//  2019-03-03: OpenGL: Fix support for ES 2.0 (WebGL 1.0).\n//  2019-02-20: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN even if defined by the headers/loader.\n//  2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.\n//  2019-02-01: OpenGL: Using GLSL 410 shaders for any version over 410 (e.g. 430, 450).\n//  2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.\n//  2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT) / GL_CLIP_ORIGIN.\n//  2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used.\n//  2018-08-09: OpenGL: Default to OpenGL ES 3 on iOS and Android. GLSL version default to \"#version 300 ES\".\n//  2018-07-30: OpenGL: Support for GLSL 300 ES and 410 core. Fixes for Emscripten compilation.\n//  2018-07-10: OpenGL: Support for more GLSL versions (based on the GLSL version string). Added error output when shaders fail to compile/link.\n//  2018-06-08: Misc: Extracted imgui_impl_opengl3.cpp/.h away from the old combined GLFW/SDL+OpenGL3 examples.\n//  2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.\n//  2018-05-25: OpenGL: Removed unnecessary backup/restore of GL_ELEMENT_ARRAY_BUFFER_BINDING since this is part of the VAO state.\n//  2018-05-14: OpenGL: Making the call to glBindSampler() optional so 3.2 context won't fail if the function is a NULL pointer.\n//  2018-03-06: OpenGL: Added const char* glsl_version parameter to ImGui_ImplOpenGL3_Init() so user can override the GLSL version e.g. \"#version 150\".\n//  2018-02-23: OpenGL: Create the VAO in the render function so the setup can more easily be used with multiple shared GL context.\n//  2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplSdlGL3_RenderDrawData() in the .h file so you can call it yourself.\n//  2018-01-07: OpenGL: Changed GLSL shader version from 330 to 150.\n//  2017-09-01: OpenGL: Save and restore current bound sampler. Save and restore current polygon mode.\n//  2017-05-01: OpenGL: Fixed save and restore of current blend func state.\n//  2017-05-01: OpenGL: Fixed save and restore of current GL_ACTIVE_TEXTURE.\n//  2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle.\n//  2016-07-29: OpenGL: Explicitly setting GL_UNPACK_ROW_LENGTH to reduce issues because SDL changes it. (#752)\n\n//----------------------------------------\n// OpenGL    GLSL      GLSL\n// version   version   string\n//----------------------------------------\n//  2.0       110       \"#version 110\"\n//  2.1       120       \"#version 120\"\n//  3.0       130       \"#version 130\"\n//  3.1       140       \"#version 140\"\n//  3.2       150       \"#version 150\"\n//  3.3       330       \"#version 330 core\"\n//  4.0       400       \"#version 400 core\"\n//  4.1       410       \"#version 410 core\"\n//  4.2       420       \"#version 410 core\"\n//  4.3       430       \"#version 430 core\"\n//  ES 2.0    100       \"#version 100\"      = WebGL 1.0\n//  ES 3.0    300       \"#version 300 es\"   = WebGL 2.0\n//----------------------------------------\n\n#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)\n#define _CRT_SECURE_NO_WARNINGS\n#endif\n\n#include \"imgui/imgui.h\"\n#include \"imgui_impl_opengl3.h\"\n#include <stdio.h>\n#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier\n#include <stddef.h>     // intptr_t\n#else\n#include <stdint.h>     // intptr_t\n#endif\n#if defined(__APPLE__)\n#include \"TargetConditionals.h\"\n#endif\n\n// Auto-enable GLES on matching platforms\n#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3)\n#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__))\n#define IMGUI_IMPL_OPENGL_ES3           // iOS, Android  -> GL ES 3, \"#version 300 es\"\n#undef IMGUI_IMPL_OPENGL_LOADER_GL3W\n#undef IMGUI_IMPL_OPENGL_LOADER_GLEW\n#undef IMGUI_IMPL_OPENGL_LOADER_GLAD\n#undef IMGUI_IMPL_OPENGL_LOADER_CUSTOM\n#elif defined(__EMSCRIPTEN__)\n#define IMGUI_IMPL_OPENGL_ES2           // Emscripten    -> GL ES 2, \"#version 100\"\n#undef IMGUI_IMPL_OPENGL_LOADER_GL3W\n#undef IMGUI_IMPL_OPENGL_LOADER_GLEW\n#undef IMGUI_IMPL_OPENGL_LOADER_GLAD\n#undef IMGUI_IMPL_OPENGL_LOADER_CUSTOM\n#endif\n#endif\n\n// GL includes\n#if defined(IMGUI_IMPL_OPENGL_ES2)\n#include <GLES2/gl2.h>\n#elif defined(IMGUI_IMPL_OPENGL_ES3)\n#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))\n#include <OpenGLES/ES3/gl.h>    // Use GL ES 3\n#else\n#include <GLES3/gl3.h>          // Use GL ES 3\n#endif\n#else\n// About Desktop OpenGL function loaders:\n//  Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.\n//  Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad).\n//  You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.\n#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)\n#include <GL/gl3w.h>    // Needs to be initialized with gl3wInit() in user's code\n#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)\n#include <GL/glew.h>    // Needs to be initialized with glewInit() in user's code\n#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)\n#include <glad/glad.h>  // Needs to be initialized with gladLoadGL() in user's code\n#else\n#include IMGUI_IMPL_OPENGL_LOADER_CUSTOM\n#endif\n#endif\n\n// Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have.\n#if defined(IMGUI_IMPL_OPENGL_ES2) || defined(IMGUI_IMPL_OPENGL_ES3) || !defined(GL_VERSION_3_2)\n#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET   0\n#else\n#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET   1\n#endif\n\n// OpenGL Data\nstatic GLuint       g_GlVersion = 0;                // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries.\nstatic char         g_GlslVersionString[32] = \"\";   // Specified by user or detected based on compile time GL settings.\nstatic GLuint       g_FontTexture = 0;\nstatic GLuint       g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0;\nstatic int          g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0;                                // Uniforms location\nstatic int          g_AttribLocationVtxPos = 0, g_AttribLocationVtxUV = 0, g_AttribLocationVtxColor = 0; // Vertex attributes location\nstatic unsigned int g_VboHandle = 0, g_ElementsHandle = 0;\n\n// Functions\nbool    ImGuiInitOpenGl(const char* glsl_version)\n{\n    // Query for GL version\n#if !defined(IMGUI_IMPL_OPENGL_ES2)\n    GLint major, minor;\n    glGetIntegerv(GL_MAJOR_VERSION, &major);\n    glGetIntegerv(GL_MINOR_VERSION, &minor);\n    g_GlVersion = major * 1000 + minor;\n#else\n    g_GlVersion = 2000; // GLES 2\n#endif\n\n    // Setup back-end capabilities flags\n    ImGuiIO& io = ImGui::GetIO();\n    io.BackendRendererName = \"imgui_impl_opengl3\";\n#if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET\n    if (g_GlVersion >= 3200)\n        io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;  // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.\n#endif\n\n    // Store GLSL version string so we can refer to it later in case we recreate shaders. \n    // Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure.\n#if defined(IMGUI_IMPL_OPENGL_ES2)\n    if (glsl_version == NULL)\n        glsl_version = \"#version 100\";\n#elif defined(IMGUI_IMPL_OPENGL_ES3)\n    if (glsl_version == NULL)\n        glsl_version = \"#version 300 es\";\n#else\n    if (glsl_version == NULL)\n        glsl_version = \"#version 130\";\n#endif\n    IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString));\n    strcpy(g_GlslVersionString, glsl_version);\n    strcat(g_GlslVersionString, \"\\n\");\n\n    // Dummy construct to make it easily visible in the IDE and debugger which GL loader has been selected.\n    // The code actually never uses the 'gl_loader' variable! It is only here so you can read it!\n    // If auto-detection fails or doesn't select the same GL loader file as used by your application,\n    // you are likely to get a crash below.\n    // You can explicitly select a loader by using '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.\n    const char* gl_loader = \"Unknown\";\n    IM_UNUSED(gl_loader);\n#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)\n    gl_loader = \"GL3W\";\n#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)\n    gl_loader = \"GLEW\";\n#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)\n    gl_loader = \"GLAD\";\n#else // IMGUI_IMPL_OPENGL_LOADER_CUSTOM\n    gl_loader = \"Custom\";\n#endif\n\n    // Make a dummy GL call (we don't actually need the result)\n    // IF YOU GET A CRASH HERE: it probably means that you haven't initialized the OpenGL function loader used by this code.\n    // Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above.\n    GLint current_texture;\n    glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture);\n\n    return true;\n}\n\nvoid    ImGuiShutdownOpenGL()\n{\n    ImGui_ImplOpenGL3_DestroyDeviceObjects();\n}\n\nvoid    ImGuiNewFrameOpenGL()\n{\n    if (!g_ShaderHandle)\n        ImGui_ImplOpenGL3_CreateDeviceObjects();\n}\n\nstatic void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)\n{\n    // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill\n    glEnable(GL_BLEND);\n    glBlendEquation(GL_FUNC_ADD);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n    glDisable(GL_CULL_FACE);\n    glDisable(GL_DEPTH_TEST);\n    glEnable(GL_SCISSOR_TEST);\n#ifdef GL_POLYGON_MODE\n    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);\n#endif\n\n    // Setup viewport, orthographic projection matrix\n    // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.\n    glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);\n    float L = draw_data->DisplayPos.x;\n    float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;\n    float T = draw_data->DisplayPos.y;\n    float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;\n    const float ortho_projection[4][4] =\n    {\n        { 2.0f/(R-L),   0.0f,         0.0f,   0.0f },\n        { 0.0f,         2.0f/(T-B),   0.0f,   0.0f },\n        { 0.0f,         0.0f,        -1.0f,   0.0f },\n        { (R+L)/(L-R),  (T+B)/(B-T),  0.0f,   1.0f },\n    };\n    glUseProgram(g_ShaderHandle);\n    glUniform1i(g_AttribLocationTex, 0);\n    glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);\n#ifdef GL_SAMPLER_BINDING\n    glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.\n#endif\n\n    (void)vertex_array_object;\n#ifndef IMGUI_IMPL_OPENGL_ES2\n    glBindVertexArray(vertex_array_object);\n#endif\n\n    // Bind vertex/index buffers and setup attributes for ImDrawVert\n    glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle);\n    glEnableVertexAttribArray(g_AttribLocationVtxPos);\n    glEnableVertexAttribArray(g_AttribLocationVtxUV);\n    glEnableVertexAttribArray(g_AttribLocationVtxColor);\n    glVertexAttribPointer(g_AttribLocationVtxPos,   2, GL_FLOAT,         GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos));\n    glVertexAttribPointer(g_AttribLocationVtxUV,    2, GL_FLOAT,         GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv));\n    glVertexAttribPointer(g_AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE,  sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col));\n}\n\n// OpenGL3 Render function.\n// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)\n// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so.\nvoid    ImGuiRenderDrawData(ImDrawData* draw_data)\n{\n    // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)\n    int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);\n    int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);\n    if (fb_width <= 0 || fb_height <= 0)\n        return;\n\n    // Backup GL state\n    GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture);\n    glActiveTexture(GL_TEXTURE0);\n    GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);\n    GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);\n#ifdef GL_SAMPLER_BINDING\n    GLint last_sampler; glGetIntegerv(GL_SAMPLER_BINDING, &last_sampler);\n#endif\n    GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);\n#ifndef IMGUI_IMPL_OPENGL_ES2\n    GLint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array_object);\n#endif\n#ifdef GL_POLYGON_MODE\n    GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);\n#endif\n    GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);\n    GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);\n    GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb);\n    GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb);\n    GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha);\n    GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha);\n    GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb);\n    GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha);\n    GLboolean last_enable_blend = glIsEnabled(GL_BLEND);\n    GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);\n    GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);\n    GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);\n    bool clip_origin_lower_left = true;\n#if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__)\n    GLenum last_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)&last_clip_origin); // Support for GL 4.5's glClipControl(GL_UPPER_LEFT)\n    if (last_clip_origin == GL_UPPER_LEFT)\n        clip_origin_lower_left = false;\n#endif\n\n    // Setup desired GL state\n    // Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts)\n    // The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.\n    GLuint vertex_array_object = 0;\n#ifndef IMGUI_IMPL_OPENGL_ES2\n    glGenVertexArrays(1, &vertex_array_object);\n#endif\n    ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);\n\n    // Will project scissor/clipping rectangles into framebuffer space\n    ImVec2 clip_off = draw_data->DisplayPos;         // (0,0) unless using multi-viewports\n    ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)\n\n    // Render command lists\n    for (int n = 0; n < draw_data->CmdListsCount; n++)\n    {\n        const ImDrawList* cmd_list = draw_data->CmdLists[n];\n\n        // Upload vertex/index buffers\n        glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW);\n        glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW);\n\n        for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)\n        {\n            const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];\n            if (pcmd->UserCallback != NULL)\n            {\n                // User callback, registered via ImDrawList::AddCallback()\n                // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)\n                if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)\n                    ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);\n                else\n                    pcmd->UserCallback(cmd_list, pcmd);\n            }\n            else\n            {\n                // Project scissor/clipping rectangles into framebuffer space\n                ImVec4 clip_rect;\n                clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;\n                clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;\n                clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;\n                clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;\n\n                if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)\n                {\n                    // Apply scissor/clipping rectangle\n                    if (clip_origin_lower_left)\n                        glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y));\n                    else\n                        glScissor((int)clip_rect.x, (int)clip_rect.y, (int)clip_rect.z, (int)clip_rect.w); // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)\n\n                    // Bind texture, Draw\n                    glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);\n#if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET\n                    if (g_GlVersion >= 3200)\n                        glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset);\n                    else\n#endif\n                    glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)));\n                }\n            }\n        }\n    }\n\n    // Destroy the temporary VAO\n#ifndef IMGUI_IMPL_OPENGL_ES2\n    glDeleteVertexArrays(1, &vertex_array_object);\n#endif\n\n    // Restore modified GL state\n    glUseProgram(last_program);\n    glBindTexture(GL_TEXTURE_2D, last_texture);\n#ifdef GL_SAMPLER_BINDING\n    glBindSampler(0, last_sampler);\n#endif\n    glActiveTexture(last_active_texture);\n#ifndef IMGUI_IMPL_OPENGL_ES2\n    glBindVertexArray(last_vertex_array_object);\n#endif\n    glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);\n    glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);\n    glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);\n    if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);\n    if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);\n    if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);\n    if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);\n#ifdef GL_POLYGON_MODE\n    glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);\n#endif\n    glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);\n    glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);\n}\n\nbool ImGui_ImplOpenGL3_CreateFontsTexture()\n{\n    // Build texture atlas\n    ImGuiIO& io = ImGui::GetIO();\n    unsigned char* pixels;\n    int width, height;\n    io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);   // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.\n\n    // Upload texture to graphics system\n    GLint last_texture;\n    glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);\n    glGenTextures(1, &g_FontTexture);\n    glBindTexture(GL_TEXTURE_2D, g_FontTexture);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n#ifdef GL_UNPACK_ROW_LENGTH\n    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);\n#endif\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);\n\n    // Store our identifier\n    io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontTexture;\n\n    // Restore state\n    glBindTexture(GL_TEXTURE_2D, last_texture);\n\n    return true;\n}\n\nvoid ImGui_ImplOpenGL3_DestroyFontsTexture()\n{\n    if (g_FontTexture)\n    {\n        ImGuiIO& io = ImGui::GetIO();\n        glDeleteTextures(1, &g_FontTexture);\n        io.Fonts->TexID = 0;\n        g_FontTexture = 0;\n    }\n}\n\n// If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file.\nstatic bool CheckShader(GLuint handle, const char* desc)\n{\n    GLint status = 0, log_length = 0;\n    glGetShaderiv(handle, GL_COMPILE_STATUS, &status);\n    glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);\n    if ((GLboolean)status == GL_FALSE)\n        fprintf(stderr, \"ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\\n\", desc);\n    if (log_length > 1)\n    {\n        ImVector<char> buf;\n        buf.resize((int)(log_length + 1));\n        glGetShaderInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());\n        fprintf(stderr, \"%s\\n\", buf.begin());\n    }\n    return (GLboolean)status == GL_TRUE;\n}\n\n// If you get an error please report on GitHub. You may try different GL context version or GLSL version.\nstatic bool CheckProgram(GLuint handle, const char* desc)\n{\n    GLint status = 0, log_length = 0;\n    glGetProgramiv(handle, GL_LINK_STATUS, &status);\n    glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);\n    if ((GLboolean)status == GL_FALSE)\n        fprintf(stderr, \"ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! (with GLSL '%s')\\n\", desc, g_GlslVersionString);\n    if (log_length > 1)\n    {\n        ImVector<char> buf;\n        buf.resize((int)(log_length + 1));\n        glGetProgramInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());\n        fprintf(stderr, \"%s\\n\", buf.begin());\n    }\n    return (GLboolean)status == GL_TRUE;\n}\n\nbool    ImGui_ImplOpenGL3_CreateDeviceObjects()\n{\n    // Backup GL state\n    GLint last_texture, last_array_buffer;\n    glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);\n    glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);\n#ifndef IMGUI_IMPL_OPENGL_ES2\n    GLint last_vertex_array;\n    glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);\n#endif\n\n    // Parse GLSL version string\n    int glsl_version = 130;\n    sscanf(g_GlslVersionString, \"#version %d\", &glsl_version);\n\n    const GLchar* vertex_shader_glsl_120 =\n        \"uniform mat4 ProjMtx;\\n\"\n        \"attribute vec2 Position;\\n\"\n        \"attribute vec2 UV;\\n\"\n        \"attribute vec4 Color;\\n\"\n        \"varying vec2 Frag_UV;\\n\"\n        \"varying vec4 Frag_Color;\\n\"\n        \"void main()\\n\"\n        \"{\\n\"\n        \"    Frag_UV = UV;\\n\"\n        \"    Frag_Color = Color;\\n\"\n        \"    gl_Position = ProjMtx * vec4(Position.xy,0,1);\\n\"\n        \"}\\n\";\n\n    const GLchar* vertex_shader_glsl_130 =\n        \"uniform mat4 ProjMtx;\\n\"\n        \"in vec2 Position;\\n\"\n        \"in vec2 UV;\\n\"\n        \"in vec4 Color;\\n\"\n        \"out vec2 Frag_UV;\\n\"\n        \"out vec4 Frag_Color;\\n\"\n        \"void main()\\n\"\n        \"{\\n\"\n        \"    Frag_UV = UV;\\n\"\n        \"    Frag_Color = Color;\\n\"\n        \"    gl_Position = ProjMtx * vec4(Position.xy,0,1);\\n\"\n        \"}\\n\";\n\n    const GLchar* vertex_shader_glsl_300_es =\n        \"precision mediump float;\\n\"\n        \"layout (location = 0) in vec2 Position;\\n\"\n        \"layout (location = 1) in vec2 UV;\\n\"\n        \"layout (location = 2) in vec4 Color;\\n\"\n        \"uniform mat4 ProjMtx;\\n\"\n        \"out vec2 Frag_UV;\\n\"\n        \"out vec4 Frag_Color;\\n\"\n        \"void main()\\n\"\n        \"{\\n\"\n        \"    Frag_UV = UV;\\n\"\n        \"    Frag_Color = Color;\\n\"\n        \"    gl_Position = ProjMtx * vec4(Position.xy,0,1);\\n\"\n        \"}\\n\";\n\n    const GLchar* vertex_shader_glsl_410_core =\n        \"layout (location = 0) in vec2 Position;\\n\"\n        \"layout (location = 1) in vec2 UV;\\n\"\n        \"layout (location = 2) in vec4 Color;\\n\"\n        \"uniform mat4 ProjMtx;\\n\"\n        \"out vec2 Frag_UV;\\n\"\n        \"out vec4 Frag_Color;\\n\"\n        \"void main()\\n\"\n        \"{\\n\"\n        \"    Frag_UV = UV;\\n\"\n        \"    Frag_Color = Color;\\n\"\n        \"    gl_Position = ProjMtx * vec4(Position.xy,0,1);\\n\"\n        \"}\\n\";\n\n    const GLchar* fragment_shader_glsl_120 =\n        \"#ifdef GL_ES\\n\"\n        \"    precision mediump float;\\n\"\n        \"#endif\\n\"\n        \"uniform sampler2D Texture;\\n\"\n        \"varying vec2 Frag_UV;\\n\"\n        \"varying vec4 Frag_Color;\\n\"\n        \"void main()\\n\"\n        \"{\\n\"\n        \"    gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\\n\"\n        \"}\\n\";\n\n    const GLchar* fragment_shader_glsl_130 =\n        \"uniform sampler2D Texture;\\n\"\n        \"in vec2 Frag_UV;\\n\"\n        \"in vec4 Frag_Color;\\n\"\n        \"out vec4 Out_Color;\\n\"\n        \"void main()\\n\"\n        \"{\\n\"\n        \"    Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\\n\"\n        \"}\\n\";\n\n    const GLchar* fragment_shader_glsl_300_es =\n        \"precision mediump float;\\n\"\n        \"uniform sampler2D Texture;\\n\"\n        \"in vec2 Frag_UV;\\n\"\n        \"in vec4 Frag_Color;\\n\"\n        \"layout (location = 0) out vec4 Out_Color;\\n\"\n        \"void main()\\n\"\n        \"{\\n\"\n        \"    Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\\n\"\n        \"}\\n\";\n\n    const GLchar* fragment_shader_glsl_410_core =\n        \"in vec2 Frag_UV;\\n\"\n        \"in vec4 Frag_Color;\\n\"\n        \"uniform sampler2D Texture;\\n\"\n        \"layout (location = 0) out vec4 Out_Color;\\n\"\n        \"void main()\\n\"\n        \"{\\n\"\n        \"    Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\\n\"\n        \"}\\n\";\n\n    // Select shaders matching our GLSL versions\n    const GLchar* vertex_shader = NULL;\n    const GLchar* fragment_shader = NULL;\n    if (glsl_version < 130)\n    {\n        vertex_shader = vertex_shader_glsl_120;\n        fragment_shader = fragment_shader_glsl_120;\n    }\n    else if (glsl_version >= 410)\n    {\n        vertex_shader = vertex_shader_glsl_410_core;\n        fragment_shader = fragment_shader_glsl_410_core;\n    }\n    else if (glsl_version == 300)\n    {\n        vertex_shader = vertex_shader_glsl_300_es;\n        fragment_shader = fragment_shader_glsl_300_es;\n    }\n    else\n    {\n        vertex_shader = vertex_shader_glsl_130;\n        fragment_shader = fragment_shader_glsl_130;\n    }\n\n    // Create shaders\n    const GLchar* vertex_shader_with_version[2] = { g_GlslVersionString, vertex_shader };\n    g_VertHandle = glCreateShader(GL_VERTEX_SHADER);\n    glShaderSource(g_VertHandle, 2, vertex_shader_with_version, NULL);\n    glCompileShader(g_VertHandle);\n    CheckShader(g_VertHandle, \"vertex shader\");\n\n    const GLchar* fragment_shader_with_version[2] = { g_GlslVersionString, fragment_shader };\n    g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER);\n    glShaderSource(g_FragHandle, 2, fragment_shader_with_version, NULL);\n    glCompileShader(g_FragHandle);\n    CheckShader(g_FragHandle, \"fragment shader\");\n\n    g_ShaderHandle = glCreateProgram();\n    glAttachShader(g_ShaderHandle, g_VertHandle);\n    glAttachShader(g_ShaderHandle, g_FragHandle);\n    glLinkProgram(g_ShaderHandle);\n    CheckProgram(g_ShaderHandle, \"shader program\");\n\n    g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, \"Texture\");\n    g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, \"ProjMtx\");\n    g_AttribLocationVtxPos = glGetAttribLocation(g_ShaderHandle, \"Position\");\n    g_AttribLocationVtxUV = glGetAttribLocation(g_ShaderHandle, \"UV\");\n    g_AttribLocationVtxColor = glGetAttribLocation(g_ShaderHandle, \"Color\");\n\n    // Create buffers\n    glGenBuffers(1, &g_VboHandle);\n    glGenBuffers(1, &g_ElementsHandle);\n\n    ImGui_ImplOpenGL3_CreateFontsTexture();\n\n    // Restore modified GL state\n    glBindTexture(GL_TEXTURE_2D, last_texture);\n    glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);\n#ifndef IMGUI_IMPL_OPENGL_ES2\n    glBindVertexArray(last_vertex_array);\n#endif\n\n    return true;\n}\n\nvoid    ImGui_ImplOpenGL3_DestroyDeviceObjects()\n{\n    if (g_VboHandle)        { glDeleteBuffers(1, &g_VboHandle); g_VboHandle = 0; }\n    if (g_ElementsHandle)   { glDeleteBuffers(1, &g_ElementsHandle); g_ElementsHandle = 0; }\n    if (g_ShaderHandle && g_VertHandle) { glDetachShader(g_ShaderHandle, g_VertHandle); }\n    if (g_ShaderHandle && g_FragHandle) { glDetachShader(g_ShaderHandle, g_FragHandle); }\n    if (g_VertHandle)       { glDeleteShader(g_VertHandle); g_VertHandle = 0; }\n    if (g_FragHandle)       { glDeleteShader(g_FragHandle); g_FragHandle = 0; }\n    if (g_ShaderHandle)     { glDeleteProgram(g_ShaderHandle); g_ShaderHandle = 0; }\n\n    ImGui_ImplOpenGL3_DestroyFontsTexture();\n}\n"
  },
  {
    "path": "graphics/gui/imgui/legacy_imgui_impl_opengl3.h",
    "content": "// dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline\n// - Desktop GL: 2.x 3.x 4.x\n// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)\n// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)\n\n// Implemented features:\n//  [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!\n//  [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.\n\n// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.\n// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.\n// https://github.com/ocornut/imgui\n\n// About Desktop OpenGL function loaders:\n//  Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.\n//  Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad).\n//  You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.\n\n// About GLSL version:\n//  The 'glsl_version' initialization parameter should be NULL (default) or a \"#version XXX\" string.\n//  On computer platform the GLSL version default to \"#version 130\". On OpenGL ES 3 platform it defaults to \"#version 300 es\"\n//  Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp.\n\n#pragma once\n\n// Backend API\nIMGUI_IMPL_API bool     ImGuiInitOpenGl(const char* glsl_version = NULL);\nIMGUI_IMPL_API void     ImGuiShutdownOpenGL();\nIMGUI_IMPL_API void     ImGuiNewFrameOpenGL();\nIMGUI_IMPL_API void     ImGuiRenderDrawData(ImDrawData* draw_data);\n\n// (Optional) Called by Init/NewFrame/Shutdown\nIMGUI_IMPL_API bool     ImGui_ImplOpenGL3_CreateFontsTexture();\nIMGUI_IMPL_API void     ImGui_ImplOpenGL3_DestroyFontsTexture();\nIMGUI_IMPL_API bool     ImGui_ImplOpenGL3_CreateDeviceObjects();\nIMGUI_IMPL_API void     ImGui_ImplOpenGL3_DestroyDeviceObjects();\n\n// Specific OpenGL versions\n//#define IMGUI_IMPL_OPENGL_ES2     // Auto-detected on Emscripten\n//#define IMGUI_IMPL_OPENGL_ES3     // Auto-detected on iOS/Android\n\n// Desktop OpenGL: attempt to detect default GL loader based on available header files.\n// If auto-detection fails or doesn't select the same GL loader file as used by your application,\n// you are likely to get a crash in ImGui_ImplOpenGL3_Init().\n// You can explicitly select a loader by using '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.\n#if !defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) \\\n && !defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) \\\n && !defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) \\\n && !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)\n    #if defined(__has_include)\n        #if __has_include(<GL/glew.h>)\n            #define IMGUI_IMPL_OPENGL_LOADER_GLEW\n        #elif __has_include(<glad/glad.h>)\n            #define IMGUI_IMPL_OPENGL_LOADER_GLAD\n        #elif __has_include(<GL/gl3w.h>)\n            #define IMGUI_IMPL_OPENGL_LOADER_GL3W\n        #else\n            #error \"Cannot detect OpenGL loader!\"\n        #endif\n    #else\n        #define IMGUI_IMPL_OPENGL_LOADER_GL3W       // Default to GL3W\n    #endif\n#endif\n\n"
  },
  {
    "path": "graphics/gui/orderedVector.h",
    "content": "#pragma once\n\n#include <vector>\n\ntemplate<typename T>\nstruct OrderedVector {\nprivate:\n\tstd::vector<T> elements;\npublic:\n\tinline typename std::vector<T>::const_iterator begin() const {\n\t\treturn elements.begin();\n\t}\n\n\tinline typename std::vector<T>::const_iterator end() const {\n\t\treturn elements.end();\n\t}\n\n\tinline typename std::vector<T>::const_reverse_iterator rbegin() const {\n\t\treturn elements.rbegin();\n\t}\n\n\tinline typename std::vector<T>::const_reverse_iterator rend() const {\n\t\treturn elements.rend();\n\t}\n\n\tinline void insert(const T& element) {\n\t\telements.insert(begin(), element);\n\t}\n\n\tinline void add(const T& element) {\n\t\telements.push_back(element);\n\t}\n\n\tinline void remove(typename std::vector<T>::const_iterator iterator) {\n\t\telements.erase(iterator);\n\t}\n\n\tinline void remove(const T& element) {\n\t\tfor (auto iterator = begin(); iterator != end(); ++iterator) {\n\t\t\tif (&element == &*iterator)\n\t\t\t\telements.erase(iterator);\n\t\t}\n\t}\n\n\tinline void select(const T& element) {\n\t\tfor (auto iterator = begin(); iterator != end(); ++iterator) {\n\t\t\tif (element == *iterator) {\n\t\t\t\tauto resultValue = *iterator;\n\t\t\t\telements.erase(iterator);\n\t\t\t\telements.insert(begin(), resultValue);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tinline size_t size() const {\n\t\treturn elements.size();\n\t}\n\n\tT operator[](size_t index) const {\n\t\treturn elements[index];\n\t}\n};"
  },
  {
    "path": "graphics/legacy/button.cpp",
    "content": "#include \"core.h\"\n\n#include \"button.h\"\n\n#include \"texture.h\"\n#include \"font.h\"\n#include \"path/path.h\"\n\n#include \"mesh/primitive.h\"\n\n\nButton::Button(double x, double y, double width, double height, bool textured) : Component(x, y, width, height) {\n\tthis->textured = textured;\n\tthis->borderColor = GUI::borderColor;\n\n\tthis->padding = GUI::padding;\n\tthis->margin = GUI::margin;\n\t\n\tif (textured)\n\t\tthis->borderWidth = 0;\n\telse\n\t\tthis->borderWidth = GUI::borderWidth;\n}\n\nButton::Button(std::string text, double x, double y, bool textured) : Component(x, y) {\n\tthis->fontColor = GUI::fontColor;\n\tthis->fontSize = GUI::fontSize;\n\tthis->textured = textured;\n\n\tthis->padding = GUI::padding;\n\tthis->margin = GUI::margin;\n\n\tthis->text = text;\n\tthis->borderColor = GUI::borderColor;\n\tif (textured)\n\t\tthis->borderWidth = 0;\n\telse\n\t\tthis->borderWidth = GUI::borderWidth;\n}\n\nvoid Button::render() {\n\tif (visible) {\n\t\tresize();\n\n\t\tColor blendColor = (disabled) ? COLOR::DISABLED : COLOR::WHITE;\n\n\t\tVec2f buttonPosition = position;\n\t\tVec2f buttonDimension = dimension;\n\n\t\tif (borderWidth > 0) {\n\t\t\tPath::rectFilled(buttonPosition, buttonDimension, 0, COLOR::blend(borderColor, blendColor));\n\n\t\t\tbuttonPosition = position + Vec2f(borderWidth, -borderWidth);\n\t\t\tbuttonDimension = dimension - Vec2f(borderWidth) * 2;\n\t\t}\n\n\t\tif (pressed)\n\t\t\tif (textured) Path::rectUV(pressTexture->getID(), position, dimension);\n\t\t\telse Path::rectFilled(position, dimension, 0, COLOR::blend(pressColor, blendColor));\n\t\telse if (hovering)\n\t\t\tif (textured) Path::rectUV(hoverTexture->getID(), position, dimension);\n\t\t\telse Path::rectFilled(position, dimension, 0, COLOR::blend(hoverColor, blendColor));\n\t\telse\n\t\t\tif (textured) Path::rectUV(idleTexture->getID(), position, dimension);\n\t\t\telse Path::rectFilled(position, dimension, 0, COLOR::blend(idleColor, blendColor));\n\n\t\tif (!text.empty())\n\t\t\tPath::text(GUI::font, text, fontSize, position + Vec2(borderWidth, -borderWidth), COLOR::blend(fontColor, blendColor));\n\t}\n}\n\nVec2 Button::resize() {\n\tif (resizing) {\n\t\tdimension = GUI::font->size(text, fontSize) + Vec2(borderWidth) * 2;\n\t} \n\n\treturn dimension;\n}\n\nvoid Button::enter() {\n\tif (disabled)\n\t\treturn;\n\n\thovering = true;\n}\n\nvoid Button::exit() {\n\tif (disabled)\n\t\treturn;\n\n\thovering = false;\n\tpressed = false;\n}\n\nvoid Button::press(Vec2 point) {\n\tif (disabled)\n\t\treturn;\n\n\tpressed = true;\n}\n\nvoid Button::release(Vec2 point) {\n\tif (disabled)\n\t\treturn;\n\n\tpressed = false;\n\t(*action)(this);\n}\n\nvoid Button::setColor(const Color& color) {\n\tidleColor = color;\n\tpressColor = color;\n\thoverColor = color;\n}"
  },
  {
    "path": "graphics/legacy/button.h",
    "content": "#pragma once\n\n#include \"component.h\"\n\nclass Button;\nclass Texture;\n\ntypedef void (*ButtonAction) (Button*);\n\nclass Button : public Component {\npublic:\n\tButtonAction action = [] (Button*) {};\n\n\tTexture* hoverTexture = nullptr;\n\tTexture* idleTexture = nullptr;\n\tTexture* pressTexture = nullptr;\n\n\tstd::string text;\n\tColor fontColor;\n\tdouble fontSize;\n\n\tbool textured = false;\n\tbool hovering = false;\n\tbool pressed = false;\n\n\tColor hoverColor;\n\tColor idleColor;\n\tColor pressColor;\n\n\tColor borderColor;\n\tdouble borderWidth;\n\n\tvoid setColor(const Color& color);\n\n\tButton(double x, double y, double width, double height, bool textured);\n\tButton(std::string text, double x, double y, bool textured);\n\n\tvoid render() override;\n\tVec2 resize() override;\n\n\tvoid press(Vec2 point) override;\n\tvoid release(Vec2 point) override;\n\tvoid enter() override;\n\tvoid exit() override;\n};\n\n"
  },
  {
    "path": "graphics/legacy/checkBox.cpp",
    "content": "#include \"core.h\"\n\n#include \"checkBox.h\"\n\n#include \"label.h\"\n#include \"path/path.h\"\n\n#include \"texture.h\"\n#include \"renderUtils.h\"\n\n#include \"mesh/primitive.h\"\n\nCheckBox::CheckBox(std::string text, double x, double y, double width, double height, bool textured) : Component(x, y, width, height) {\n\tthis->label = new Label(text, x, y);\n\tthis->checkBoxLabelOffset = GUI::checkBoxLabelOffset;\n\tthis->textured = textured;\n\tthis->padding = GUI::padding;\n\tthis->margin = GUI::margin;\n\n\tif (textured) {\n\t\tthis->checkedTexture = GUI::checkBoxCheckedTexture;\n\t\tthis->uncheckedTexture = GUI::checkBoxUncheckedTexture;\n\t\tthis->hoverCheckedTexture = GUI::checkBoxHoverCheckedTexture;\n\t\tthis->hoverUncheckedTexture = GUI::checkBoxHoverUncheckedTexture;\n\t\tthis->pressCheckedTexture = GUI::checkBoxPressCheckedTexture;\n\t\tthis->pressUncheckedTexture = GUI::checkBoxPressUncheckedTexture;\n\t} else {\n\t\t// TODO colors\n\t}\n}\n\nCheckBox::CheckBox(std::string text, double x, double y, bool textured) : CheckBox(text, x, y, GUI::checkBoxSize + 2 * padding, GUI::checkBoxSize + 2 * padding, textured) {\n\n}\n\nCheckBox::CheckBox(double x, double y, bool textured) : CheckBox(\"\", x, y, GUI::checkBoxSize + 2 * padding, GUI::checkBoxSize + 2 * padding, textured) {\n\n}\n\nCheckBox::CheckBox(double x, double y, double width, double height, bool textured) : CheckBox(\"\", x, y, width, height, textured) {\n\n}\n\nvoid CheckBox::render() {\n\tif (visible) {\n\t\tresize();\n\n\t\tColor blendColor = (disabled) ? COLOR::DISABLED : COLOR::WHITE;\n\n\t\tVec2f checkBoxPosition;\n\t\tVec2f checkBoxDimension;\n\t\t\n\t\tif (label->text.empty()) {\n\t\t\t// No text, resizing using default width\n\t\t\tcheckBoxPosition = position + Vec2(padding, -padding);\n\t\t\tcheckBoxDimension = Vec2(GUI::checkBoxSize);\n\t\t} else {\n\t\t\tif (label->dimension.y > GUI::checkBoxSize) {\n\t\t\t\t// Label defines component size, checkbox is centered vertically\n\t\t\t\tcheckBoxPosition = position + Vec2(padding, -padding - (label->dimension.y - GUI::checkBoxSize) / 2);\n\t\t\t\tcheckBoxDimension = Vec2(GUI::checkBoxSize);\n\t\t\t} else {\n\t\t\t\t// Checkbox defines component size\n\t\t\t\tcheckBoxPosition = position + Vec2(padding, -padding);\n\t\t\t\tcheckBoxDimension = Vec2(GUI::checkBoxSize);\n\t\t\t}\n\t\t}\n\n\t\tif (pressed)\n\t\t\tif (textured)\n\t\t\t\tif (checked)\n\t\t\t\t\tPath::rectUV(pressCheckedTexture->getID(), checkBoxPosition, checkBoxDimension);\n\t\t\t\telse\n\t\t\t\t\tPath::rectUV(pressUncheckedTexture->getID(), checkBoxPosition, checkBoxDimension);\n\t\t\telse\n\t\t\t\tif (checked)\n\t\t\t\t\tPath::rectFilled(checkBoxPosition, checkBoxPosition, 0.0f, COLOR::blend(pressCheckedColor, blendColor));\n\t\t\t\telse\n\t\t\t\t\tPath::rectFilled(checkBoxPosition, checkBoxPosition, 0.0f, COLOR::blend(pressUncheckedColor, blendColor));\n\t\telse if (hovering)\n\t\t\tif (textured)\n\t\t\t\tif (checked)\n\t\t\t\t\tPath::rectUV(checkedTexture->getID(), checkBoxPosition, checkBoxDimension);\n\t\t\t\telse\n\t\t\t\t\tPath::rectUV(uncheckedTexture->getID(), checkBoxPosition, checkBoxDimension);\n\t\t\telse\n\t\t\t\tif (checked)\n\t\t\t\t\tPath::rectFilled(checkBoxPosition, checkBoxPosition, 0.0f, COLOR::blend(checkedColor, blendColor));\n\t\t\t\telse\n\t\t\t\t\tPath::rectFilled(checkBoxPosition, checkBoxPosition, 0.0f, COLOR::blend(uncheckedColor, blendColor));\n\t\telse\n\t\t\tif (textured)\n\t\t\t\tif (checked)\n\t\t\t\t\tPath::rectUV(hoverCheckedTexture->getID(), checkBoxPosition, checkBoxDimension);\n\t\t\t\telse\n\t\t\t\t\tPath::rectUV(hoverUncheckedTexture->getID(), checkBoxPosition, checkBoxDimension);\n\t\t\telse\n\t\t\t\tif (checked)\n\t\t\t\t\tPath::rectFilled(checkBoxPosition, checkBoxPosition, 0.0f, COLOR::blend(hoverCheckedColor, blendColor));\n\t\t\t\telse\n\t\t\t\t\tPath::rectFilled(checkBoxPosition, checkBoxPosition, 0.0f, COLOR::blend(hoverUncheckedColor, blendColor));\n\n\t\tif (!label->text.empty()) {\n\t\t\tVec2 labelPosition;\n\t\t\tif (label->dimension.y > GUI::checkBoxSize) {\n\t\t\t\t// Label defines the size of the component\n\t\t\t\tlabelPosition = position + Vec2(padding + checkBoxDimension.x + checkBoxLabelOffset, -padding);\n\t\t\t} else {\n\t\t\t\t// Label is centered vertically\n\t\t\t\tlabelPosition = position + Vec2(padding + checkBoxDimension.x + checkBoxLabelOffset, -padding - (GUI::checkBoxSize - label->dimension.y) / 2);\n\t\t\t}\n\t\t\tlabel->position = labelPosition;\n\t\t\tlabel->render();\n\t\t}\n\n\t\tif (debug) {\n\t\t\tPath::rect(position, dimension, 0.0f, COLOR::RED);\n\t\t\tPath::rect(checkBoxPosition, checkBoxDimension, 0.0f, COLOR::GREEN);\n\t\t}\n\t}\n}\n\nVec2 CheckBox::resize() {\n\tif (!label->text.empty()) {\n\t\tlabel->resize();\n\t\tif (label->dimension.y > GUI::checkBoxSize) {\n\t\t\t// Label defines dimension\n\t\t\tdimension = label->dimension + Vec2(GUI::checkBoxSize + checkBoxLabelOffset, 0) + Vec2(padding) * 2;\n\t\t} else {\n\t\t\t// Checkbox defines dimension\n\t\t\tdimension = Vec2(GUI::checkBoxSize + checkBoxLabelOffset + label->width, GUI::checkBoxSize) + Vec2(padding) * 2;\n\t\t}\n\t}\n\n\treturn dimension;\n}\n\nvoid CheckBox::disable() {\n\tdisabled = true;\n\tlabel->disable();\n}\n\nvoid CheckBox::enable() {\n\tdisabled = false;\n\tlabel->enable();\n}\n\nvoid CheckBox::enter() {\n\tif (disabled)\n\t\treturn;\n\n\thovering = true;\n}\n\nvoid CheckBox::exit() {\n\tif (disabled)\n\t\treturn;\n\n\thovering = false;\n\tpressed = false;\n}\n\nvoid CheckBox::press(Vec2 point) {\n\tif (disabled)\n\t\treturn;\n\n\tpressed = true;\n}\n\nvoid CheckBox::release(Vec2 point) {\n\tif (disabled)\n\t\treturn;\n\n\tpressed = false;\n\tchecked = !checked;\n\t(*action)(this);\n}\n"
  },
  {
    "path": "graphics/legacy/checkBox.h",
    "content": "#pragma once\n\n#include \"component.h\"\n\nclass CheckBox;\nclass Texture;\nclass Label;\n\ntypedef void (*CheckBoxAction) (CheckBox*);\n\nclass CheckBox : public Component {\npublic:\n\tCheckBoxAction action = [] (CheckBox*) {};\n\n\tTexture* pressUncheckedTexture = nullptr;\n\tTexture* pressCheckedTexture = nullptr;\n\tTexture* hoverUncheckedTexture = nullptr;\n\tTexture* hoverCheckedTexture = nullptr;\n\tTexture* uncheckedTexture = nullptr;\n\tTexture* checkedTexture = nullptr;\n\t\n\tbool textured = false;\n\tbool hovering = false;\n\tbool pressed = false;\n\tbool checked = false;\n\n\tColor pressUncheckedColor;\n\tColor pressCheckedColor;\n\tColor hoverUncheckedColor;\n\tColor hoverCheckedColor;\n\tColor uncheckedColor;\n\tColor checkedColor;\n\n\tdouble checkOffset;\n\tdouble checkBoxLabelOffset;\n\n\tLabel* label;\n\n\tCheckBox(double x, double y, bool textured);\n\tCheckBox(std::string text, double x, double y, bool textured);\n\tCheckBox(double x, double y, double width, double height, bool textured);\n\tCheckBox(std::string text, double x, double y, double width, double height, bool textured);\n\n\tvoid render() override;\n\tVec2 resize() override;\n\n\tvoid disable() override;\n\tvoid enable() override;\n\tvoid press(Vec2 point) override;\n\tvoid release(Vec2 point) override;\n\tvoid enter() override;\n\tvoid exit() override;\n};\n"
  },
  {
    "path": "graphics/legacy/colorPicker.cpp",
    "content": "#include \"core.h\"\n\n#include \"colorPicker.h\"\n\n#include \"guiUtils.h\"\n#include \"texture.h\"\n#include \"path/path.h\"\n#include \"mesh/primitive.h\"\n\nColorPicker::ColorPicker(double x, double y, double size) : Component(x, y, size, size) {\n\tthis->padding = GUI::padding;\n\tthis->margin = GUI::margin;\n\tthis->background = COLOR::BACK;\n\n\tdimension = Vec2(\n\t\tpadding + \n\t\tGUI::colorPickerBarWidth + 2 * GUI::colorPickerBarBorderWidth + \n\t\tGUI::colorPickerSpacing + \n\t\tGUI::colorPickerBarWidth + 2 * GUI::colorPickerBarBorderWidth +\n\t\tGUI::colorPickerSpacing + size + GUI::colorPickerSpacing + \n\t\tGUI::colorPickerBarWidth + 2 * GUI::colorPickerBarBorderWidth + \n\t\tpadding, \n\t\t\n\t\tpadding + size + padding\n\t);\n\n\tsetRgba(Vec4(1));\n}\n\nColorPicker::ColorPicker(double x, double y) : Component(x, y) {\n\tthis->background = COLOR::BACK;\n\tthis->padding = GUI::padding;\n\tthis->margin = GUI::margin;\n\n\tdimension = Vec2(\n\t\tpadding + \n\t\tGUI::colorPickerBarWidth + 2 * GUI::colorPickerBarBorderWidth +\n\t\tGUI::colorPickerSpacing +\n\t\tGUI::colorPickerBarWidth + 2 * GUI::colorPickerBarBorderWidth + \n\t\tGUI::colorPickerSpacing + GUI::colorPickerHueSize + GUI::colorPickerSpacing + \n\t\tGUI::colorPickerBarWidth + 2 * GUI::colorPickerBarBorderWidth + \n\t\tpadding,\n\t\t\n\t\tpadding + GUI::colorPickerHueSize + padding\n\t);\n\n\tsetRgba(Vec4(1));\n};\n\nvoid ColorPicker::render() {\n\tif (visible) {\n\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n\n\t\tVec4 blendColor = (disabled) ? COLOR::DISABLED : COLOR::WHITE;\n\n\t\t// Brightness\n\t\tVec2f brightnessBorderPosition = position + Vec2(padding, -padding);\n\t\tVec2f brightnessBorderDimension = Vec2(GUI::colorPickerBarWidth + 2 * GUI::colorPickerBarBorderWidth, height - 2 * padding);\n\t\tPath::rectFilled(brightnessBorderPosition, brightnessBorderDimension, 0.0f, COLOR::blend(GUI::colorPickerBarBorderColor, blendColor));\n\n\t\tVec2f brightnessPosition = brightnessBorderPosition + Vec2(GUI::colorPickerBarBorderWidth, -GUI::colorPickerBarBorderWidth);\n\t\tVec2f brightnessDimension = Vec2(GUI::colorPickerBarWidth, brightnessBorderDimension.y - 2 * GUI::colorPickerBarBorderWidth);\n\t\tPath::rectUV(GUI::colorPickerBrightnessTexture->getID(), brightnessPosition, brightnessDimension, Vec2f(0), Vec2f(1), COLOR::blend(COLOR::hsvaToRgba(Vec4(hsva.x, hsva.y, 1, 1)), blendColor));\n\n\t\tVec2f brightnessSelectorPosition = brightnessPosition + Vec2((GUI::colorPickerBarWidth - GUI::colorPickerSelectorWidth) / 2, -(1 - hsva.z) * brightnessDimension.y + GUI::colorPickerSelectorHeight / 2);\n\t\tVec2f brightnessSelectorDimension = Vec2(GUI::colorPickerSelectorWidth, GUI::colorPickerSelectorHeight);\n\t\tPath::rectFilled(brightnessSelectorPosition, brightnessSelectorDimension, 0.0f, COLOR::blend(GUI::colorPickerSelectorColor, blendColor));\n\n\t\t// Alpha\n\t\tVec2f alphaBorderPosition = brightnessBorderPosition + Vec2(brightnessBorderDimension.x + GUI::colorPickerSpacing, 0);\n\t\tVec2f alphaBorderDimension = brightnessBorderDimension;\n\t\tPath::rectFilled(alphaBorderPosition, alphaBorderDimension, 0.0f, COLOR::blend(GUI::colorPickerBarBorderColor, blendColor));;\n\n\t\tVec2f alphaPosition = alphaBorderPosition + Vec2(GUI::colorPickerBarBorderWidth, -GUI::colorPickerBarBorderWidth);\n\t\tVec2f alphaDimension = brightnessDimension;\n\t\tPath::rectUV(GUI::colorPickerAlphaPatternTexture->getID(), alphaPosition, alphaDimension);\n\t\tPath::rectUV(GUI::colorPickerAlphaBrightnessTexture->getID(), alphaPosition, alphaDimension, Vec2f(0), Vec2f(1), COLOR::blend(COLOR::hsvaToRgba(Vec4(hsva.x, hsva.y, hsva.z, 1)), blendColor));\n\n\t\tVec2f alphaSelectorPosition = alphaPosition + Vec2((GUI::colorPickerBarWidth - GUI::colorPickerSelectorWidth) / 2, -(1 - hsva.w) * brightnessDimension.y + GUI::colorPickerSelectorHeight / 2);\n\t\tVec2f alphaSelectorDimension = brightnessSelectorDimension;\n\t\tPath::rectFilled(alphaSelectorPosition, alphaSelectorDimension, 0.0f, COLOR::blend(GUI::colorPickerSelectorColor, blendColor));\n\n\t\t// Hue\n\t\tVec2f huePosition = Vec2(alphaBorderPosition.x + alphaBorderDimension.x + GUI::colorPickerSpacing, alphaBorderPosition.y);\n\t\tVec2f hueDimension = Vec2(alphaBorderDimension.y);\n\t\tPath::rectUV(GUI::colorPickerHueTexture->getID(), huePosition, hueDimension, Vec2f(0), Vec2f(1), blendColor);\n\n\t\tVec2f crosshairPosition = position + crosshair + Vec2(-GUI::colorPickerCrosshairSize, GUI::colorPickerCrosshairSize) / 2;\n\t\tVec2f crosshairDimension = Vec2(GUI::colorPickerCrosshairSize);\n\t\tPath::rectUV(GUI::colorPickerCrosshairTexture->getID(), crosshairPosition, crosshairDimension, Vec2f(0), Vec2f(1), blendColor);\n\n\t\t// Color\n\t\tVec2f colorBorderPosition = Vec2(huePosition.x + hueDimension.x + GUI::colorPickerSpacing, brightnessBorderPosition.y);\n\t\tVec2f colorBorderDimension = brightnessBorderDimension;\n\t\tPath::rectFilled(colorBorderPosition, colorBorderDimension, 0.0f, COLOR::blend(GUI::colorPickerBarBorderColor, blendColor));\n\n\t\tVec2f colorPosition = colorBorderPosition + Vec2(GUI::colorPickerBarBorderWidth, -GUI::colorPickerBarBorderWidth);\n\t\tVec2f colorDimension = brightnessDimension;\n\t\tPath::rectUV(GUI::colorPickerAlphaPatternTexture->getID(), colorPosition, colorDimension);\n\t\tPath::rectFilled(colorPosition, colorDimension, 0.0f, COLOR::blend(COLOR::hsvaToRgba(hsva), blendColor));\n\t}\n}\n\nVec2 ColorPicker::resize() {\n\treturn dimension;\n}\n\nvoid ColorPicker::setRgba(Color rgba) {\n\thsva = COLOR::rgbaToHsva(rgba);\n\tdouble radius = height / 2 - padding;\n\n\tVec2 relativeCenter = Vec2(padding + 2 * GUI::colorPickerBarWidth + 2 * GUI::colorPickerSpacing + 2 * 2 * GUI::colorPickerBarBorderWidth + radius, -height / 2);\n\tdouble angle = -(hsva.x - 0.25) * 2 * 3.14159265359;\n\tcrosshair = relativeCenter + Vec2(cos(angle), sin(angle)) * hsva.y * radius;\n}\n\nColor ColorPicker::getRgba() {\n\treturn COLOR::hsvaToRgba(hsva);\n}\n\nvoid ColorPicker::press(Vec2 point) {\n\tif (disabled)\n\t\treturn;\n\n\t// BrightnessPicker\n\tVec2 brightnessPosition = position + Vec2(padding + GUI::colorPickerBarBorderWidth, -GUI::colorPickerBarBorderWidth - padding);\n\tVec2 brightnessDimension = Vec2(GUI::colorPickerBarWidth, height - 2 * padding - 2 * GUI::colorPickerBarBorderWidth);\n\n\tif (!colorPicking && !brightnessPicking && !alphaPicking) {\n\t\tbrightnessPicking = GUI::intersectsSquare(point, brightnessPosition, brightnessDimension);\n\t} \n\n\tif (brightnessPicking) {\n\t\tdouble leftBottomY = brightnessPosition.y - brightnessDimension.y;\n\t\tdouble relativeY = point.y - leftBottomY;\n\t\thsva.z = GUI::clamp(relativeY / brightnessDimension.y, 0, 1);\n\t\t(*action)(this);\n\t}\n\n\t// AlphaPicker\n\tVec2 alphaPosition = brightnessPosition + Vec2(brightnessDimension.x + GUI::colorPickerSpacing + GUI::colorPickerBarBorderWidth, 0);\n\tVec2 alphaDimension = brightnessDimension;\n\n\tif (!colorPicking && !brightnessPicking && !alphaPicking) {\n\t\talphaPicking = GUI::intersectsSquare(point, alphaPosition, alphaDimension);\n\t}\n\n\tif (alphaPicking) {\n\t\tdouble leftBottomY = alphaPosition.y - alphaDimension.y;\n\t\tdouble relativeY = point.y - leftBottomY;\n\t\thsva.w = GUI::clamp(relativeY / alphaDimension.y, 0, 1);\n\t\t(*action)(this);\n\t}\n\n\t// ColorPicker\n\tdouble radius = height / 2 - padding;\n\tVec2 center = position + Vec2(padding + 2 * GUI::colorPickerBarWidth + 2 * GUI::colorPickerSpacing + 2 * 2 * GUI::colorPickerBarBorderWidth + radius, -height / 2);\n\tVec2 pointer = (point - center);\n\tdouble l = length(pointer);\n\n\tif (!colorPicking && !brightnessPicking && !alphaPicking) {\n\t\tcolorPicking = l <= radius;\n\t} \n\n\tif (colorPicking) {\n\t\tif (l > radius) {\n\t\t\tpointer = pointer / l * radius;\n\t\t\tpoint = center + pointer;\n\t\t\tl = radius;\n\t\t}\n\n\t\tcrosshair = point - position;\n\n\t\tdouble hue = fmod(atan2(-pointer.y, pointer.x) / (2 * 3.14159265359) + 1.25, 1);\n\t\tdouble saturation = l / radius;\n\t\thsva = Vec4(hue, saturation, hsva.z, hsva.w);\n\t\t(*action)(this);\n\t}\n}\n\nvoid ColorPicker::drag(Vec2 newPoint, Vec2 oldPoint) {\n\tif (disabled)\n\t\treturn;\n\n\tpress(newPoint);\n}\n\nvoid ColorPicker::release(Vec2 point) {\n\tif (disabled)\n\t\treturn;\n\n\tcolorPicking = false;\n\tbrightnessPicking = false;\n\talphaPicking = false;\n}"
  },
  {
    "path": "graphics/legacy/colorPicker.h",
    "content": "#pragma once\n\n#include \"component.h\"\n\nclass ColorPicker;\nclass Texture;\n\ntypedef void (*ColorPickerAction) (ColorPicker*);\n\nclass ColorPicker : public Component {\nprivate:\n\tVec2 crosshair;\n\n\tbool colorPicking;\n\tbool brightnessPicking;\n\tbool alphaPicking;\n\npublic:\n\tColorPickerAction action = [] (ColorPicker*) {};\n\n\tColor hsva;\n\tColor background;\n\n\tComponent* focus = nullptr;\n\n\tColorPicker(double x, double y, double size);\n\tColorPicker(double x, double y);\n\n\tvoid setRgba(Color rgba);\n\tColor getRgba();\n\n\tVec2 resize() override;\n\tvoid render() override;\n\n\tvoid press(Vec2 point) override;\n\tvoid drag(Vec2 newPoint, Vec2 oldPoint) override;\n\tvoid release(Vec2 point) override;\n};"
  },
  {
    "path": "graphics/legacy/component.h",
    "content": "#pragma once\n\n#include \"core.h\"\n\n#include \"layout.h\"\n#include \"gui.h\"\n\nnamespace P3D::Graphics {\n\nclass Component {\npublic:\n\t/*\n\t\tAlignment of the component within its current layout\n\t\tFLOW:\n\t\t\tFILL:\tThe component fills up the remaining width of the parent container\n\t\t\tRELATIVE: The components are placed next to eachother, filling up the container\n\t\t\tCENTER: The same as fill but the filled components are centered\n\t*/\n\tAlign align = Align::RELATIVE;\n\n\t/*\n\t\tParent of this component\n\t*/\n\tComponent* parent = nullptr;\n\n\t/*\n\t\tDetermines if the component has a fixed size\n\t*/\n\tbool resizing = true;\n\n\t/*\n\t\tDetermines if the component is disabled, the component will still be\n\t\trendered, but will not be interactable.\n\t*/\n\tbool disabled = false;\n\n\t/*\n\t\tThe topleft edge of the container, margin not included, padding included\n\t\tThis property can be altered by its parent\n\t*/\n\tunion {\n\t\tstruct {\n\t\t\tdouble x;\n\t\t\tdouble y;\n\t\t};\n\t\tVec2 position;\n\t};\n\n\t/*\n\t\tThe size of the container, margin not included, padding included\n\t\tThis property can be altered by its parent\n\t*/\n\tunion {\n\t\tstruct {\n\t\t\tfloat width;\n\t\t\tfloat height;\n\t\t};\n\t\tVec2f dimension;\n\t};\n\n\t/*\n\t\tPadding of this component\n\t*/\n\tdouble padding = GUI::padding;\n\n\t/*\n\t\tMargin of this component\n\t*/\n\tdouble margin = GUI::margin;\n\n\t/*\n\t\tDetermines if this component and its content should be rendered\n\t*/\n\tbool visible = true;\n\n\t/*\n\t\tDebug\n\t*/\n\tbool debug = false;\n\n\t/*\n\t\tConstructors\n\t*/\n\tComponent(Vec2 position, Vec2f dimension) : position(position), dimension(dimension), resizing(false) {};\n\tComponent(Vec2 position) : position(position), dimension(Vec2f(0.0f, 0.0f)), resizing(true) {};\n\tComponent(double x, double y, float width, float height) : Component(Vec2(x, y), Vec2f(width, height)) {};\n\tComponent(double x, double y) : Component(Vec2(x, y)) {};\n\n\n\t/*\n\t\tReturns this if the component contains the point\n\t*/\n\tvirtual Component* intersect(Vec2 point) {\n\t\tVec2f halfDimension = dimension / 2;\n\t\tVec2 center = position + Vec2f(halfDimension.x, -halfDimension.y);\n\t\tif (std::abs(point.x - center.x) < halfDimension.x && std::abs(point.y - center.y) < halfDimension.y)\n\t\t\treturn this;\n\t\treturn nullptr;\n\t}\n\n\t/*\n\t\tReturns the minimal size of the container, margin not included, padding included\n\t*/\n\tvirtual Vec2 resize() = 0;\n\n\t/*\n\t\tRenders the component, resizing may happen\n\t*/\n\tvirtual void render() = 0;\n\n\t/*\n\t\tDisables the component and all its children\n\t*/\n\tvirtual void disable() {\n\t\tdisabled = true;\n\t};\n\n\t/*\n\t\tEnables the component and all its children\n\t*/\n\tvirtual void enable() {\n\t\tdisabled = false;\n\t};\n\n\t/*\n\t\tDrag behaviour of this component\n\t*/\n\tvirtual void drag(Vec2 mxyNew, Vec2 mxyOld) {};\n\n\t/*\n\t\tHover behaviour of this component\n\t*/\n\tvirtual void hover(Vec2 mxy) {};\n\n\t/*\n\t\tPress behaviour of this component\n\t*/\n\tvirtual void press(Vec2 mxy) {};\n\n\t/*\n\t\tRelease behaviour of this component\n\t*/\n\tvirtual void release(Vec2 mxy) {}\n\n\t/*\n\t\tEnter behaviour of this component\n\t*/\n\tvirtual void enter() {};\n\n\t/*\n\t\tExit behaviour of this component\n\t*/\n\tvirtual void exit() {};\n};\n\n};"
  },
  {
    "path": "graphics/legacy/container.cpp",
    "content": "#include \"core.h\"\n\n#include \"container.h\"\n\n#include \"layout.h\"\n#include \"path/path.h\"\n#include \"mesh/primitive.h\"\n\nnamespace P3D::Graphics {\n\nContainer::Container(Vec2 position) : Component(position), layout(new FlowLayout()) {\n};\n\nContainer::Container(Vec2 position, Vec2 dimension) : Component(position, dimension), layout(new FlowLayout()) {\n\n};\n\nContainer::Container(double x, double y, double width, double height) : Container(Vec2(x, y), Vec2(width, height)) {\n};\n\nContainer::Container(double x, double y) : Container(Vec2(x, y)) {\n\n};\n\nvoid Container::add(Component* child) {\n\tadd(child, Align::RELATIVE);\n}\n\nvoid Container::add(Component* child, Align alignment) {\n\tchild->parent = this;\n\tchildren.add(std::make_pair(child, alignment));\n}\n\nstd::pair<Component*, Align> Container::get(Component* child) {\n\tfor (auto iterator = children.begin(); iterator != children.end(); ++iterator) {\n\t\tif (child == iterator->first)\n\t\t\treturn *iterator;\n\t}\n\n\tthrow \"Unreachable\";\n}\n\nvoid Container::remove(Component* child) {\n\tfor (auto iterator = children.begin(); iterator != children.end(); ++iterator) {\n\t\tif (child == iterator->first) {\n\t\t\tchildren.remove(iterator);\n\t\t\treturn;\n\t\t}\n\t}\n}\n\nComponent* Container::intersect(Vec2 point) {\n\tfor (auto iterator = children.begin(); iterator != children.end(); ++iterator) {\n\t\tif (iterator->first->intersect(point))\n\t\t\treturn iterator->first;\n\t}\n\treturn this->Component::intersect(point);\n}\n\nvoid Container::renderChildren() {\n\tfor (auto child : children) {\n\t\tchild.first->render();\n\t\tif (debug) {\n\t\t\tPath::rect(child.first->position + Vec2(-margin, margin), child.first->dimension + Vec2f::full(float(margin) * 2), 0, COLOR::RGB_R);\n\t\t\tPath::rect(child.first->position, child.first->dimension, 0, COLOR::RGB_G);\n\t\t\tPath::rect(child.first->position + Vec2(padding, -padding), child.first->dimension + Vec2f::full(-float(padding) * 2), 0, COLOR::RGB_B);\n\t\t}\n\t}\n}\n\n};"
  },
  {
    "path": "graphics/legacy/container.h",
    "content": "#pragma once\n\n#include \"orderedVector.h\"\n#include \"component.h\"\n\nnamespace P3D::Graphics {\n\nclass Container : public Component {\npublic:\n\t/*\n\t\tLayout of the container's children\n\t\tFLOW:\tThe children are placed next to eachother until they fill the width of the container,\n\t\t\t\tmuch like lines of text in a paragraph\n\t*/\n\tLayout* layout;\n\n\t/*\n\t\tChildren of this container, ordered by z-index\n\t*/\n\tOrderedVector<std::pair<Component*, Align>> children;\n\n\t/*\n\t\tConstructors\n\t*/\n\tContainer(Vec2 position);\n\tContainer(Vec2 position, Vec2 dimension);\n\tContainer(double x, double y, double width, double height);\n\tContainer(double x, double y);\n\n\t/*\n\t\tAdds the child to the end of the container\n\t*/\n\tvoid add(Component* child);\n\n\t/*\n\t\tAdds the child to the end of the container with a given alignment\n\t*/\n\tvoid add(Component* child, Align alignment);\n\n\t/*\n\t\tReturns the child with its alignment\n\t*/\n\tstd::pair<Component*, Align> get(Component* child);\n\n\t/*\n\t\tRemoves the given child from the children\n\t*/\n\tvoid remove(Component* child);\n\n\t/*\n\t\tReturns the intersected component at the given point.\n\t*/\n\tvirtual Component* intersect(Vec2 point);\n\n\t/*\n\t\tRenders the children of the container\n\t*/\n\tvirtual void renderChildren();\n\n\tvirtual void render() = 0;\n\tvirtual Vec2 resize() = 0;\n};\n\n}"
  },
  {
    "path": "graphics/legacy/cshader.cpp",
    "content": "#include \"core.h\"\n\n#include <GL/glew.h>\n\n#include \"cshader.h\"\n#include \"renderer.h\"\n#include \"debug/guiDebug.h\"\n\n#include <fstream>\n#include <sstream>\n#include <future>\n\n#include \"../util/stringUtil.h\"\n#include \"../util/fileUtils.h\"\n\nnamespace P3D::Graphics {\n\n#pragma region compile\n\nGLID CShader::createShader(const ShaderSource& shaderSource) {\n\tGLID program = glCreateProgram();\n\n\tLog::subject s(shaderSource.name);\n\tLog::info(\"Compiling shader (%s)\", shaderSource.name.c_str());\n\n\tGLID cs = 0;\n\n\tcs = Shader::compile(\"Compute shader\", shaderSource.computeSource, GL_VERTEX_SHADER);\n\tglAttachShader(program, cs);\n\n\tglCall(glLinkProgram(program));\n\tglCall(glValidateProgram(program));\n\n\tglDeleteShader(cs);\n\n\tLog::info(\"Created shader with id (%d)\", program);\n\n\treturn program;\n}\n\n#pragma endregion\n\n#pragma region constructors\n\nCShader::CShader() {};\nCShader::CShader(const ShaderSource& shaderSource) : Shader(shaderSource) {\n\tid = createShader(shaderSource);\n\n\tbool result = addShaderStage(shaderSource.computeSource, COMPUTE);\n};\n\nCShader::CShader(const std::string& name, const std::string& path, const std::string& computeSource) : CShader(ShaderSource(name, path, \"\", \"\", \"\", \"\", \"\", computeSource)) {}\n\nCShader::~CShader() {\n\tclose();\n}\n\nCShader::CShader(CShader&& other) {\n\t// TODO\n}\n\nCShader& CShader::operator=(CShader&& other) {\n\tif (this != &other) {\n\t\tclose();\n\t}\n\n\treturn *this;\n}\n\n#pragma endregion\n\n\nbool CShader::addShaderStage(const std::string& source, const ShaderFlag& flag) {\n\tShaderStage stage(source);\n\t\n\tif (!stage.source.empty()) {\n\t\taddUniforms(stage);\n\n\t\tflags |= flag;\n\n\t\tswitch (flag) {\n\t\t\tcase COMPUTE:\n\t\t\t\tcomputeStage = stage;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn true;\n}\n\nvoid CShader::close() {\n\tShader::close();\n}\n\nvoid CShader::dispatch(unsigned int x, unsigned int y, unsigned int z) {\n\tglDispatchCompute(x, y, z);\n}\n\nvoid CShader::barrier(unsigned int flags) {\n\tglMemoryBarrier(flags);\n}\n\n};"
  },
  {
    "path": "graphics/legacy/cshader.h",
    "content": "#pragma once\n\n#include \"shader.h\"\n\nnamespace P3D::Graphics {\n\nclass CShader : public Shader {\nprivate:\n\tGLID createShader(const ShaderSource& shaderSource);\n\nprotected:\n\tbool addShaderStage(const std::string& source, const ShaderFlag& flag) override;\n\npublic:\n\tShaderStage computeStage;\n\n\tCShader();\n\tCShader(const ShaderSource& shaderSource);\n\tCShader(const std::string& name, const std::string& path, const std::string& computeShader);\n\n\t~CShader();\n\tCShader(CShader&& other);\n\tCShader(const CShader&) = delete;\n\tCShader& operator=(CShader&& other);\n\tCShader& operator=(const CShader&) = delete;\n\n\tvoid close() override;\n\n\tvoid dispatch(unsigned int x, unsigned int y, unsigned int z);\n\tvoid barrier(unsigned int flags);\n};\n\nShaderSource parseShader(const std::string& name, const std::string& path, const std::string& computePath);\n\n};"
  },
  {
    "path": "graphics/legacy/directionEditor.cpp",
    "content": "#include \"core.h\"\n\n#include \"directionEditor.h\"\n\n#include \"../physics/math/cframe.h\"\n#include \"../physics/math/mathUtil.h\"\n#include \"../physics/math/globalCFrame.h\"\n\n#include \"gui.h\"\n#include \"texture.h\"\n#include \"renderUtils.h\"\n#include \"path/path.h\"\n#include \"buffers/frameBuffer.h\"\n#include \"mesh/indexedMesh.h\"\n#include \"mesh/primitive.h\"\n#include \"meshLibrary.h\"\n\nDirectionEditor::DirectionEditor(double x, double y, double width, double height) : Component(x, y, width, height) {\n\tviewPosition = Position(0.0, 0.0, -3.0);\n\tviewMatrix = CFrameToMat4(GlobalCFrame(viewPosition));\n\tmodelMatrix = Matrix<float, 4, 4>::IDENTITY(); //.scale(4, 0.5, 4);\n\trspeed = 10;\n}\n\nvoid DirectionEditor::render() {\n\tif (visible) {\n\n\t\tColor blendColor = (disabled) ? COLOR::DISABLED : COLOR::WHITE;\n\n\t\t// Draw onto gui framebuffer\n\t\tGUI::guiFrameBuffer->bind();\n\t\tRenderer::enableDepthTest();\n\t\tRenderer::clearColor();\n\t\tRenderer::clearDepth();\n\n\t\tLibrary::vector->render();\n\n\t\tGUI::guiFrameBuffer->unbind();\n\t\tRenderer::disableDepthTest();\n\n\t\tPath::rect(position, dimension, 0.0f, COLOR::blend(COLOR::BACK, blendColor));\n\n\t\tVec2 contentPosition = position + Vec2(GUI::padding, -GUI::padding);\n\t\tVec2 contentDimension = dimension - Vec2(GUI::padding) * 2;\n\t\tPath::rectUV(GUI::guiFrameBuffer->texture->getID(), contentPosition, contentDimension, Vec2f(0), Vec2f(1), blendColor);\n\t}\n}\n\nvoid DirectionEditor::rotate(double dalpha, double dbeta, double dgamma) {\n\tmodelMatrix = Mat4f(Matrix<float, 3, 3>(rotX(float(dalpha)) * Mat3f(modelMatrix.getSubMatrix<3, 3>(0,0)) * rotZ(float(-dbeta))), 1.0f);\n\t(*action)(this);\n}\n\nVec2 DirectionEditor::resize() {\n\treturn dimension;\n}\n\nvoid DirectionEditor::drag(Vec2 newPoint, Vec2 oldPoint) {\n\tif (disabled)\n\t\treturn;\n\n\tVec2 dmxy = newPoint - oldPoint;\n\trotate(dmxy.y * rspeed, dmxy.x * rspeed, 0);\n}\n"
  },
  {
    "path": "graphics/legacy/directionEditor.h",
    "content": "#pragma once\n\n#include \"component.h\"\n\nclass DirectionEditor;\n\ntypedef void (*DirectionEditorAction) (DirectionEditor*);\n\nclass DirectionEditor : public Component {\nprivate:\n\tMat4f viewMatrix;\n\tPosition viewPosition;\n\t\n\tdouble rspeed;\n\tvoid rotate(double dalpha, double dbeta, double dgamma);\npublic:\n\tMat4f modelMatrix;\n\tDirectionEditorAction action = [] (DirectionEditor*) {};\n\n\tDirectionEditor(double x, double y, double width, double height);\n\n\tvoid render() override;\n\tVec2 resize() override;\n\n\tvoid drag(Vec2 newPoint, Vec2 oldPoint) override;\n};"
  },
  {
    "path": "graphics/legacy/frame.cpp",
    "content": "#include \"core.h\"\n\n#include \"frame.h\"\n\n#include \"path/path.h\"\n#include \"button.h\"\n#include \"label.h\"\n#include \"texture.h\"\n#include \"renderUtils.h\"\n#include \"guiUtils.h\"\n#include \"mesh/primitive.h\"\n#include \"buffers/frameBuffer.h\"\n#include \"../physics/math/mathUtil.h\"\n\nFrame::Frame() : Frame(0, 0) {\n\n};\n\nFrame::Frame(double x, double y, std::string name) : Container(x, y) {\n\tthis->backgroundColor = GUI::frameBackgroundColor;\n\tthis->titleBarColor = GUI::frameTitleBarColor;\n\tthis->titleBarHeight = GUI::frameTitleBarHeight;\n\n\tthis->buttonOffset = GUI::frameButtonOffset;\n\n\tthis->closeButton = new Button(position.x, position.y, titleBarHeight - 2 * buttonOffset, titleBarHeight - 2 * buttonOffset, true);\n\tthis->closeButton->parent = this;\n\tthis->closeButton->idleTexture = GUI::closeButtonIdleTexture;\n\tthis->closeButton->hoverTexture = GUI::closeButtonHoverTexture;\n\tthis->closeButton->pressTexture = GUI::closeButtonPressTexture;\n\tthis->closeButton->action = [] (Button* button) {\n\t\tbutton->parent->visible = false;\n\t};\n\n\tthis->minimizeButton = new Button(position.x, position.y, titleBarHeight - 2 * buttonOffset, titleBarHeight - 2 * buttonOffset, true);\n\tthis->minimizeButton->parent = this;\n\tthis->minimizeButton->idleTexture = GUI:: minimizeButtonIdleTexture;\n\tthis->minimizeButton->hoverTexture = GUI::minimizeButtonHoverTexture;\n\tthis->minimizeButton->pressTexture = GUI::minimizeButtonPressTexture;\n\tthis->minimizeButton->action = [] (Button* button) {\n\t\tFrame* frame = static_cast<Frame*>(button->parent);\n\t\tframe->minimized = !frame->minimized;\n\t};\n\n\ttitle = new Label(name, position.x, position.y);\n\n\tanchor = nullptr;\n};\n\nFrame::Frame(double x, double y, double width, double height, std::string name) : Container(x, y, width, height) {\n\tthis->padding = GUI::padding;\n\tthis->margin = GUI::margin;\n\n\tthis->backgroundColor = GUI::frameBackgroundColor;\n\tthis->titleBarColor = GUI::frameTitleBarColor;\n\tthis->titleBarHeight = GUI::frameTitleBarHeight;\n\n\tthis->buttonOffset = GUI::frameButtonOffset;\n\n\tthis->closeButton = new Button(position.x, position.y, titleBarHeight - 2 * buttonOffset, titleBarHeight - 2 * buttonOffset, true);\n\tthis->closeButton->parent = this;\n\tthis->closeButton->idleTexture = GUI::closeButtonIdleTexture;\n\tthis->closeButton->hoverTexture = GUI::closeButtonHoverTexture;\n\tthis->closeButton->pressTexture = GUI::closeButtonPressTexture;\n\tthis->closeButton->action = [] (Button* button) {\n\t\tbutton->parent->visible = false;\n\t};\n\n\tthis->minimizeButton = new Button(position.x, position.y, titleBarHeight - 2 * buttonOffset, titleBarHeight - 2 * buttonOffset, true);\n\tthis->minimizeButton->parent = this;\n\tthis->minimizeButton->idleTexture = GUI::minimizeButtonIdleTexture;\n\tthis->minimizeButton->hoverTexture = GUI::minimizeButtonHoverTexture;\n\tthis->minimizeButton->pressTexture = GUI::minimizeButtonPressTexture;\n\tthis->minimizeButton->action = [] (Button* button) {\n\t\tFrame* frame = (Frame*) button->parent;\n\t\tframe->minimized = !frame->minimized;\n\t};\n\n\ttitle = new Label(name, position.x, position.y);\n\n\tanchor = nullptr;\n};\n\nVec2 Frame::resize() {\n\tif (anchor)\n\t\tposition = Vec2(anchor->position.x + anchor->dimension.x + 2 * GUI::padding, anchor->position.y);\n\n\t// Button\n\tcloseButton->position = position + Vec2(width - titleBarHeight + buttonOffset, -buttonOffset);\n\tminimizeButton->position = position + Vec2(width - 2 * titleBarHeight + buttonOffset, -buttonOffset);\n\n\t// Title\n\tif (!title->text.empty()) {\n\t\ttitle->resize();\n\t\tdouble yOffset = (titleBarHeight - title->height) / 2;\n\t\ttitle->position = position + Vec2(yOffset, -yOffset);\n\t}\n\n\t// Content\n\tif (!minimized) {\n\t\tVec2 positionOffset = Vec2(padding, -padding - titleBarHeight);\n\t\tVec2 dimensionOffset = Vec2(2 * padding, 2 * padding + titleBarHeight);\n\n\t\tposition += positionOffset;\n\t\tdimension -= dimensionOffset;\n\n\t\tif (title->text.empty())\n\t\t\tdimension = layout->resize(this);\n\t\telse\n\t\t\tdimension = layout->resize(this, Vec2(title->dimension.x + (titleBarHeight - title->height) / 2 + 2 * titleBarHeight, 0));\n\n\n\t\tposition -= positionOffset;\n\t\tdimension += dimensionOffset;\n\t} else {\n\t\tdimension = Vec2(dimension.x, titleBarHeight);\n\t}\n\n\treturn dimension;\n}\n\nComponent* Frame::intersect(Vec2 point) {\n\tif (closeButton->intersect(point))\n\t\treturn closeButton;\n\n\tif (minimizeButton->intersect(point))\n\t\treturn minimizeButton;\n\n\tif (!minimized) {\n\t\tfor (auto component : children) {\n\t\t\tif (component.first->intersect(point))\n\t\t\t\treturn component.first;\n\t\t}\n\t}\n\n\tif (GUI::intersectsSquare(point, position, dimension)) {\n\t\treturn this;\n\t}\n\n\treturn nullptr;\n}\n\nvoid Frame::disable() {\n\tdisabled = true;\n\n\tminimizeButton->disable();\n\tcloseButton->disable();\n\ttitle->disable();\n\n\tfor (auto component : children)\n\t\tcomponent.first->disable();\n}\n\nvoid Frame::enable() {\n\tdisabled = false;\n\n\tminimizeButton->enable();\n\tcloseButton->enable();\n\ttitle->enable();\n\n\tfor (auto component : children)\n\t\tcomponent.first->enable();\n}\n\nvoid Frame::press(Vec2 point) {\n\tif (GUI::between(point.x - x, 0, GUI::frameResizeHandleSize)) {\n\t\tresizeFlags |= resizingW;\n\t\tresizing = false;\n\t}\n\n\tif (GUI::between(point.y - y, -GUI::frameResizeHandleSize, 0)) {\n\t\tresizeFlags |= resizingN;\n\t\tresizing = false;\n\t}\n\n\tif (GUI::between(point.x - x - width, -GUI::frameResizeHandleSize, 0)) {\n\t\tresizeFlags |= resizingE;\n\t\tresizing = false;\n\t}\n\n\tif (GUI::between(point.y - y + height, 0, GUI::frameResizeHandleSize)) {\n\t\tresizeFlags |= resizingS;\n\t\tresizing = false;\n\t}\n}\n\nvoid Frame::release(Vec2 point) {\n\tresizeFlags = None;\n}\n\nvoid Frame::drag(Vec2 newPoint, Vec2 oldPoint) {\n\tif (disabled)\n\t\treturn;\n\n\tif (resizeFlags != None) {\n\t\t// component resizing should be off right now\n\t\tif (resizeFlags & resizingE) {\n\t\t\twidth = GUI::clamp(newPoint.x - x, title->width, 10);\n\t\t} else if (resizeFlags & resizingW) {\n\t\t\twidth = GUI::clamp(x - newPoint.x + width, title->width, 10);\n\t\t\tx = newPoint.x;\n\t\t}\n\n\t\tif (resizeFlags & resizingS) {\n\t\t\theight = GUI::clamp(y - newPoint.y, titleBarHeight, 10);\n\t\t} else if (resizeFlags & resizingN) {\n\t\t\theight = GUI::clamp(newPoint.y - y + height, titleBarHeight, 10);\n\t\t\ty = newPoint.y;\n\t\t}\n\t} else {\n\t\tposition += newPoint - oldPoint;\n\t\tanchor = nullptr;\n\t}\n}\n\nvoid Frame::render() {\n\tif (visible) {\n\n\t\tColor blendColor = (disabled) ? COLOR::DISABLED : COLOR::WHITE;\n\n\t\tresize();\n\n\t\t// TitleBar\n\t\tVec2f titleBarPosition = position;\n\t\tVec2f titleBarDimension = Vec2f(width, titleBarHeight);\n\t\tPath::rectFilled(titleBarPosition, titleBarDimension, 0, COLOR::blend(titleBarColor, blendColor));\n\n\t\t// Buttons\n\t\tcloseButton->render();\n\t\tminimizeButton->render();\n\n\t\t// Title\n\t\tif (!title->text.empty())\n\t\t\ttitle->render();\n\n\t\tif (!minimized) {\n\t\t\t// Padding\n\t\t\tVec2f offsetPosition = titleBarPosition + Vec2f(0, -titleBarHeight);\n\t\t\tVec2f offsetDimension = dimension + Vec2f(0, -titleBarHeight);\n\t\t\tVec2f xRange = Vec2f(-GUI::windowInfo.aspect, GUI::windowInfo.aspect) * 2;\n\t\t\tVec2f yRange = Vec2(-1, 1);\n\t\t\tColor color = COLOR::blend(Color(0.4, 0.4, 0.4, 1), blendColor);\n\n\t\t\tPath::rectUVRange(GUI::blurFrameBuffer->texture->getID(), offsetPosition, offsetDimension, xRange, yRange, color);\n\n\t\t\trenderChildren();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "graphics/legacy/frame.h",
    "content": "#pragma once\n\n#include \"component.h\"\n#include \"container.h\"\n\nclass Button;\nclass Label;\n\nclass Frame : public Container {\nprivate:\n\tenum ResizingFlags : char {\n\t\t// Not resizing\n\t\tNone = 0 << 0,\n\n\t\t// Resizing using top handle\n\t\tresizingN = 1 << 0,\n\n\t\t// Resizing using right handle\n\t\tresizingE = 1 << 1,\n\n\t\t// Resizing using bottom handle\n\t\tresizingS = 1 << 2,\n\n\t\t// Resizing using left handle\n\t\tresizingW = 1 << 3\n\t};\n\n\tchar resizeFlags = None;\n\npublic:\n\tComponent* anchor;\n\n\tButton* closeButton;\n\tButton* minimizeButton;\n\tdouble buttonOffset;\n\n\tLabel* title;\n\n\tdouble titleBarHeight;\n\tColor titleBarColor;\n\n\tColor backgroundColor;\n\n\tbool minimized = false;\n\n\tFrame();\n\tFrame(double x, double y, std::string title = \"\");\n\tFrame(double x, double y, double width, double height, std::string title = \"\");\n\n\tVec2 resize() override;\n\tvoid render() override;\n\n\tComponent* intersect(Vec2 point) override;\n\n\tvoid drag(Vec2 newPoint, Vec2 oldPoint) override;\n\tvoid press(Vec2 point) override;\n\tvoid release(Vec2 point) override;\n\tvoid disable() override;\n\tvoid enable() override;\n};\n\n"
  },
  {
    "path": "graphics/legacy/gshader.cpp",
    "content": "#include \"core.h\"\n\n#include <GL/glew.h>\n\n#include \"gshader.h\"\n#include \"renderer.h\"\n#include \"debug/guiDebug.h\"\n\n#include <fstream>\n#include <sstream>\n#include <future>\n\n#include \"../../util/systemVariables.h\"\n#include \"../util/fileUtils.h\"\n\nnamespace P3D::Graphics {\n\n#pragma region compile\n\nGLID GShader::createShader(const ShaderSource& shaderSource) {\n\tif (SystemVariables::get(\"OPENGL_SHADER_VERSION\") < 330) {\n\t\tLog::print(Log::Color::ERROR, \"shader version not supported\\n\");\n\t\tLog::setDelimiter(\"\\n\");\n\t\treturn 0;\n\t}\n\t\n\tGLID program = glCreateProgram();\n\n\tLog::subject s(shaderSource.name);\n\tLog::info(\"Compiling shader (%s)\", shaderSource.name.c_str());\n\n\tGLID vs = 0;\n\tGLID fs = 0;\n\tGLID gs = 0;\n\tGLID tcs = 0;\n\tGLID tes = 0;\n\n\tvs = Shader::compile(\"Vertex shader\", shaderSource.vertexSource, GL_VERTEX_SHADER);\n\tglAttachShader(program, vs);\n\n\tfs = Shader::compile(\"Fragment shader\", shaderSource.fragmentSource, GL_FRAGMENT_SHADER);\n\tglAttachShader(program, fs);\n\n\tif (!shaderSource.geometrySource.empty()) {\n\t\tgs = Shader::compile(\"Geometry shader\", shaderSource.geometrySource, GL_GEOMETRY_SHADER);\n\t\tglAttachShader(program, gs);\n\t}\n\n\tif (!shaderSource.tesselationControlSource.empty()) {\n\t\ttcs = Shader::compile(\"Tesselation control shader\", shaderSource.tesselationControlSource, GL_TESS_CONTROL_SHADER);\n\t\tglAttachShader(program, tcs);\n\t}\n\n\tif (!shaderSource.tesselationEvaluateSource.empty()) {\n\t\ttes = Shader::compile(\"Tesselation evaluate\", shaderSource.tesselationEvaluateSource, GL_TESS_EVALUATION_SHADER);\n\t\tglAttachShader(program, tes);\n\t}\n\n\tglCall(glLinkProgram(program));\n\tglCall(glValidateProgram(program));\n\n\tglDeleteShader(vs);\n\tglDeleteShader(fs);\n\tif (!shaderSource.geometrySource.empty())\n\t\tglDeleteShader(gs);\n\tif (!shaderSource.tesselationControlSource.empty())\n\t\tglDeleteShader(tcs);\n\tif (!shaderSource.tesselationEvaluateSource.empty())\n\t\tglDeleteShader(tes);\n\n\tLog::info(\"Created shader with id (%d)\", program);\n\n\treturn program;\n}\n\nvoid GShader::reload(const ShaderSource& shaderSource) {\n\tLog::subject s(name);\n\tLog::info(\"Reloading shader (%s)\", name.c_str());\n\n\tGShader shader(shaderSource);\n\tif (shader.id == 0) {\n\t\tLog::error(\"Reloading failed\");\n\t\treturn;\n\t}\n\n\tunbind();\n\tglDeleteProgram(id);\n\n\tthis->id = shader.id;\n\tshader.id = 0; // Avoid deletion\n\tthis->uniforms = shader.uniforms;\n\tthis->vertexStage = shader.vertexStage;\n\tthis->fragmentStage = shader.fragmentStage;\n\tthis->geometryStage = shader.geometryStage;\n\tthis->tesselationControlStage = shader.tesselationControlStage;\n\tthis->tesselationEvaluationStage = shader.tesselationEvaluationStage;\n\tthis->flags = shader.flags;\n\tthis->name = shader.name;\n\n\tLog::info(\"Reloading succesful\");\n}\n\n#pragma endregion\n\n#pragma region parse\n\nShaderSource parseShader(const std::string& name, const std::string& path, const std::string& vertexPath, const std::string& fragmentPath, const std::string& geometryPath, const std::string& tesselationControlPath, const std::string& tesselationEvaluatePath) {\n\tLog::subject s(name);\n\n\tstd::string vertexFile = Util::parseFile(vertexPath);\n\tstd::string fragmentFile = Util::parseFile(fragmentPath);\n\tstd::string geometryFile = Util::parseFile(geometryPath);\n\tstd::string tesselationControlFile = Util::parseFile(tesselationControlPath);\n\tstd::string tesselationEvaluateFile = Util::parseFile(tesselationEvaluatePath);\n\n\treturn ShaderSource(name, path, vertexFile, fragmentFile, geometryFile, tesselationControlFile, tesselationEvaluateFile, \"\");\n}\n\nbool GShader::addShaderStage(const std::string& source, const ShaderFlag& flag) {\n\tShaderStage stage(source);\n\t\n\tif (SystemVariables::get(\"OPENGL_SHADER_VERSION\") < stage.info.version.version) {\n\t\tLog::error(\"Shader version %d %snot supported for shader %s\", stage.info.version.version, stage.info.version.core ? \"core \" : \"\", name.c_str());\n\t\treturn false;\n\t}\n\t\n\tif (!stage.source.empty()) {\n\t\taddUniforms(stage);\n\n\t\tflags |= flag;\n\n\t\tswitch (flag) {\n\t\t\tcase VERTEX:\n\t\t\t\tvertexStage = stage;\n\t\t\t\tbreak;\n\t\t\tcase FRAGMENT:\n\t\t\t\tfragmentStage = stage;\n\t\t\t\tbreak;\n\t\t\tcase GEOMETRY:\n\t\t\t\tgeometryStage = stage;\n\t\t\t\tbreak;\n\t\t\tcase TESSELATION_CONTROL:\n\t\t\t\ttesselationControlStage = stage;\n\t\t\t\tbreak;\n\t\t\tcase TESSELATION_EVALUATE:\n\t\t\t\ttesselationEvaluationStage = stage;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn true;\n}\n\n#pragma endregion\n\n#pragma region constructors\n\nGShader::GShader() {};\nGShader::GShader(const ShaderSource& shaderSource) : Shader(shaderSource) {\n\tid = createShader(shaderSource);\n\n\tbool succes = true;\n\tsucces &= addShaderStage(shaderSource.vertexSource, VERTEX);\n\tsucces &= addShaderStage(shaderSource.fragmentSource, FRAGMENT);\n\tsucces &= addShaderStage(shaderSource.geometrySource, GEOMETRY);\n\tsucces &= addShaderStage(shaderSource.tesselationControlSource, TESSELATION_CONTROL);\n\tsucces &= addShaderStage(shaderSource.tesselationEvaluateSource, TESSELATION_EVALUATE);\n\n\tif (!succes) {\n\t\tLog::error(\"Error during shader stage initialization, closing shader\");\n\t\tclose();\n\t}\n};\n\nGShader::GShader(const std::string& name, const std::string& path, const std::string& vertexSource, const std::string& fragmentSource, const std::string& geometrySource, const std::string& tesselationControlSource, const std::string& tesselationEvaluateSource) : GShader(ShaderSource(name, path, vertexSource, fragmentSource, geometrySource, tesselationControlSource, tesselationEvaluateSource, \"\")) {}\n\nGShader::~GShader() {\n\tclose();\n}\n\nGShader::GShader(GShader&& other) {\n\tvertexStage = other.vertexStage;\n\tother.vertexStage = ShaderStage();\n\n\tfragmentStage = other.fragmentStage;\n\tother.fragmentStage = ShaderStage();\n\n\tgeometryStage = other.geometryStage;\n\tother.geometryStage = ShaderStage();\n\n\ttesselationControlStage = other.tesselationControlStage;\n\tother.tesselationControlStage = ShaderStage();\n\n\ttesselationEvaluationStage = other.tesselationEvaluationStage;\n\tother.tesselationEvaluationStage = ShaderStage();\n}\n\nGShader& GShader::operator=(GShader&& other) {\n\tif (this != &other) {\n\t\tclose();\n\t}\n\n\treturn *this;\n}\n\n#pragma endregion\n\n#pragma region bindable\n\nvoid GShader::close() {\n\tif (id != 0) {\n\t\tLog::subject s(name);\n\t\tunbind();\n\t\tLog::info(\"Closing shader\");\n\n\t\tglDeleteProgram(id);\n\t\tid = 0;\n\n\t\tLog::info(\"Closed shader\");\n\t}\n}\n\n#pragma endregion\n\n};"
  },
  {
    "path": "graphics/legacy/gshader.h",
    "content": "#pragma once\n\n#include \"shader.h\"\n\nnamespace P3D::Graphics {\n\nclass GShader : public Shader {\nprivate:\n\tGLID createShader(const ShaderSource& shaderSource);\n\nprotected:\n\tvirtual bool addShaderStage(const std::string& source, const ShaderFlag& flag) override;\n\npublic:\n\tShaderStage vertexStage;\n\tShaderStage fragmentStage;\n\tShaderStage geometryStage;\n\tShaderStage tesselationControlStage;\n\tShaderStage tesselationEvaluationStage;\n\n\tGShader();\n\tGShader(const ShaderSource& shaderSource);\n\tGShader(const std::string& name, const std::string& path, const std::string& vertexShader, const std::string& fragmentShader, const std::string& geometryShader, const std::string& tesselationControlSource, const std::string& tesselationEvaluateSource);\n\t\n\t~GShader();\n\tGShader(GShader&& other);\n\tGShader(const GShader&) = delete;\n\tGShader& operator=(GShader&& other);\n\tGShader& operator=(const GShader&) = delete;\n\n\tvoid reload(const ShaderSource& shaderSource);\n\n\tvoid close() override;\n};\n\nShaderSource parseShader(const std::string& name, const std::string& path, const std::string& vertexPath, const std::string& fragmentPath, const std::string& geometryPath = \"\", const std::string& tesselationControlPath = \"\", const std::string& tesselationEvaluatePath = \"\");\n\n};"
  },
  {
    "path": "graphics/legacy/image.cpp",
    "content": "#include \"core.h\"\n\n#include \"image.h\"\n\n#include \"texture.h\"\n#include \"guiUtils.h\"\n#include \"path/path.h\"\n#include \"mesh/primitive.h\"\n\n\nImage::Image(double x, double y, double width, double height) : Component(x, y, width, height) {\n\tVec2 dimension = GUI::unmap(Vec2(width, height));\n\tthis->texture = nullptr;\n\tthis->margin = GUI::margin;\n\tthis->padding = GUI::padding;\n\tthis->fixedWidth = true;\n\tthis->fixedHeight = true;\n}\n\nImage::Image(double x, double y, Texture* texture) : Component(x, y) {\n\tthis->texture = texture;\n\tthis->margin = GUI::margin;\n\tthis->padding = GUI::padding;\n\tthis->fixedWidth = false;\n\tthis->fixedHeight = false;\n};\n\nImage::Image(double x, double y, double width, double height, Texture* texture) : Component(x, y, width, height) {\n\tthis->texture = texture;\n\tthis->margin = GUI::margin;\n\tthis->padding = GUI::padding;\n\tthis->fixedWidth = true;\n\tthis->fixedHeight = true;\n}\n\nvoid Image::render() {\n\tif (!texture)\n\t\treturn;\n\n\tif (visible) {\n\t\tColor blendColor = (disabled) ? COLOR::DISABLED : COLOR::WHITE;\n\n\t\tif (texture)\n\t\t\tPath::rectUV(texture->getID(), position, dimension);\n\t\telse \n\t\t\tPath::rectFilled(position, dimension, 0, COLOR::blend(COLOR::BLACK, blendColor));\n\n\t\tPath::rect(position, dimension, 0.0f, COLOR::R);\n\t}\n}\n\nVec2 Image::resize() {\n\tif (!texture)\n\t\treturn dimension;\n\n\tif (resizing) {\n\t\tif (fixedWidth && fixedHeight)\n\t\t\treturn dimension;\n\n\t\tdimension -= Vec2(GUI::padding) * 2;\n\n\t\tif (fixedWidth) \n\t\t\tthis->height = this->width / texture->getAspect();\n\t\telse if (fixedHeight)\n\t\t\tthis->width = this->height * texture->getAspect();\n\t\telse\n\t\t\tdimension = Vec2(texture->getWidth(), texture->getHeight());\n\n\t\tdimension += Vec2(GUI::padding) * 2;\n\t}\n\n\treturn dimension;\n}\n\nImage* Image::fixHeight(float height) {\n\tfixedHeight = true;\n\tthis->height = height;\n\n\treturn this;\n}\n\nImage* Image::fixWidth(float width) {\n\tfixedWidth = true;\n\tthis->width = width;\n\n\treturn this;\n}"
  },
  {
    "path": "graphics/legacy/image.h",
    "content": "#pragma once\n\n#include \"component.h\"\n\nclass Texture;\n\nclass Image : public Component {\nprivate:\n\tbool fixedHeight;\n\tbool fixedWidth;\npublic:\n\tTexture* texture;\n\n\tImage(double x, double y, double width, double height);\n\tImage(double x, double y, Texture* texture);\n\tImage(double x, double y, double width, double height, Texture* texture);\n\t\n\tImage* fixHeight(float height);\n\tImage* fixWidth(float width);\n\n\tVec2 resize() override;\n\tvoid render() override;\n};"
  },
  {
    "path": "graphics/legacy/label.cpp",
    "content": "#include \"core.h\"\n\n#include \"label.h\"\n\n#include \"gui.h\"\n#include \"font.h\"\n#include \"path/path.h\"\n#include \"renderUtils.h\"\n#include \"mesh/primitive.h\"\n\nLabel::Label(std::string text, double x, double y) : Label(text, x, y, GUI::fontSize, GUI::fontColor) {};\n\nLabel::Label(std::string text, double x, double y, double size) : Label(text, x, y, size, GUI::fontColor) {};\n\nLabel::Label(std::string text, double x, double y, double size, Color color) : Label(text, x, y, size, color, GUI::font) {};\n\nLabel::Label(std::string text, double x, double y, double scale, Color color, Font* font) : Component(x, y) {\n\tthis->font = font;\n\tthis->text = text;\n\tthis->scale = scale;\n\tthis->padding = GUI::padding;\n\tthis->margin = GUI::margin;\n\tthis->foregroundColor = color;\n\tthis->backgroundColor = GUI::labelBackgroundColor;\n};\n\nvoid Label::render() {\n\tif (visible) {\n\n\t\tColor blendColor = (disabled) ? COLOR::DISABLED : COLOR::WHITE;\n\n\t\tresize();\n\t\t\n\t\tVec2 textPosition = position + Vec2(padding, -dimension.y + padding);\n\t\tPath::text(font, text, scale, textPosition, COLOR::blend(foregroundColor, blendColor));\n\n\t\tif (debug) {\n\t\t\tPath::rect(position, dimension, 0.0f, COLOR::R);\n\t\t\tPath::rect(position + Vec2f(padding, -padding), dimension - Vec2f(padding) * 2, 0.0f, COLOR::G);\n\t\t}\n\t}\n}\n\nVec2 Label::resize() {\n\tif (resizing) {\n\t\tVec2 fontDimension = font->size(text, scale);\n\t\tdimension = fontDimension + Vec2(padding) * 2;\n\t}\n\n\treturn dimension;\n}"
  },
  {
    "path": "graphics/legacy/label.h",
    "content": "#pragma once\n\n#include \"component.h\"\n\nclass Font;\n\nclass Label : public Component {\npublic:\n\tstd::string text;\n\tColor backgroundColor;\n\tColor foregroundColor;\n\tdouble scale;\n\tFont* font;\n\n\tLabel(std::string text, double x, double y);\n\tLabel(std::string text, double x, double y, double scale);\n\tLabel(std::string text, double x, double y, double scale, Color color);\n\tLabel(std::string text, double x, double y, double scale, Color color, Font* font);\n\n\tVec2 resize() override;\n\tvoid render() override;\n};"
  },
  {
    "path": "graphics/legacy/layout.cpp",
    "content": "#include \"core.h\"\n\n#include \"layout.h\"\n\n#include \"container.h\"\n\nnamespace P3D::Graphics {\n\nVec2 FlowLayout::resize(Container* container, Vec2 minDimension) {\n\t// Resulting width of the container\n\tdouble contentWidth = minDimension.x;\n\t// Resulting height of the container\n\tdouble contentHeight = minDimension.y;\n\t// Width of the current row of components\n\tdouble rowWidth = 0;\n\t// Height of the current row of components\n\tdouble rowHeight = 0;\n\n\t// Components to be centered\n\tstd::vector<Component*> centeredComponents;\n\n\tfor (int i = 0; i < container->children.size(); i++) {\n\t\tauto child = container->children[i];\n\t\tComponent* component = child.first;\n\t\tAlign alignment = child.second;\n\t\tVec2 componentSize = component->resize();\n\n\t\t// NO HEIGHT CHECK YET\n\t\tif (alignment == Align::FILL || alignment == Align::CENTER) {\n\t\t\t// Calculate new row width, component margin included\n\t\t\tdouble newRowWidth = rowWidth + component->margin + componentSize.x + component->margin;\n\t\t\tif (newRowWidth <= container->width || container->resizing) {\n\t\t\t\t// Set component position relative to parent with old rowWidth and contentHeight, component margin included\n\t\t\t\tcomponent->position = container->position + Vec2(rowWidth, -contentHeight) + Vec2(component->margin, -component->margin);\n\n\t\t\t\t// End of the current row, component keeps dimension\n\t\t\t\t// Update row width with calculated value\n\t\t\t\trowWidth = newRowWidth;\n\t\t\t\t// Update row height, component margin included\n\t\t\t\trowHeight = fmax(rowHeight, component->margin + componentSize.y + component->margin);\n\n\t\t\t\t// Resize the container so the component fits in\n\t\t\t\tcontentWidth = fmax(contentWidth, rowWidth);\n\n\t\t\t\t// Next line\n\t\t\t\tcontentHeight += rowHeight;\n\n\t\t\t\t// Reset row size\n\t\t\t\trowWidth = 0;\n\t\t\t\trowHeight = 0;\n\n\t\t\t\tif (alignment == Align::CENTER) {\n\t\t\t\t\tcenteredComponents.push_back(component);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// NO CHECK IF COMPONENT WIDTH IS GREATER THAN CONTENTWIDTH\n\t\t\t\t// Component does not fit in the current row, advance to the next row\n\t\t\t\tcontentHeight += rowHeight;\n\n\t\t\t\t// Set component position relative to parent, component margin included\n\t\t\t\tcomponent->position = container->position + Vec2(0, -contentHeight) + Vec2(component->margin, -component->margin);\n\n\t\t\t\t// Advance content height, component margin included\n\t\t\t\tcontentHeight += component->margin + componentSize.y + component->margin;\n\n\t\t\t\t// Reset row size\n\t\t\t\trowWidth = 0;\n\t\t\t\trowHeight = 0;\n\t\t\t}\n\t\t} else if (alignment == Align::RELATIVE) {\n\t\t\t// Calculate new row width, component margin included\n\t\t\tdouble newRowWidth = rowWidth + component->margin + componentSize.x + component->margin;\n\t\t\tif (newRowWidth <= container->width || container->resizing) {\n\t\t\t\t// Set component position relative to parent\n\t\t\t\tcomponent->position = container->position + Vec2(rowWidth, -contentHeight) + Vec2(component->margin, -component->margin);\n\n\t\t\t\t// Update row width with calculated value\n\t\t\t\trowWidth = newRowWidth;\n\t\t\t\t// Update row height, component margin included\n\t\t\t\trowHeight = fmax(rowHeight, component->margin + componentSize.y + component->margin);\n\n\t\t\t\t// Resize the container\n\t\t\t\tcontentWidth = fmax(contentWidth, rowWidth);\n\t\t\t} else {\n\t\t\t\t// Component does not fit in the current row, advance to the next row\n\t\t\t\tcontentHeight += rowHeight;\n\n\t\t\t\t// Set component position relative to parent\n\t\t\t\tcomponent->position = container->position + Vec2(0, -contentHeight) + Vec2(component->margin, -component->margin);\n\n\t\t\t\t// Set new row size\n\t\t\t\trowWidth = component->margin + componentSize.x + component->margin;\n\t\t\t\trowHeight = component->margin + componentSize.y + component->margin;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Center remaining components\n\tfor (Component* component : centeredComponents) {\n\t\t// Distance from component position to the end of the container minus the component margin\n\t\tdouble remainingWidth = container->x + contentWidth - component->x - component->margin;\n\t\t// Component width\n\t\tdouble componentWidth = component->width;\n\n\t\t// Move component to the center\n\t\tcomponent->x += (remainingWidth - componentWidth) / 2;\n\t}\n\n\t// Add height of last row\n\tcontentHeight += rowHeight;\n\n\tif (container->resizing) {\n\t\tcontainer->dimension = Vec2f(contentWidth, contentHeight);\n\t}\n\n\treturn container->dimension;\n}\n\n};"
  },
  {
    "path": "graphics/legacy/layout.h",
    "content": "#pragma once\n\nnamespace P3D::Graphics {\n\nclass Container;\n\nenum class Align {\n\tFILL,\n\tRELATIVE,\n\tCENTER\n};\n\nclass Layout {\npublic:\n\t// Positions the components of the given container (not including the padding of the container)\n\tvirtual Vec2 resize(Container* container, Vec2 minDimension = Vec2()) = 0;\n};\n\nclass FlowLayout : public Layout {\npublic:\n\tVec2 resize(Container* container, Vec2 minDimension = Vec2()) override;\n};\n\n};"
  },
  {
    "path": "graphics/legacy/panel.cpp",
    "content": "#include \"core.h\"\n\n#include \"panel.h\"\n\n#include \"gui.h\"\n#include \"layout.h\"\n#include \"path/path.h\"\n#include \"mesh/primitive.h\"\n#include \"../physics/math/mathUtil.h\"\n\nPanel::Panel(double x, double y) : Container(x, y) {\n\tthis->background = COLOR::BACK;\n\tthis->padding = GUI::padding;\n\tthis->margin = GUI::margin;\n};\n\nPanel::Panel(double x, double y, double width, double height) : Container(x, y, width, height) {\n\tthis->background = COLOR::BACK;\n\tthis->padding = GUI::padding;\n\tthis->margin = GUI::margin;\n};\n\nVec2 Panel::resize() {\n\tVec2 positionOffset = Vec2(padding, -padding);\n\tVec2 dimensionOffset = Vec2(2 * padding);\n\n\tposition += positionOffset;\n\tdimension -= dimensionOffset;\n\n\tdimension = layout->resize(this);\n\n\tposition -= positionOffset;\n\tdimension += dimensionOffset;\n\n\treturn dimension;\n}\n\nvoid Panel::render() {\n\tif (visible) {\n\n\t\tColor blendColor = (disabled) ? COLOR::DISABLED : COLOR::WHITE;\n\n\t\tresize();\n\n\t\tPath::rectFilled(position, dimension, 0, COLOR::blend(background, blendColor));\n\n\t\trenderChildren();\n\t}\n}\n"
  },
  {
    "path": "graphics/legacy/panel.h",
    "content": "#pragma once\n\n#include \"component.h\"\n#include \"container.h\"\n\nclass Panel : public Container {\npublic:\n\tColor background;\n\n\tPanel(double x, double y);\n\tPanel(double x, double y, double width, double height);\n\n\tVec2 resize() override;\n\tvoid render() override;\n};"
  },
  {
    "path": "graphics/legacy/shader.cpp",
    "content": "﻿#include \"core.h\"\n\n#include <GL/glew.h>\n\n#include \"shader.h\"\n#include \"renderer.h\"\n#include \"debug/guiDebug.h\"\n\n#include <fstream>\n#include <sstream>\n#include <future>\n\nnamespace P3D::Graphics {\n\n#pragma region uniforms\n\nint Shader::getUniform(const std::string& uniform) const {\n\tauto iterator = uniforms.find(uniform);\n\tif (iterator != uniforms.end())\n\t\treturn iterator->second;\n\n\treturn -1;\n}\n\nvoid Shader::addUniform(const std::string& uniform) {\n\tif (uniforms.find(uniform) == uniforms.end())\n\t\tcreateUniform(uniform);\n}\n\nvoid Shader::createUniform(const std::string& uniform) {\n\tbind();\n\tLog::subject s(name);\n\tint location = id != 0 ? glGetUniformLocation(id, uniform.c_str()) : -1;\n\n\tif (location < 0)\n\t\tLog::error(\"Could not find uniform (%s) in shader (%s)\", uniform.c_str(), name.c_str());\n\telse\n\t\tLog::debug(\"Created uniform (%s) in shader (%s) with id (%d)\", uniform.c_str(), name.c_str(), location);\n\n\tuniforms.insert({ uniform, location });\n}\n\nvoid Shader::setUniform(const std::string& uniform, GLID value) const {\n\tif (id == 0)\n\t\treturn;\n\t\n\tglUniform1i(uniforms.at(uniform), value);\n}\n\nvoid Shader::setUniform(const std::string& uniform, int value) const {\n\tif (id == 0)\n\t\treturn;\n\n\tglUniform1i(uniforms.at(uniform), value);\n}\n\nvoid Shader::setUniform(const std::string& uniform, float value) const {\n\tif (id == 0)\n\t\treturn;\n\n\tglUniform1f(uniforms.at(uniform), value);\n}\n\nvoid Shader::setUniform(const std::string& uniform, const Vec2f& value) const {\n\tif (id == 0)\n\t\treturn;\n\n\tglUniform2f(uniforms.at(uniform), value.x, value.y);\n}\n\nvoid Shader::setUniform(const std::string& uniform, const Vec3f& value) const {\n\tif (id == 0)\n\t\treturn;\n\n\tglUniform3f(uniforms.at(uniform), value.x, value.y, value.z);\n}\n\nvoid Shader::setUniform(const std::string& uniform, const Position& value) const {\n\tif (id == 0)\n\t\treturn;\n\n\tglUniform3f(uniforms.at(uniform), float(value.x), float(value.y), float(value.z));\n}\n\nvoid Shader::setUniform(const std::string& uniform, const Vec4f& value) const {\n\tif (id == 0)\n\t\treturn;\n\n\tglUniform4f(uniforms.at(uniform), value.x, value.y, value.z, value.w);\n}\n\nvoid Shader::setUniform(const std::string& uniform, const Mat2f& value) const {\n\tif (id == 0)\n\t\treturn;\n\n\tfloat buf[4];\n\tvalue.toColMajorData(buf);\n\tglUniformMatrix2fv(uniforms.at(uniform), 1, GL_FALSE, buf);\n}\n\nvoid Shader::setUniform(const std::string& uniform, const Mat3f& value) const {\n\tif (id == 0)\n\t\treturn;\n\n\tfloat buf[9];\n\tvalue.toColMajorData(buf);\n\tglUniformMatrix3fv(uniforms.at(uniform), 1, GL_FALSE, buf);\n}\n\nvoid Shader::setUniform(const std::string& uniform, const Mat4f& value) const {\n\tif (id == 0)\n\t\treturn;\n\n\tfloat buf[16];\n\tvalue.toColMajorData(buf);\n\tglUniformMatrix4fv(uniforms.at(uniform), 1, GL_FALSE, buf);\n}\n\n#pragma endregion\n\n#pragma region compile\n\nGLID Shader::compile(const std::string& name, const std::string& source, unsigned int type) {\n\tLog::setDelimiter(\"\");\n\tLog::info(\"%s: \", name.c_str());\n\n\tGLID id = glCreateShader(type);\n\n\tconst char* src = source.c_str();\n\n\tglShaderSource(id, 1, &src, NULL);\n\tglCall(glCompileShader(id));\n\n\tint result; glGetShaderiv(id, GL_COMPILE_STATUS, &result);\n\tif (result == GL_FALSE) {\n\t\tint length; glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);\n\t\tchar* message = (char*) alloca(length * sizeof(char)); \n\t\tglGetShaderInfoLog(id, length, &length, message);\n\t\t\n\t\tLog::print(Log::Color::ERROR, \"fail\\n\");\n\t\tLog::error(message);\n\n\t\tglDeleteShader(id);\n\t\tLog::setDelimiter(\"\\n\");\n\n\t\treturn 0;\n\t} else {\n\t\tLog::print(Log::Color::DEBUG, \"done\\n\");\n\t}\n\n\tLog::setDelimiter(\"\\n\");\n\n\treturn id;\n}\n\n#pragma endregion\n\n#pragma region parse\n\nShaderSource parseShader(const std::string& name, const std::string& path, const std::string& shaderText) {\n\tstd::istringstream shaderTextStream(shaderText);\n\treturn parseShader(name, path, shaderTextStream);\n}\n\nShaderSource parseShader(const std::string& name, const std::string& path) {\n\tstd::ifstream input;\n\tinput.open(path);\n\n\tif (input.is_open()) {\n\t\tstd::string line;\n\t\tstd::stringstream shaderTextStream;\n\t\twhile (getline(input, line))\n\t\t\tshaderTextStream << line << \"\\n\";\n\t\treturn parseShader(name, path, shaderTextStream);\n\t} else\n\t\treturn ShaderSource();\n}\n\nShaderSource parseShader(const std::string& name, const std::string& path, std::istream& shaderTextStream) {\n\tLog::subject s(name);\n\tLog::info(\"Reading (%s)\", name.c_str());\n\n\tenum class ShaderType {\n\t\tNONE = -1,\n\t\tCOMMON = 0,\n\t\tVERTEX = 1,\n\t\tFRAGMENT = 2,\n\t\tGEOMETRY = 3,\n\t\tTESSELATION_CONTROL = 4,\n\t\tTESSELATION_EVALUATE = 5,\n\t\tCOMPUTE = 6\n\t};\n\n\tShaderType type = ShaderType::NONE;\n\n\tstd::string line;\n\tstd::stringstream stringStream[7];\n\n\tint lineNumber = 0;\n\twhile (getline(shaderTextStream, line)) {\n\t\tlineNumber++;\n\t\tif (line == \"\\r\") {\n\t\t\tcontinue;\n\t\t} if (line.find(\"[vertex]\") != std::string::npos) {\n\t\t\ttype = ShaderType::VERTEX;\n\t\t} else if (line.find(\"[fragment]\") != std::string::npos) {\n\t\t\ttype = ShaderType::FRAGMENT;\n\t\t} else if (line.find(\"[geometry]\") != std::string::npos) {\n\t\t\ttype = ShaderType::GEOMETRY;\n\t\t} else if (line.find(\"[tesselation control]\") != std::string::npos) {\n\t\t\ttype = ShaderType::TESSELATION_CONTROL;\n\t\t} else if (line.find(\"[tesselation evaluate]\") != std::string::npos) {\n\t\t\ttype = ShaderType::TESSELATION_EVALUATE;\n\t\t} else if (line.find(\"[compute]\") != std::string::npos) {\n\t\t\ttype = ShaderType::COMPUTE;\n\t\t} else if (line.find(\"[common]\") != std::string::npos) {\n\t\t\ttype = ShaderType::COMMON;\n\t\t} else {\n\t\t\tif (type == ShaderType::NONE) {\n\t\t\t\tLog::warn(\"(line %d): code before the first #shader instruction will be ignored\", lineNumber);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tstringStream[(int) type] << line << \"\\n\";\n\t\t}\n\t}\n\n\tstd::string commonSource = stringStream[(int) ShaderType::COMMON].str();\n\tstd::string vertexSource = stringStream[(int) ShaderType::VERTEX].str();\n\tstd::string fragmentSource = stringStream[(int) ShaderType::FRAGMENT].str();\n\tstd::string geometrySource = stringStream[(int) ShaderType::GEOMETRY].str();\n\tstd::string tesselationControlSource = stringStream[(int) ShaderType::TESSELATION_CONTROL].str();\n\tstd::string tesselationEvaluateSource = stringStream[(int) ShaderType::TESSELATION_EVALUATE].str();\n\tstd::string computeSource = stringStream[(int) ShaderType::COMPUTE].str();\n\n\tLog::setDelimiter(\"\");\n\n\tif (!commonSource.empty()) {\n\t\tLog::info(\"Common file: \");\n\t\tLog::print(Log::Color::DEBUG, \"done\\n\");\n\t}\n\n\tif (!vertexSource.empty()) {\n\t\tLog::info(\"Vertex shader: \");\n\t\tLog::print(Log::Color::DEBUG, \"done\\n\");\n\t\tvertexSource = commonSource + vertexSource;\n\t}\n\n\tif (!fragmentSource.empty()) {\n\t\tLog::info(\"Fragment shader: \");\n\t\tLog::print(Log::Color::DEBUG, \"done\\n\");\n\t\tfragmentSource = commonSource + fragmentSource;\n\t}\n\n\tif (!geometrySource.empty()) {\n\t\tLog::info(\"Geometry shader: \");\n\t\tLog::print(Log::Color::DEBUG, \"done\\n\");\n\t\tgeometrySource = commonSource + geometrySource;\n\t}\n\n\tif (!tesselationControlSource.empty()) {\n\t\tLog::info(\"Tesselation control shader: \");\n\t\tLog::print(Log::Color::DEBUG, \"done\\n\");\n\t\ttesselationControlSource = commonSource + tesselationControlSource;\n\t}\n\n\tif (!tesselationEvaluateSource.empty()) {\n\t\tLog::info(\"Tesselation evaluation shader: \");\n\t\tLog::print(Log::Color::DEBUG, \"done\\n\");\n\t\ttesselationEvaluateSource = commonSource + tesselationEvaluateSource;\n\t}\n\n\tif (!computeSource.empty()) {\n\t\tLog::info(\"Tesselation evaluation shader: \");\n\t\tLog::print(Log::Color::DEBUG, \"done\\n\");\n\t\tcomputeSource = commonSource + computeSource;\n\t}\n\n\tLog::setDelimiter(\"\\n\");\n\n\treturn ShaderSource(name, path, vertexSource, fragmentSource, geometrySource, tesselationControlSource, tesselationEvaluateSource, computeSource);\n}\n\n#pragma endregion\n\n#pragma region constructors\n\nShaderSource::ShaderSource() = default;\nShaderSource::ShaderSource(const std::string& name, const std::string& path, const std::string& vertexSource, const std::string& fragmentSource, const std::string& geometrySource, const std::string& tesselationControlSource, const std::string& tesselationEvaluateSource, const std::string& computeSource) : name(name), path(path), vertexSource(vertexSource), fragmentSource(fragmentSource), geometrySource(geometrySource), tesselationControlSource(tesselationControlSource), tesselationEvaluateSource(tesselationEvaluateSource), computeSource(computeSource) {}\n\nShader::Shader() = default;\nShader::Shader(const ShaderSource& shaderSource) : name(shaderSource.name) {}\t\n\nShader::~Shader() {\n\tclose();\n}\n\nShader::Shader(Shader&& other) {\n\tid = other.id;\n\tother.id = 0;\n\n\tuniforms = other.uniforms;\n\tother.uniforms = std::unordered_map<std::string, int>();\n\n\tflags = other.flags;\n\tother.flags = NONE;\n\n\tname = other.name;\n\tother.name = std::string();\n}\n\nShader& Shader::operator=(Shader&& other) noexcept {\n\tif (this != &other) {\n\t\tclose();\n\t\tstd::swap(id, other.id);\n\t\tname = std::move(other.name);\n\t\tuniforms = std::move(other.uniforms);\n\t}\n\n\treturn *this;\n}\n\n#pragma endregion\n\n#pragma region bindable\n\nvoid Shader::bind() {\n\tRenderer::bindShader(id);\n}\n\nvoid Shader::unbind() {\n\tRenderer::bindShader(0);\n}\n\nvoid Shader::close() {\n\tif (id != 0) {\n\t\tLog::subject s(name);\n\t\tunbind();\n\t\tLog::info(\"Closing shader\");\n\n\t\tglDeleteProgram(id);\n\t\tid = 0;\n\n\t\tLog::info(\"Closed shader\");\n\t}\n}\n\n#pragma endregion\n\n#pragma region ShaderStage\n\nShaderStage::ShaderStage() = default;\nShaderStage::ShaderStage(const std::string& source) : source(source) {\n\tthis->info = Parser::parse(this->source.c_str());\n}\n\nstd::vector<std::string> getSuffixes(const ShaderStage& stage, const Parser::Local& local) {\n\tstd::vector<std::string> suffixes;\n\n\tauto strct = stage.info.structs.find(local.type.string(stage.source.c_str()));\n\tbool isStruct = strct != stage.info.structs.end();\n\tstd::string localName(local.name.view(stage.source.c_str()));\n\tif (local.amount != 0) {\n\t\tif (isStruct) { // struct array\n\t\t\tfor (int i = 0; i < local.amount; i++) {\n\t\t\t\tstd::string variable = localName + \"[\" + std::to_string(i) + \"].\";\n\n\t\t\t\tfor (const Parser::Local& local : strct->second.locals)\n\t\t\t\t\tfor (const std::string& localSuffix : getSuffixes(stage, local))\n\t\t\t\t\t\tsuffixes.push_back(variable + localSuffix);\n\t\t\t}\n\t\t} else { // normal array\n\t\t\tfor (int i = 0; i < local.amount; i++)\n\t\t\t\tsuffixes.push_back(localName + \"[\" + std::to_string(i) + \"]\");\n\t\t}\n\t} else {\n\t\tif (isStruct) {\n\t\t\tstd::string variable = localName + \".\";\n\n\t\t\tfor (const Parser::Local& local : strct->second.locals) \n\t\t\t\tfor (const std::string& localSuffix : getSuffixes(stage, local))\n\t\t\t\t\tsuffixes.push_back(variable + localSuffix);\n\t\t} else {\n\t\t\tsuffixes.push_back(localName);\n\t\t}\n\t}\n\n\treturn suffixes;\n}\n\nvoid Shader::addUniforms(const ShaderStage& stage) {\n\tfor (const Parser::Local& uniform : stage.info.uniforms) {\n\t\tstd::vector<std::string> variables = getSuffixes(stage, uniform);\n\n\t\tfor (const std::string& variable : variables)\n\t\t\taddUniform(variable);\n\t}\n}\n\n#pragma endregion\n\n};"
  },
  {
    "path": "graphics/legacy/shader.h",
    "content": "#pragma once\n\n#include \"../bindable.h\"\n#include \"parser.h\"\n\nnamespace P3D::Graphics {\n\nstruct ShaderStage {\n\tstd::string source;\n\tParser::Parse info;\n\n\tShaderStage();\n\tShaderStage(const std::string& source);\n};\n\nstruct ShaderSource {\n\tstd::string name;\n\tstd::string path;\n\n\tstd::string vertexSource;\n\tstd::string fragmentSource;\n\tstd::string geometrySource;\n\tstd::string tesselationControlSource;\n\tstd::string tesselationEvaluateSource;\n\tstd::string computeSource;\n\n\tShaderSource();\n\tShaderSource(const std::string& name, const std::string& path, const std::string& vertexSource, const std::string& fragmentSource, const std::string& geometrySource, const std::string& tesselationControlSource, const std::string& tesselationEvaluateSource, const std::string& computeSource);\n};\n\nclass Shader : public Bindable {\npublic:\n\tenum ShaderFlag : char {\n\t\tNONE = 0 << 0,\n\t\tVERTEX = 1 << 0,\n\t\tFRAGMENT = 1 << 1,\n\t\tGEOMETRY = 1 << 2,\n\t\tTESSELATION_CONTROL = 1 << 3,\n\t\tTESSELATION_EVALUATE = 1 << 4,\n\t\tCOMPUTE = 1 << 5\n\t};\n\n\tchar flags = NONE;\n\tstd::string name;\n\n\t~Shader();\n\tShader(const Shader&) = delete;\n\tShader& operator=(Shader&& other) noexcept;\n\tShader& operator=(const Shader&) = delete;\n\n\tstatic GLID compile(const std::string& name, const std::string& source, unsigned int type);\n\n\tint getUniform(const std::string& uniform) const;\n\tvoid createUniform(const std::string& uniform);\n\tvoid setUniform(const std::string& uniform, int value) const;\n\tvoid setUniform(const std::string& uniform, GLID value) const;\n\tvoid setUniform(const std::string& uniform, float value) const;\n\tvoid setUniform(const std::string& uniform, const Vec2f& value) const;\n\tvoid setUniform(const std::string& unfiorm, const Vec3f& value) const;\n\tvoid setUniform(const std::string& unfiorm, const Vec4f& value) const;\n\tvoid setUniform(const std::string& uniform, const Mat2f& value) const;\n\tvoid setUniform(const std::string& uniform, const Mat3f& value) const;\n\tvoid setUniform(const std::string& uniform, const Mat4f& value) const;\n\tvoid setUniform(const std::string& uniform, const Position& value) const;\n\n\tvoid bind() override;\n\tvoid unbind() override;\n\tvoid close() override;\n\nprotected:\n\tstd::unordered_map<std::string, int> uniforms;\n\n\tShader();\n\tShader(const ShaderSource& shaderSource);\n\tShader(Shader&& other);\n\n\tvoid addUniform(const std::string& uniform);\n\tvoid addUniforms(const ShaderStage& stage);\n\n\tvirtual bool addShaderStage(const std::string& source, const ShaderFlag& flag) = 0;\n};\n\nShaderSource parseShader(const std::string& name, const std::string& path);\nShaderSource parseShader(const std::string& name, const std::string& path, std::istream& shaderTextStream);\nShaderSource parseShader(const std::string& name, const std::string& path, const std::string& shaderText);\n};"
  },
  {
    "path": "graphics/legacy/shaderLexer.cpp",
    "content": "#include \"core.h\"\n\n#include \"shaderLexer.h\"\n#include \"../util/stringUtil.h\"\n\nnamespace P3D::Graphics {\n\nstd::vector<TokenType> ShaderLexer::types = {\n\tTokenType(TokenType::NONE, std::regex(\"(.*?)\")),\n\tTokenType(TokenType::COMMA, ','),\n\tTokenType(TokenType::EOL, ';'),\n\tTokenType(TokenType::RP, ')'),\n\tTokenType(TokenType::LP, '('),\n\tTokenType(TokenType::ASSIGN, '='),\n\tTokenType(TokenType::LC, '{'),\n\tTokenType(TokenType::RC, '}'),\n\tTokenType(TokenType::LB, '['),\n\tTokenType(TokenType::RB, ']'),\n\tTokenType(TokenType::DOT, '.'),\n\tTokenType(TokenType::IO, std::regex(\"in|out\")),\n\tTokenType(TokenType::LAYOUT, std::regex(\"layout\")),\n\tTokenType(TokenType::UNIFORM, std::regex(\"uniform\")),\n\tTokenType(TokenType::QUALIFIER, std::regex(\"const\")),\n\tTokenType(TokenType::STRUCT, std::regex(\"struct\")),\n\tTokenType(TokenType::VERSION, std::regex(\"#version\")),\n\tTokenType(TokenType::PREP, std::regex(\"#ifdef|#ifndef|#else|#endif|#define|#if|#undef\")),\n\tTokenType(TokenType::TYPE, std::regex(\"mat2|mat3|mat4|float|int|vec2|vec3|vec4|VS_OUT|sampler2D|void|sampler3D\")),\n\tTokenType(TokenType::ID, std::regex(\"[A-Za-z_]\\\\w*\")),\n\tTokenType(TokenType::OP, std::regex(\"&&?|\\\\|\\\\|?|\\\\+\\\\+?|--?|\\\\*\\\\*?|\\\\:|\\\\/\\\\/?|\\\\?|<=?|>=?\")),\n\tTokenType(TokenType::NUMBER, std::regex(\"^[-+]?[0-9]*\\\\.?[0-9]+([eE][-+]?[0-9]+)?\")),\n\tTokenType(TokenType::STRING, std::regex(\"\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"\")),\n\tTokenType(TokenType::SINGLECOMMENT, std::regex(\"\\\\/[\\\\/]+.*\")),\n\tTokenType(TokenType::MULTICOMMENT, std::regex(\"\\\\/\\\\*((?:.|[^\\\\*\\\\/])*)\\\\*\\\\/\"))\n};\n\nstd::string lexSingleComment(const std::string& input) {\n\tint index = 0;\n\twhile (input.length() != index && input.at(index) != '\\n')\n\t\tindex++;\n\n\treturn input.substr(0, index);\n}\n\nTokenType ShaderLexer::getMatch(const std::string& input) {\n\tTokenType match = ShaderLexer::types[0];\n\n\tfor (int i = 1; i < ShaderLexer::types.size(); i++) {\n\t\tif (types[i].accepting) {\n\t\t\tif (input.length() == 1 && input.at(0) == types[i].character)\n\t\t\t\treturn types[i];\n\t\t\telse\n\t\t\t\tcontinue;\n\t\t} else {\n\t\t\tif (std::regex_match(input, types[i].regex))\n\t\t\t\treturn types[i];\n\t\t}\n\t}\n\n\treturn match;\n}\n\nToken ShaderLexer::popToken(std::string& input, const TokenType& type, std::string value) {\n\t// Throw exception if the token is not recognized\n\tif (type == TokenType::NONE)\n\t\tLog::error(\"Type not recognized for value %s\", value.c_str());\n\n\t// removes the token from the input\n\tinput.erase(0, value.length());\n\n\t// removes all leading whitespaces from the input\n\tinput = Util::ltrim(input);\n\n\t// remove quotes from the value if the type is a string, regex or comment\n\tswitch (type) {\n\t\tcase TokenType::SINGLECOMMENT:\n\t\t\tvalue = value.substr(2, value.length());\n\t\t\tbreak;\n\t\tcase TokenType::MULTICOMMENT:\n\t\t\tvalue = value.substr(1, value.length() - 1);\n\t\tcase TokenType::STRING:\n\t\t\tvalue = value.substr(1, value.length() - 1);\n\t\t\tbreak;\n\t}\n\n\treturn Token(type, value);\n}\n\nToken ShaderLexer::nextToken(std::string& input) {\n\tstd::string currentToken;\n\n\tTokenType lastMatch = ShaderLexer::types[0];\n\tfor (int i = 0; i < input.length(); i++) {\n\t\tcurrentToken.push_back(input.at(i));\n\n\t\t// search for matches\n\t\tTokenType match = getMatch(currentToken);\n\n\t\t// No current match\n\t\tif (match == TokenType::NONE) {\n\t\t\t// Earlier match found\n\t\t\tif (lastMatch != TokenType::NONE) {\n\t\t\t\t// Remove last char\n\t\t\t\tcurrentToken.erase(currentToken.end() - 1);\n\t\t\t\t// break the loop\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t// else continue to search for a match\n\t\t} else if (match == TokenType::SINGLECOMMENT) {\n\t\t\treturn popToken(input, match, lexSingleComment(input));\n\t\t} else {\n\t\t\t// update last match\n\t\t\tlastMatch = match;\n\t\t}\n\t}\n\n\treturn popToken(input, lastMatch, currentToken);\n}\n\nTokenStack ShaderLexer::lexDebug(const std::string& input) {\n\tstd::function<std::vector<size_t>(const std::string&)> collect = [input] (const std::string& key) {\n\t\tstd::vector<size_t> list;\n\t\tsize_t lastIndex = 0;\n\t\twhile (true) {\n\t\t\tsize_t index = input.find(key, lastIndex);\n\t\t\tif (index == input.npos) {\n\t\t\t\tbreak;\n\t\t\t} else {\n\t\t\t\tlist.push_back(index);\n\t\t\t\tlastIndex = index + key.size();\n\t\t\t}\n\t\t}\n\t\treturn list;\n\t};\n\n\tstd::function<std::pair<size_t, size_t>(size_t, bool)> next = [input] (size_t offset, bool allowEnter) {\n\t\tsize_t start = offset;\n\t\tsize_t index = offset;\n\t\twhile (true) {\n\t\t\tconst char& c = input[index];\n\t\t\tif (c == ' ' || c == '\\t' || c == '\\r' || c == ';' || c == '\\n' || c == '[') {\n\t\t\t\tif (start == index) {\n\t\t\t\t\tif (!allowEnter && c == '\\n')\n\t\t\t\t\t\treturn std::make_pair(size_t(0), size_t(0));\n\t\t\t\t\telse\n\t\t\t\t\t\tstart++;\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tindex++;\n\t\t}\n\t\treturn std::make_pair(start, index);\n\t};\n\n\tstd::function<size_t(char, char, size_t)> until = [input] (char l, char r, size_t offset) {\n\t\tint depth = -1;\n\t\tsize_t index = offset;\n\t\tsize_t size = input.length();\n\t\twhile (index < size) {\n\t\t\tconst char& c = input[index];\n\t\t\tif (c == l) {\n\t\t\t\tdepth++;\n\t\t\t} else if (c == r) {\n\t\t\t\tif (depth == 0)\n\t\t\t\t\tbreak;\n\t\t\t\telse if (depth > 0)\n\t\t\t\t\tdepth--;\n\t\t\t}\n\t\t\tindex++;\n\t\t}\n\t\treturn index;\n\t};\n\n\tTokenStack tokens;\n\tstd::vector<size_t> defines = collect(\"#define \");\n\tstd::vector<size_t> uniforms = collect(\"uniform \");\n\tstd::vector<size_t> structs = collect(\"struct \");\n\n\tfor (size_t index : defines) {\n\t\ttokens.add(Token(TokenType(TokenType::PREP, 0), \"#define\"));\n\t\tindex += 7; // length(\"#define \")\n\n\t\tauto [n1, n2] = next(index, false);\n\t\tstd::string name = input.substr(n1, n2 - n1);\n\t\ttokens.add(Token(TokenType(TokenType::ID, 0), name));\n\t\tindex = n2;\n\n\t\tauto [n3, n4] = next(index, false);\n\t\tstd::string value = input.substr(n3, n4 - n3);\n\t\tif (!value.empty())\n\t\t\ttokens.add(Token(TokenType(TokenType::NUMBER, 0), value));\n\t}\n\n\tfor (size_t index : structs) {\n\t\ttokens.add(Token(TokenType(TokenType::STRUCT, 0), \"struct\"));\n\t\tindex += 6; // length(\"uniform \")\n\n\t\tsize_t end = until('{', '}', index);\n\t\tstd::string content = input.substr(index, end - index + 1);\n\t\tTokenStack strct = lex(content);\n\t\ttokens.addAll(strct);\n\n\t\ttokens.add(Token(TokenType(TokenType::EOL, 0), \"\"));\n\t}\n\n\tfor (size_t index : uniforms) {\n\t\ttokens.add(Token(TokenType(TokenType::UNIFORM, 0), \"uniform\"));\n\t\tindex += 7; // length(\"uniform \")\n\n\t\tauto [n1, n2] = next(index, true);\n\t\tstd::string type = input.substr(n1, n2 - n1);\n\t\ttokens.add(Token(TokenType(TokenType::TYPE, 0), type));\n\t\tindex = n2;\n\n\t\tauto [n3, n4] = next(index, true);\n\t\tstd::string name = input.substr(n3, n4 - n3);\n\t\ttokens.add(Token(TokenType(TokenType::ID, 0), name));\n\t\tindex = n4;\n\n\t\tauto [n5, n6] = next(index, true);\n\t\tstd::string array = input.substr(n5 - 1, n6 - n5 + 1);\n\t\tif (!array.empty() && Util::startsWith(array, \"[\") && Util::endsWith(array, \"]\")) {\n\t\t\tTokenStack content = lex(array);\n\t\t\ttokens.addAll(content);\n\t\t}\n\n\t\ttokens.add(Token(TokenType(TokenType::EOL, 0), \"\"));\n\t}\n\n\ttokens.flip();\n\n\treturn tokens;\n}\n\nTokenStack ShaderLexer::lex(const std::string& input) {\n\tTokenStack tokens;\n\n\tstd::string code = Util::trim(input);\n\n\twhile (code.length() != 0) {\n\t\tToken token = nextToken(code);\n\n\t\tif (token.type == TokenType::SINGLECOMMENT || token.type == TokenType::MULTICOMMENT)\n\t\t\tcontinue;\n\n\t\ttokens.add(token);\n\t}\n\n\ttokens.flip();\n\n\treturn tokens;\n}\n\nToken TokenStack::peek(size_t offset) const {\n\tif (read)\n\t\tif (available(offset))\n\t\t\treturn *(iterator + offset);\n\n\treturn Token(ShaderLexer::types[0], \"\");\n}\n\nToken TokenStack::pop() {\n\tif (read)\n\t\tif (available())\n\t\t\treturn *iterator++;\n\n\treturn Token(ShaderLexer::types[0], \"\");\n}\n\nvoid TokenStack::discard() {\n\tif (read)\n\t\tif (available())\n\t\t\titerator++;\n}\n\nvoid TokenStack::add(const Token& token) {\n\tif (!read)\n\t\tstack.push_back(token);\n}\n\nvoid TokenStack::addAll(const TokenStack& tokens) {\n\tint index = 0;\n\twhile (tokens.available(index))\n\t\tadd(tokens.peek(index++));\n}\n\nvoid TokenStack::flip() {\n\tread = !read;\n\n\tif (read)\n\t\titerator = stack.begin();\n}\n\nTokenStack TokenStack::until(const TokenType::Type& type, bool popType) {\n\tTokenStack content;\n\n\tif (read) {\n\t\twhile (available()) {\n\t\t\tif (iterator->type == type)\n\t\t\t\tbreak;\n\n\t\t\tcontent.add(*iterator++);\n\t\t}\n\n\t\tif (popType)\n\t\t\tdiscard();\n\t}\n\n\tcontent.flip();\n\n\treturn content;\n}\n\nbool TokenStack::available(size_t offset) const {\n\tif (read)\n\t\treturn iterator + offset < stack.end();\n\n\treturn false;\n}\n\nsize_t TokenStack::size() const {\n\treturn stack.size();\n}\n\n};"
  },
  {
    "path": "graphics/legacy/shaderLexer.h",
    "content": "#pragma once\n\n#include \"../util/stringUtil.h\"\n#include <regex>\n\nnamespace P3D::Graphics {\n\nstruct TokenType {\n\n\tenum Type : char {\n\t\tNONE,\n\t\tID,\n\t\tOP,\n\t\tCOMMA,\n\t\tDOT,\n\t\tASSIGN,\n\t\tNUMBER,\n\t\tVERSION,\n\t\tPREP,\n\t\tSTRING,\n\t\tSINGLECOMMENT,\n\t\tMULTICOMMENT,\n\t\tLP,\n\t\tRP,\n\t\tLB,\n\t\tRB,\n\t\tLC,\n\t\tRC,\n\t\tEOL,\n\t\tIO,\n\t\tSTRUCT,\n\t\tLAYOUT,\n\t\tLOCATION,\n\t\tQUALIFIER,\n\t\tUNIFORM,\n\t\tTYPE,\n\t};\n\npublic:\n\tType type;\n\tstd::regex regex;\n\tchar character;\n\tbool accepting;\n\n\tTokenType(Type type, std::regex regex) : type(type), regex(regex), character(), accepting(false) {}\n\tTokenType(Type type, char character) : type(type), character(character), accepting(true) {}\n\n\toperator Type() const { return type; }\n\tbool operator==(Type other) const { return type == other; }\n\tbool operator==(TokenType other) const { return type == other.type; }\n\tbool operator!=(Type other) const { return type != other; }\n\tbool operator!=(TokenType other) const { return type != other.type; }\n};\n\nstruct Token {\n\tTokenType type;\n\tstd::string value;\n\n\tToken(const TokenType& type, const std::string& value) : type(type), value(value) {}\n};\n\nstruct TokenStack {\nprivate:\n\tbool read = false;\n\n\tstd::vector<Token> stack;\n\tstd::vector<Token>::iterator iterator;\npublic:\n\tvoid add(const Token& token);\n\tvoid addAll(const TokenStack& tokens);\n\n\tvoid flip();\n\n\tTokenStack until(const TokenType::Type& type, bool popType = true);\n\tToken peek(size_t offset = 0) const;\n\tToken pop();\n\tvoid discard();\n\tbool available(size_t offset = 0) const;\n\tsize_t size() const;\n};\n\nclass ShaderLexer {\n\tfriend TokenStack;\nprivate:\n\tstatic std::vector<TokenType> types;\n\n\tstatic Token nextToken(std::string& input);\n\tstatic TokenType getMatch(const std::string& input);\n\tstatic Token popToken(std::string& input, const TokenType& type, std::string value);\n\npublic:\n\tstatic TokenStack lex(const std::string& input);\n\tstatic TokenStack lexDebug(const std::string& input);\n};\n\n};"
  },
  {
    "path": "graphics/legacy/shaderParser.cpp",
    "content": "#include \"core.h\"\n\n#include \"shaderParser.h\"\n\nnamespace P3D::Graphics {\n\nstd::map<std::string, ShaderVariableType> variableTypeMap = {\n\t{ \"void\", ShaderVariableType::VOID },\n\t{ \"int\", ShaderVariableType::INT },\n\t{ \"float\", ShaderVariableType::FLOAT },\n\t{ \"mat2\", ShaderVariableType::MAT2 },\n\t{ \"mat3\", ShaderVariableType::MAT3 },\n\t{ \"mat4\", ShaderVariableType::MAT4 },\n\t{ \"vec2\", ShaderVariableType::VEC2 },\n\t{ \"vec3\", ShaderVariableType::VEC3 },\n\t{ \"vec4\", ShaderVariableType::VEC4 },\n\t{ \"sampler2D\", ShaderVariableType::SAMPLER2D },\n\t{ \"sampler3D\", ShaderVariableType::SAMPLER3D },\n\t{ \"struct\", ShaderVariableType::STRUCT },\n\t{ \"VS_OUT\", ShaderVariableType::VS_OUT },\n};\n\nShaderLocal parseLocal(TokenStack& tokens, const ShaderDefines& defines);\n\nShaderVariableType ShaderParser::parseVariableType(const std::string& value) {\n\tauto iterator = variableTypeMap.find(value);\n\tif (iterator != variableTypeMap.end())\n\t\treturn iterator->second;\n\n\treturn ShaderVariableType::NONE;\n}\n\nShaderIOType parseIOType(const Token& token) {\n\tstd::string value = token.value;\n\n\tif (value == \"in\")\n\t\treturn ShaderIOType::IN;\n\tif (value == \"out\")\n\t\treturn ShaderIOType::OUT;\n\n\treturn ShaderIOType::NONE;\n}\n\nTokenStack nextScope(TokenStack& tokens, const TokenType::Type& ltype, const TokenType::Type& rtype) {\n\tint depth = -1;\n\tTokenStack scope;\n\twhile (tokens.available()) {\n\t\tToken token = tokens.pop();\n\n\t\tif (token.type == ltype) {\n\t\t\tif (++depth == 0)\n\t\t\t\tcontinue;\n\t\t} else if (token.type == rtype) {\n\t\t\tif (depth == 0)\n\t\t\t\tbreak;\n\t\t\telse if (depth > 0)\n\t\t\t\tdepth--;\n\t\t}\n\n\t\tscope.add(token);\n\t}\n\n\tscope.flip();\n\treturn scope;\n}\n\nbool testFunction(TokenStack& tokens) {\n\tif (ShaderParser::parseVariableType(tokens.peek().value) == ShaderVariableType::VOID)\n\t\treturn true;\n\n\tif (tokens.peek(1).type == TokenType::ID)\n\t\tif (tokens.peek(2).type == TokenType::LP)\n\t\t\treturn true;\n\n\treturn false;\n}\n\nint parseArray(TokenStack& tokens, const ShaderDefines& defines) {\n\tif (tokens.peek().type == TokenType::LB) {\n\t\ttokens.discard();\n\t\tToken next = tokens.pop();\n\t\tswitch (next.type) {\n\t\t\tcase TokenType::NUMBER: {\n\t\t\t\treturn std::stoi(next.value);\n\t\t\t\tbreak;\n\t\t\t} case TokenType::ID: {\n\t\t\t\tif (defines.find(next.value) != defines.end())\n\t\t\t\t\treturn int (defines.at(next.value));\n\t\t\t} case TokenType::RB: {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn -1;\n}\n\nShaderLocals parseStructContent(TokenStack& scope, const ShaderStructs& structs, const ShaderDefines& defines) {\n\tShaderLocals locals;\n\n\twhile (scope.available()) {\n\t\tconst Token& token = scope.peek();\n\t\tswitch (token.type) {\n\t\t\tcase TokenType::TYPE: {\n\t\t\t\tShaderLocal local = parseLocal(scope, defines);\n\t\t\t\tlocals.push_back(local);\n\t\t\t\tbreak;\n\t\t\t} case TokenType::ID: {\n\t\t\t\tif (structs.find(token.value) != structs.end()) {\n\t\t\t\t\tShaderLocal local = parseLocal(scope, defines);\n\t\t\t\t\tlocals.push_back(local);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t} default: {\n\t\t\t\tscope.discard();\n\t\t\t}\n\t\t}\n\t}\n\n\treturn locals;\n}\n\nShaderStruct parseStruct(TokenStack& tokens, const ShaderStructs& structs, const ShaderDefines& defines) {\n\ttokens.discard(); // pop STRUCT\n\n\tstd::string name = tokens.pop().value;\n\tTokenStack scope = nextScope(tokens, TokenType::LC, TokenType::RC);\n\tShaderLocals locals = parseStructContent(scope, structs, defines);\n\n\treturn ShaderStruct(name, locals);\n}\n\nShaderUniform parseUniform(TokenStack& tokens, const ShaderDefines& defines) {\n\ttokens.discard(); // pop UNIFORM\n\n\tstd::string variableType = tokens.pop().value;\n\tstd::string name = tokens.pop().value;\n\tint amount = parseArray(tokens, defines);\n\ttokens.until(TokenType::EOL);\n\n\treturn ShaderUniform(name, variableType, amount != -1, amount);\n}\n\nShaderVSOUT parseVSOUT(TokenStack& tokens, const std::string& ioType, const ShaderDefines& defines) {\n\tTokenStack scope = nextScope(tokens, TokenType::LC, TokenType::RC);\n\tShaderLocals locals = parseStructContent(scope, ShaderStructs(), defines);\n\tstd::string name = tokens.pop().value;\n\tint amount = parseArray(tokens, defines);\n\n\treturn ShaderVSOUT(name, ioType, \"VS_OUT\", amount != -1, amount, locals);\n}\n\nShaderLocal parseLocal(TokenStack& tokens, const ShaderDefines& defines) {\n\tstd::string variableType = tokens.pop().value;\n\tstd::string name = tokens.pop().value;\n\tint amount = parseArray(tokens, defines);\n\n\treturn ShaderLocal(name, variableType, amount != -1, amount);\n}\n\nShaderGlobal parseGlobal(TokenStack& tokens, const ShaderDefines& defines) {\n\tstd::string ioType = tokens.pop().value;\n\tstd::string variableType = tokens.pop().value;\n\n\tswitch (ShaderParser::parseVariableType(variableType)) {\n\t\tcase ShaderVariableType::VS_OUT: {\n\t\t\tShaderVSOUT vsout = parseVSOUT(tokens, ioType, defines);\n\t\t\treturn vsout;\n\t\t\tbreak;\n\t\t} default: {\n\t\t\tstd::string name = tokens.pop().value;\n\t\t\tint amount = parseArray(tokens, defines);\n\n\t\t\treturn ShaderGlobal(name, ioType, variableType, amount != -1, amount);\n\t\t\tbreak; \n\t\t}\n\t}\n}\n\nShaderLayoutItem parseLayoutItem(TokenStack& tokens) {\n\ttokens.discard();\n\n\tTokenStack scope = nextScope(tokens, TokenType::LP, TokenType::RP);\n\n\tShaderLayoutAttributes attributes;\n\twhile (scope.available()) {\n\t\tTokenStack setting = scope.until(TokenType::COMMA);\n\t\tstd::string attribute = setting.pop().value;\n\t\tstd::string value = (setting.peek().type == TokenType::ASSIGN) ? setting.pop().value : \"\";\n\t\t\n\t\tattributes.push_back(ShaderLayoutAttribute(attribute, value));\n\t}\n\n\tstd::string ioType = tokens.pop().value;\n\tstd::string variableType = \"\";\n\tstd::string name = \"\";\n\tif (tokens.peek().type == TokenType::TYPE) {\n\t\tvariableType = tokens.pop().value;\n\t\tname = tokens.pop().value;\n\t}\n\n\treturn ShaderLayoutItem(attributes, ioType, variableType, name);\n}\n\nvoid parseDefine(TokenStack& tokens, ShaderDefines& defines) {\n\tstd::string name = tokens.pop().value;\n\tfloat value = 1;\n\n\tif (tokens.peek().type == TokenType::NUMBER) {\n\t\ttry {\n\t\t\tvalue = std::stof(tokens.pop().value);\n\t\t} catch (...) {\n\t\t\treturn;\n\t\t}\n\n\t\tdefines[name] = value;\n\t}\n}\n\nvoid parseUnDef(TokenStack& tokens, ShaderDefines& defines) {\n\tstd::string name = tokens.pop().value;\n\tauto iterator = defines.find(name);\n\tif (iterator != defines.end())\n\t\tdefines.erase(iterator);\n}\n\nbool parseIf(TokenStack& tokens, ShaderDefines& defines) {\n\tToken token = tokens.pop();\n\n\tswitch (token.type) {\n\t\tcase TokenType::NUMBER: {\n\t\t\treturn std::stof(token.value);\n\t\t\tbreak;\n\t\t} case TokenType::ID: {\n\t\t\tif (defines.find(token.value) != defines.end())\n\t\t\t\treturn defines.at(token.value);\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn false;\n}\n\nbool parseIfDef(TokenStack& tokens, ShaderDefines& defines) {\n\tToken token = tokens.pop();\n\n\tif (defines.find(token.value) != defines.end())\n\t\treturn true;\n\n\treturn false;\n}\n\nbool parseIfNDef(TokenStack& tokens, ShaderDefines& defines) {\n\treturn !parseIfDef(tokens, defines);\n}\n\nvoid parseIfBody() {\n\n}\n\nShaderVersion parseVersion(TokenStack& tokens) {\n\tShaderVersion version;\n\t\n\ttokens.discard();\n\n\tif (tokens.peek().type == TokenType::NUMBER) {\n\t\tversion.version = std::stoi(tokens.pop().value);\n\t\tversion.version = std::clamp(version.version, 300, 450); // Todo check correctness\n\n\t\tif (tokens.peek().type == TokenType::ID && tokens.peek().value == \"core\") {\n\t\t\tversion.core = true;\n\t\t\ttokens.pop();\n\t\t}\n\t}\n\n\treturn version;\n}\n\nvoid parsePreprocessor(TokenStack& tokens, ShaderDefines& defines) {\n\tstd::string preprocessor = tokens.pop().value;\n\n\tif (preprocessor == \"#define\") {\n\t\tparseDefine(tokens, defines);\n\t} else if (preprocessor == \"#if\") {\n\t\tbool result = parseIf(tokens, defines);\n\t} else if (preprocessor == \"#ifdef\") {\n\t\tbool result = parseIfDef(tokens, defines);\n\t} else if (preprocessor == \"#ifndef\") {\n\t\tbool result = parseIfNDef(tokens, defines);\n\t} else if (preprocessor == \"#undef\") {\n\t\tparseUnDef(tokens, defines);\n\t}\n}\n\nShaderInfo ShaderParser::parse(const std::string& code) {\n#ifdef NDEBUG // RELEASE\n\tTokenStack tokens = ShaderLexer::lex(code);\n#else\n\tTokenStack tokens = ShaderLexer::lexDebug(code);\n#endif // NDEBUG\n\treturn parseTokens(tokens);\n}\n\nShaderInfo ShaderParser::parseTokens(TokenStack& tokens) {\n\tShaderVersion version;\n\tShaderLayout layout;\n\tShaderUniforms uniforms;\n\tShaderGlobals globals;\n\tShaderLocals locals;\n\tShaderDefines defines;\n\tShaderStructs structs;\n\n\twhile (tokens.available()) {\n\t\tconst Token& token = tokens.peek();\n\t\tswitch (token.type) {\n\t\t\tcase TokenType::UNIFORM: {\n\t\t\t\tShaderUniform uniform = parseUniform(tokens, defines);\n\t\t\t\tuniforms.push_back(uniform);\n\t\t\t\tbreak; \n\t\t\t} case TokenType::IO: {\n\t\t\t\tShaderGlobal global = parseGlobal(tokens, defines);\n\n\t\t\t\tglobals.push_back(global);\n\t\t\t\tbreak;\n\t\t\t} case TokenType::TYPE: {\n\t\t\t\tif (testFunction(tokens)) {\n\t\t\t\t\tnextScope(tokens, TokenType::LC, TokenType::RC);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tShaderLocal local = parseLocal(tokens, defines);\n\t\t\t\tlocals.push_back(local);\n\t\t\t\tbreak;\n\t\t\t}  case TokenType::LAYOUT: {\n\t\t\t\tShaderLayoutItem layoutItem = parseLayoutItem(tokens);\n\t\t\t\tlayout.push_back(layoutItem);\n\t\t\t\tbreak;\n\t\t\t} case TokenType::VERSION: {\n\t\t\t\tversion = parseVersion(tokens);\n\t\t\t\tbreak;\n\t\t\t} case TokenType::PREP: {\n\t\t\t\tparsePreprocessor(tokens, defines);\n\t\t\t\tbreak;\n\t\t\t} case TokenType::STRUCT: {\n\t\t\t\tShaderStruct strct = parseStruct(tokens, structs, defines);\n\t\t\t\tstructs[strct.name] = strct;\n\t\t\t\tbreak;\n\t\t\t} case TokenType::ID: {\n\t\t\t\tif (structs.find(token.value) != structs.end()) {\n\t\t\t\t\tShaderLocal local = parseLocal(tokens, defines);\n\t\t\t\t\tlocals.push_back(local);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t} default: {\n\t\t\t\ttokens.discard();\n\t\t\t}\n\t\t}\n\t}\n\n\treturn ShaderInfo(version, layout, uniforms, globals, locals, defines, structs);\n}\n\n};"
  },
  {
    "path": "graphics/legacy/shaderParser.h",
    "content": "#pragma once\n\n#include <stack>\n#include \"shaderLexer.h\"\n\nnamespace P3D::Graphics {\n\nenum class ShaderVariableType {\n\tNONE,\n\tVOID,\n\tINT,\n\tFLOAT,\n\tVEC2,\n\tVEC3,\n\tVEC4,\n\tMAT2,\n\tMAT3,\n\tMAT4,\n\tSTRUCT,\n\tVS_OUT,\n\tSAMPLER2D,\n\tSAMPLER3D\n};\n\nenum class ShaderIOType {\n\tNONE,\n\tIN,\n\tOUT\n};\n\nstruct ShaderLocal {\n\tstd::string name;\n\tstd::string variableType;\n\tbool array;\n\tint amount;\n\n\tShaderLocal(const std::string& name, const std::string& variableType, bool array, int amount) : name(name), variableType(variableType), array(array), amount(amount) {}\n};\ntypedef std::vector<ShaderLocal> ShaderLocals;\n\nstruct ShaderGlobal {\n\tstd::string name;\n\tstd::string ioType;\n\tstd::string variableType;\n\tbool array;\n\tint amount;\n\n\tShaderGlobal(const std::string& name, const std::string& ioType, const std::string& variableType, bool array, int amount) : name(name), ioType(ioType), variableType(variableType), array(array), amount(amount) {};\n};\ntypedef std::vector<ShaderGlobal> ShaderGlobals;\n\nstruct ShaderLayoutAttribute {\n\tstd::string attribute;\n\tstd::string value;\n\n\tShaderLayoutAttribute(const std::string& attribute, const std::string& value) : attribute(attribute), value(value) {}\n};\ntypedef std::vector<ShaderLayoutAttribute> ShaderLayoutAttributes;\n\nstruct ShaderLayoutItem {\n\tShaderLayoutAttributes attributes;\n\tstd::string ioType;\n\tstd::string variableType;\n\tstd::string name;\n\n\tShaderLayoutItem(const ShaderLayoutAttributes& attributes, const std::string& ioType, const std::string& variableType, const std::string& name) : attributes(attributes), ioType(ioType), variableType(variableType), name(name) {}\n};\ntypedef std::vector<ShaderLayoutItem> ShaderLayout;\n\nstruct ShaderVSOUT : public ShaderGlobal {\n\tShaderLocals locals;\n\n\tShaderVSOUT(const std::string& name, const std::string& ioType, const std::string& variableType, bool array, int amount, const ShaderLocals& locals) : ShaderGlobal(name, ioType, variableType, array, amount), locals(locals) {}\n};\n\nstruct ShaderVersion {\n\tint version;\n\tbool core;\n};\n\t\nstruct ShaderStruct {\n\tstd::string name;\n\tShaderLocals locals;\n\n\tShaderStruct() {};\n\tShaderStruct(const std::string& name, const ShaderLocals& locals) : name(name), locals(locals) {}\n};\ntypedef std::unordered_map<std::string, ShaderStruct> ShaderStructs;\n\ntypedef ShaderLocal ShaderUniform;\ntypedef std::vector<ShaderUniform> ShaderUniforms;\ntypedef std::unordered_map<std::string, float> ShaderDefines;\n\nstruct ShaderInfo {\n\tShaderVersion version;\n\tShaderLayout layout;\n\tShaderUniforms uniforms;\n\tShaderGlobals globals;\n\tShaderLocals locals;\n\tShaderDefines defines;\n\tShaderStructs structs;\n\n\tShaderInfo() {}\n\tShaderInfo(const ShaderVersion& version, const ShaderLayout& layout, const ShaderUniforms& uniforms, const ShaderGlobals& globals, const ShaderLocals& locals, const ShaderDefines& defines, const ShaderStructs& structs) : version(version), layout(layout), uniforms(uniforms), globals(globals), locals(locals), defines(defines), structs(structs) {}\n};\n\nclass ShaderParser {\npublic:\n\tstatic ShaderVariableType parseVariableType(const std::string& value);\n\tstatic ShaderInfo parse(const std::string& code);\n\tstatic ShaderInfo parseTokens(TokenStack& tokens);\n};\n\n};"
  },
  {
    "path": "graphics/legacy/slider.cpp",
    "content": "#include \"core.h\"\n\n#include \"slider.h\"\n\n#include \"path/path.h\"\n#include \"renderUtils.h\"\n#include \"mesh/primitive.h\"\n\nSlider::Slider(double x, double y) : Slider(x, y, 0, 1, 0) {}\n\nSlider::Slider(double x, double y, double width, double height) : Slider(x, y, width, height, 0, 1, 0) {}\n\nSlider::Slider(double x, double y, double min, double max, double value) : Component(x, y) {\n\tthis->min = min;\n\tthis->max = max;\n\tthis->value = value;\n\n\tthis->handleColor = GUI::sliderHandleColor;\n\tthis->backgroundColor = GUI::sliderBackgroundColor;\n\tthis->foregroundFilledColor = GUI::sliderForegroundFilledColor;\n\tthis->foregroundEmptyColor = GUI::sliderForegroundEmptyColor;\n\n\n\tthis->handleWidth = GUI::sliderHandleWidth;\n\tthis->handleHeight = GUI::sliderHandleHeight;\n\tthis->barWidth = GUI::sliderBarWidth;\n\tthis->barHeight = GUI::sliderBarHeight;\n}\n\n\nSlider::Slider(double x, double y, double width, double height, double min, double max, double value) : Component(x, y, width, height) {\n\tthis->min = min;\n\tthis->max = max;\n\tthis->value = value;\n\n\thandleColor = GUI::sliderHandleColor;\n\tbackgroundColor = GUI::sliderBackgroundColor;\n\tforegroundFilledColor = GUI::sliderForegroundFilledColor;\n\tforegroundEmptyColor = GUI::sliderForegroundEmptyColor;\n\n\tthis->padding = GUI::padding;\n\tthis->margin = GUI::margin;\n\n\thandleWidth = GUI::sliderHandleWidth;\n\thandleHeight = height - 2 * padding;\n\tbarWidth = width - 2 * padding - handleWidth;\n\tbarHeight = GUI::sliderBarHeight;\n}\n\nvoid Slider::render() {\n\tif (visible) {\n\n\t\tColor blendColor = (disabled) ? COLOR::DISABLED : COLOR::WHITE;\n\n\t\tresize();\n\n\t\tPath::rectFilled(position, dimension, 0.0f, COLOR::blend(backgroundColor, blendColor));\n\t\t\n\t\tdouble progress = (value - min) / (max - min);\n\t\tVec2 sliderFilledPosition = position + Vec2(padding + handleWidth / 2, -height / 2 + barHeight / 2);\n\t\tVec2 sliderFilledDimension = Vec2(barWidth * progress, barHeight);\n\t\tPath::rectFilled(sliderFilledPosition, sliderFilledDimension, 0.0f, COLOR::blend(foregroundFilledColor, blendColor));\n\n\t\tVec2 sliderEmptyPosition = sliderFilledPosition + Vec2(sliderFilledDimension.x, 0);\n\t\tVec2 sliderEmptyDimension = Vec2(barWidth * (1.0 - progress), barHeight);\n\t\tPath::rectFilled(sliderEmptyPosition, sliderEmptyDimension, 0.0f, COLOR::blend(foregroundEmptyColor, blendColor));\n\n\t\tVec2 handlePosition = Vec2(sliderEmptyPosition.x - handleWidth / 2, position.y - height / 2 + handleHeight / 2);\n\t\tVec2 handleDimension = Vec2(handleWidth, handleHeight);\n\t\tPath::rectFilled(handlePosition, handleDimension, 0.0f, COLOR::blend(handleColor, blendColor));\n\t\tPath::rect(handlePosition, handleDimension, 0.0f, COLOR::blend(COLOR::ACCENT, blendColor));\n\n\t\tif (debug)\n\t\t\tPath::rect(position, dimension, 0.0f, COLOR::RED);\n\t}\n}\n\nVec2 Slider::resize() {\n\tif (resizing) {\n\t\tdimension = Vec2(GUI::sliderBarWidth + GUI::sliderHandleWidth, GUI::sliderHandleHeight) + Vec2(padding) * 2;\n\t}\n\treturn dimension;\n}\n\nvoid Slider::drag(Vec2 newPoint, Vec2 oldPoint) {\n\tif (disabled)\n\t\treturn;\n\n\tpress(newPoint);\n}\n\nvoid Slider::press(Vec2 point) {\n\tif (disabled)\n\t\treturn;\n\n\tdouble x = position.x + padding + handleWidth / 2;\n\tdouble w = dimension.x - 2 * padding - handleWidth;\n\n\tif (point.x < x || point.x > x + w)\n\t\treturn;\n\n\tvalue = min + (max - min) * (point.x - x) / w;\n\t(*action)(this);\n}\n"
  },
  {
    "path": "graphics/legacy/slider.h",
    "content": "#pragma once\n\n#include \"component.h\"\n\nclass Slider;\n\ntypedef void(*SliderAction) (Slider*);\n\nclass Slider : public Component {\npublic:\n\tSliderAction action = [] (Slider*) {};\n\n\tColor handleColor;\n\tColor backgroundColor;\n\tColor foregroundFilledColor;\n\tColor foregroundEmptyColor;\n\n\tdouble handleWidth;\n\tdouble barWidth;\n\tdouble barHeight;\n\tdouble handleHeight;\n\n\tdouble min = 0.0;\n\tdouble max = 1.0;\n\tdouble value = 0;\n\n\tSlider(double x, double y);\n\tSlider(double x, double y, double min, double max, double value);\n\tSlider(double x, double y, double width, double height);\n\tSlider(double x, double y, double width, double height, double min, double max, double value);\n\n\tvoid render() override;\n\tVec2 resize() override;\n\n\tvoid drag(Vec2 newPoint, Vec2 oldPoint) override;\n\tvoid press(Vec2 point) override;\n};"
  },
  {
    "path": "graphics/legacy/text.cpp",
    "content": "#include \"core.h\"\n\n#include \"text.h\"\n\n#pragma region Word\n\nWord::Word(double fontSize) : fontSize(fontSize), width(0.0) {\n\n}\n\nvoid Word::addCharacter(const Character& character) {\n\tcharacters.push_back(character);\n\twidth += character.width + (double) character.advance;\n}\n\n#pragma endregion\n\n#pragma region Line\n\nLine::Line(double maxWidth, double spaceWidth) : maxWidth(maxWidth), spaceWidth(spaceWidth), width(0.0) {\n\n}\t\n\nbool Line::addWord(const Word& word) {\n\t// Get word width\n\tdouble extraWidth = word.width;\n\t// Add space in front\n\textraWidth += (!words.empty() ? spaceWidth : 0.0);\n\tif (width + extraWidth <= maxWidth) {\n\t\twords.push_back(word);\n\t\twidth += extraWidth;\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n#pragma endregion\n\n#pragma region Text\n\nText::Text(std::string textString, double x, double y, Font* font, double fontSize, double maxWidth, double spaceWidth, TextFlags textFlags) : textString(textString), x(x), y(y), font(font), fontSize(fontSize), maxWidth(maxWidth), spaceWidth(spaceWidth), textFlags(textFlags) {\n\n}\n\n\n#pragma endregion\n\n#pragma region TextLoader\n\nstd::vector<Line> TextLoader::loadText(const Text& text) {\n\tconst int ASCII_SPACE = 32;\n\n\tstd::vector<Line> lines;\n\tLine currentLine(text.maxWidth, text.spaceWidth);\n\tWord currentWord(text.fontSize);\n\t\n\tfor (char character : text.textString) {\n\t\tint ascii = (int) character;\n\n\t\t// Add word if character is a space\n\t\tif (ascii == ASCII_SPACE) {\n\t\t\t// Check if the word can be added\n\t\t\tbool added = currentLine.addWord(currentWord);\n\t\t\tif (!added) {\n\t\t\t\t// Add word to new line\n\t\t\t\tlines.push_back(currentLine);\n\t\t\t\tcurrentLine = Line(text.maxWidth, text.spaceWidth);\n\t\t\t\tcurrentLine.addWord(currentWord);\n\t\t\t}\n\t\t\tcurrentWord = Word(text.fontSize);\n\t\t} else {\n\t\t\t// Add character to the word\n\t\t\tcurrentWord.addCharacter(text.font->getCharacter(ascii));\n\t\t}\n\t}\n\n\t// Add last word\n\tbool added = currentLine.addWord(currentWord);\n\tif (!added) {\n\t\t// Add word to new line\n\t\tlines.push_back(currentLine);\n\t\tcurrentLine = Line(text.maxWidth, text.spaceWidth);\n\t\tcurrentLine.addWord(currentWord);\n\t}\n\t// Add last line\n\tlines.push_back(currentLine);\n\n\treturn lines;\n}\n\n#pragma endregion"
  },
  {
    "path": "graphics/legacy/text.h",
    "content": "#pragma once\n\n#include \"core.h\"\n\n#include \"font.h\"\n\nstruct Word {\n\t// List of characters in this word\n\tstd::vector<Character> characters;\n\t// Font size of the word\n\tdouble fontSize;\n\t// Width of the word\n\tdouble width;\n\n\tWord(double fontSize);\n\n\tvoid addCharacter(const Character& character);\n};\n\nstruct Line {\n\t// Words of this line\n\tstd::vector<Word> words;\n\t// The max width of this line\n\tdouble maxWidth;\n\t// The current width of this line\n\tdouble width;\n\t// The width of a space character\n\tdouble spaceWidth;\n\n\tLine(double maxWidth, double spaceWidth);\n\n\tbool addWord(const Word& word);\n};\n\nenum TextFlags : char {\n\t// Align text pivot horizontal left\n\tTextPivotHL = 1 << 0,\n\n\t// Align text pivot horizontal centered\n\tTextPivotHC = 1 << 1,\n\n\t// Align text pivot horizontal right\n\tTextPivotHR = 1 << 2,\n\n\t// Align text pivot vertical top\n\tTextPivotVT = 1 << 3,\n\n\t// Align text pivot vertical centered\n\tTextPivotVC = 1 << 4,\n\n\t// Align text pivot vertical bottom\n\tTextPivotVB = 1 << 5\n};\n\nclass Font;\n\nstruct Text {\n\tstd::string textString;\n\n\tFont* font;\n\tdouble fontSize;\n\t\n\tTextFlags textFlags;\n\n\tdouble spaceWidth;\n\n\tdouble x;\n\tdouble y;\n\tdouble maxWidth;\n\n\tText(std::string textString, double x, double y, Font* font, double fontSize, double maxWidth, double spaceWidth, TextFlags textFlags);\n};\n\nclass TextLoader {\npublic:\n\tstd::vector<Line> loadText(const Text& text);\n};"
  },
  {
    "path": "graphics/mesh/abstractMesh.cpp",
    "content": "#include \"core.h\"\n\n#include \"abstractMesh.h\"\n\n#include \"buffers/vertexArray.h\"\n#include \"renderer.h\"\n\nnamespace P3D::Graphics {\n\nAbstractMesh::AbstractMesh(GLFLAG renderMode) : renderMode(renderMode) {\n\tvao = new VertexArray();\n}\n\nAbstractMesh::AbstractMesh() : AbstractMesh(Renderer::TRIANGLES) {}\n\n};"
  },
  {
    "path": "graphics/mesh/abstractMesh.h",
    "content": "#pragma once\n\n#include \"../buffers/bufferLayout.h\"\n#include \"../renderer.h\"\n\nnamespace P3D::Graphics {\n\nclass VertexArray;\n\nclass AbstractMesh {\npublic:\n\tVertexArray* vao = nullptr;\n\tGLFLAG renderMode;\n\n\tAbstractMesh(GLFLAG renderMode);\n\tAbstractMesh();\n\n\tvirtual void render() = 0;\n\tvirtual void close() = 0;\n};\n\n};"
  },
  {
    "path": "graphics/mesh/arrayMesh.cpp",
    "content": "#include \"core.h\"\n\n#include \"arrayMesh.h\"\n\n#include \"buffers/vertexArray.h\"\n#include \"buffers/vertexBuffer.h\"\n\n#include \"renderer.h\"\n\nnamespace P3D::Graphics {\n\nArrayMesh::ArrayMesh(Vec3f* positions, const unsigned int vertexCount) : ArrayMesh(reinterpret_cast<float const*>(positions), vertexCount * 3, 3) {\n\n};\n\nArrayMesh::ArrayMesh(Vec2f* positions, const unsigned int vertexCount) : ArrayMesh(reinterpret_cast<float const*>(positions), vertexCount * 2, 2) {\n\n};\n\nArrayMesh::ArrayMesh(const float* positions, const unsigned int vertexCount, const unsigned int dimensions) : ArrayMesh(positions, vertexCount, dimensions, Graphics::Renderer::TRIANGLES) {\n\n};\n\nArrayMesh::ArrayMesh(const float* vertices, const float* uv, const unsigned int vertexCount, const unsigned int dimensions) : AbstractMesh(), vertexCount(vertexCount) {\n\tvertexBufferLayout = {\n\t\t{{ \"vposition\", (dimensions == 2) ? BufferDataType::FLOAT2 : BufferDataType::FLOAT3 }}\n\t};\n\tvertexBuffer = new VertexBuffer(vertexBufferLayout, vertices, dimensions * vertexCount * sizeof(float));\n\n\tuvBufferLayout = {\n\t\t{{ \"vUV\", BufferDataType::FLOAT2 }}\n\t};\n\tuvBuffer = new VertexBuffer(uvBufferLayout, uv, 2 * vertexCount * sizeof(float));\n\n\tvao->addBuffer(vertexBuffer);\n\tvao->addBuffer(uvBuffer);\n}\n\nArrayMesh::ArrayMesh(const float* vertices, const unsigned int vertexCount, const unsigned int dimensions, unsigned int renderMode) : AbstractMesh(renderMode), vertexCount(vertexCount) {\n\tvertexBufferLayout = {\n\t\t{{ \"vposition\", (dimensions == 2) ? BufferDataType::FLOAT2 : BufferDataType::FLOAT3 }}\n\t};\n\tvertexBuffer = new VertexBuffer(vertexBufferLayout, vertices, dimensions * vertexCount * sizeof(float));\n\n\tvao->addBuffer(vertexBuffer);\n}\n\nvoid ArrayMesh::render() {\n\tvao->bind();\n\tGraphics::Renderer::drawArrays(renderMode, 0, vertexCount);\n}\n\nvoid ArrayMesh::close() {\n\tvertexBuffer->close();\n\tvao->close();\n}\n\n};"
  },
  {
    "path": "graphics/mesh/arrayMesh.h",
    "content": "#pragma once\n\n#include \"abstractMesh.h\"\n\n#include \"../buffers/bufferLayout.h\"\n\nnamespace P3D::Graphics {\n\nclass VertexBuffer;\n\nclass ArrayMesh : public AbstractMesh {\npublic:\n\tBufferLayout vertexBufferLayout;\n\tBufferLayout uvBufferLayout;\n\n\tVertexBuffer* vertexBuffer = nullptr;\n\tVertexBuffer* uvBuffer = nullptr;\n\n\tconst int vertexCount;\n\n\tArrayMesh(const float* positions, const float* uv, const unsigned int vertexCount, const unsigned int dimensions);\n\tArrayMesh(const float* positions, const unsigned int vertexCount, const unsigned int dimensions, unsigned int renderMode);\n\tArrayMesh(const float* positions, const unsigned int vertexCount, const unsigned int dimensions);\n\tArrayMesh(Vec3f* positions, const unsigned int vertexCount);\n\tArrayMesh(Vec2f* positions, const unsigned int vertexCount);\n\n\tvoid render() override;\n\tvoid close() override;\n};\n\n};"
  },
  {
    "path": "graphics/mesh/indexedMesh.cpp",
    "content": "#include \"core.h\"\n\n#include \"indexedMesh.h\"\n\n#include \"buffers/indexBuffer.h\"\n#include \"buffers/vertexBuffer.h\"\n#include \"buffers/vertexArray.h\"\n#include \"extendedTriangleMesh.h\"\n#include \"renderer.h\"\n\nnamespace P3D::Graphics {\n\nIndexedMesh::IndexedMesh(const ExtendedTriangleMesh& shape) : AbstractMesh(), vertexCount(shape.vertexCount), triangleCount(shape.triangleCount) {\n\tfloat* vertices = new float[shape.vertexCount * 3];\n\tfor (int i = 0; i < vertexCount; i++) {\n\t\tVec3f vertex = shape.getVertex(i);\n\t\tvertices[i * 3] = vertex.x;\n\t\tvertices[i * 3 + 1] = vertex.y;\n\t\tvertices[i * 3 + 2] = vertex.z;\n\t}\n\tunsigned int* triangles = new unsigned int[shape.triangleCount * 3];\n\tfor (int i = 0; i < triangleCount; i++) {\n\t\tTriangle triangle = shape.getTriangle(i);\n\t\ttriangles[i * 3] = triangle.firstIndex;\n\t\ttriangles[i * 3 + 1] = triangle.secondIndex;\n\t\ttriangles[i * 3 + 2] = triangle.thirdIndex;\n\t}\n\n\tBufferLayout vertexBufferLayout = {\n\t{{ \"vPosition\", BufferDataType::FLOAT3 }}\n\t};\n\tvertexBuffer = std::make_unique<VertexBuffer>(vertexBufferLayout, vertices, 3 * vertexCount * sizeof(float));\n\n\tBufferLayout normalBufferLayout = {\n\t\t{{ \"vNormal\", BufferDataType::FLOAT3 }}\n\t};\n\tnormalBuffer = std::make_unique<VertexBuffer>(normalBufferLayout, reinterpret_cast<float const*>(shape.normals.get()), 3 * vertexCount * sizeof(float));\n\n\tBufferLayout uvBufferLayout = {\n\t\t{{ \"vUV\", BufferDataType::FLOAT2 }}\n\t};\n\tuvBuffer = std::make_unique<VertexBuffer>(uvBufferLayout, reinterpret_cast<float const*>(shape.uvs.get()), 2 * vertexCount * sizeof(float));\n\n\tBufferLayout tangentBufferLayout = {\n\t\t{{ \"vTangent\", BufferDataType::FLOAT3 }}\n\t};\n\ttangentBuffer = std::make_unique<VertexBuffer>(tangentBufferLayout, reinterpret_cast<float const*>(shape.tangents.get()), 3 * vertexCount * sizeof(float));\n\n\tBufferLayout bitangentBufferLayout = {\n\t\t{{ \"vBitangent\", BufferDataType::FLOAT3 }}\n\t};\n\tbitangentBuffer = std::make_unique<VertexBuffer>(bitangentBufferLayout, reinterpret_cast<float const*>(shape.bitangents.get()), 3 * vertexCount * sizeof(float));\n\n\tindexBuffer = std::make_unique<IndexBuffer>(triangles, 3 * triangleCount);\n\n\tvao->addBuffer(vertexBuffer.get());\n\tvao->addBuffer(normalBuffer.get());\n\tvao->addBuffer(uvBuffer.get());\n\tvao->addBuffer(tangentBuffer.get());\n\tvao->addBuffer(bitangentBuffer.get());\n}\n\nIndexedMesh::IndexedMesh(const float* vertices, const float* normals, const float* uvs, const unsigned int* indices, std::size_t vertexCount, std::size_t triangleCount) : AbstractMesh(), vertexCount(vertexCount), triangleCount(triangleCount) {\n\tBufferLayout vertexBufferLayout = {\n\t\t{{ \"vposition\", BufferDataType::FLOAT3 }}\n\t};\n\tvertexBuffer = std::make_unique<VertexBuffer>(vertexBufferLayout, vertices, 3 * vertexCount * sizeof(float));\n\n\tBufferLayout normalBufferLayout = {\n\t\t{{ \"vnormal\", BufferDataType::FLOAT3 }}\n\t};\n\tnormalBuffer = std::make_unique<VertexBuffer>(normalBufferLayout, normals, 3 * vertexCount * sizeof(float));\n\n\tBufferLayout uvBufferLayout = {\n\t\t{{ \"vUV\", BufferDataType::FLOAT2 }}\n\t};\n\tuvBuffer = std::make_unique<VertexBuffer>(uvBufferLayout, uvs, 2 * vertexCount * sizeof(float));\n\n\t// TODO Generate tangents and bitangents\n\tBufferLayout tangentBufferLayout = {\n\t\t{{ \"vTangent\", BufferDataType::FLOAT3 }}\n\t};\n\ttangentBuffer = std::make_unique<VertexBuffer>(tangentBufferLayout, nullptr, 0);\n\n\tBufferLayout bitangentBufferLayout = {\n\t\t{{ \"vBitangent\", BufferDataType::FLOAT3 }}\n\t};\n\tbitangentBuffer = std::make_unique<VertexBuffer>(bitangentBufferLayout, nullptr, 0);\n\n\tindexBuffer = std::make_unique<IndexBuffer>(indices, 3 * triangleCount);\n\n\tvao->addBuffer(vertexBuffer.get());\n\tvao->addBuffer(normalBuffer.get());\n\tvao->addBuffer(uvBuffer.get());\n\tvao->addBuffer(tangentBuffer.get());\n\tvao->addBuffer(bitangentBuffer.get());\n}\n\nIndexedMesh::~IndexedMesh() {\n\tclose();\n\tLog::debug(\"Closed indexed mesh\");\n}\n\nIndexedMesh::IndexedMesh(IndexedMesh&& other) {\n\tvao = other.vao;\n\n\tindexBuffer.swap(other.indexBuffer);\n\tvertexBuffer.swap(other.vertexBuffer);\n\tnormalBuffer.swap(other.normalBuffer);\n\tuvBuffer.swap(other.uvBuffer);\n\ttangentBuffer.swap(other.tangentBuffer);\n\tbitangentBuffer.swap(other.bitangentBuffer);\n\tuniformBuffer.swap(other.uniformBuffer);\n\tindexBuffer.swap(other.indexBuffer);\n\n\tvertexCount = other.vertexCount;\n\ttriangleCount = other.triangleCount;\n\n\t// Reset so they cant be deleted by close()\n\tother.vao = nullptr;\n\n\tother.indexBuffer = nullptr;\n\tother.vertexBuffer = nullptr;\n\tother.normalBuffer = nullptr;\n\tother.uvBuffer = nullptr;\n\tother.bitangentBuffer = nullptr;\n\tother.tangentBuffer = nullptr;\n\tother.uniformBuffer = nullptr;\n\n\tother.close();\n}\n\nIndexedMesh& IndexedMesh::operator=(IndexedMesh&& other) {\n\tif (this != &other) {\n\t\tclose();\n\t\tstd::swap(vao, other.vao);\n\n\t\tstd::swap(indexBuffer, other.indexBuffer);\n\t\tstd::swap(vertexBuffer, other.vertexBuffer);\n\t\tstd::swap(normalBuffer, other.normalBuffer);\n\t\tstd::swap(uvBuffer, other.uvBuffer);\n\t\tstd::swap(tangentBuffer, other.tangentBuffer);\n\t\tstd::swap(bitangentBuffer, other.bitangentBuffer);\n\t\tstd::swap(uniformBuffer, other.uniformBuffer);\n\n\t\tstd::swap(vertexCount, other.vertexCount);\n\t\tstd::swap(triangleCount, other.triangleCount);\n\t}\n\n\treturn *this;\n}\n\nvoid IndexedMesh::render() {\n\trender(Renderer::FILL);\n}\n\nvoid IndexedMesh::addUniformBuffer(VertexBuffer* uniformBuffer) {\n\tthis->uniformBuffer = URef<VertexBuffer>(uniformBuffer);\n\n\tvao->addBuffer(uniformBuffer);\n}\n\nvoid IndexedMesh::updateUniformBuffer(const void* data, size_t sizeInBytes, int offset) {\n\tif (uniformBuffer)\n\t\tuniformBuffer->update(data, sizeInBytes, offset);\n\telse\n\t\tLog::error(\"Updating non existing uniform buffer\");\n}\n\nvoid IndexedMesh::fillUniformBuffer(const void* data, size_t sizeInBytes, GLFLAG mode) {\n\tif (uniformBuffer) \n\t\tuniformBuffer->fill(data, sizeInBytes, mode);\n\telse\n\t\tLog::error(\"Filling non existing uniform buffer\");\n}\n\nvoid IndexedMesh::render(GLFLAG mode) {\n\tvao->bind();\n\tindexBuffer->bind();\n\n\tRenderer::polygonMode(Renderer::FRONT_AND_BACK, mode);\n\tRenderer::drawElements(renderMode, triangleCount * 3, Renderer::UINT, 0);\n\tRenderer::polygonMode(Renderer::FRONT_AND_BACK, Renderer::FILL);\n}\n\nvoid IndexedMesh::renderInstanced(size_t primitives) {\n\trenderInstanced(primitives, Renderer::FILL);\n}\n\nvoid IndexedMesh::renderInstanced(size_t primitives, GLFLAG mode) {\n\tvao->bind();\n\tindexBuffer->bind();\n\n\tRenderer::polygonMode(Renderer::FRONT_AND_BACK, mode);\n\tRenderer::drawElementsInstanced(renderMode, triangleCount * 3, Renderer::UINT, 0, primitives);\n\tRenderer::polygonMode(Renderer::FRONT_AND_BACK, Renderer::FILL);\n}\n\nvoid IndexedMesh::close() {\n\tif (vertexBuffer)\n\t\tvertexBuffer->close();\n\tif (indexBuffer)\n\t\tindexBuffer->close();\n\tif (normalBuffer)\n\t\tnormalBuffer->close();\n\tif (uvBuffer)\n\t\tuvBuffer->close();\n\tif (tangentBuffer)\n\t\ttangentBuffer->close();\n\tif (bitangentBuffer)\n\t\tbitangentBuffer->close();\n\tif (uniformBuffer)\n\t\tuniformBuffer->close();\n\tif (vao)\n\t\tvao->close();\n\n\tvao = nullptr;\n\n\tindexBuffer = nullptr;\n\tvertexBuffer = nullptr;\n\tnormalBuffer = nullptr;\n\tuvBuffer = nullptr;\n\ttangentBuffer = nullptr;\n\tbitangentBuffer = nullptr;\n\tuniformBuffer = nullptr;\n\n\ttriangleCount = 0;\n\tvertexCount = 0;\n}\n\n};"
  },
  {
    "path": "graphics/mesh/indexedMesh.h",
    "content": "#pragma once\n\n#include \"abstractMesh.h\"\n\n#include \"../buffers/bufferLayout.h\"\n#include \"../renderer.h\"\n\n#include \"../buffers/indexBuffer.h\"\n#include \"../buffers/vertexBuffer.h\"\n\nnamespace P3D::Graphics {\n\nclass IndexBuffer;\nclass VertexBuffer;\nstruct ExtendedTriangleMesh;\n\nclass IndexedMesh : public AbstractMesh {\npublic:\n\tURef<IndexBuffer> indexBuffer = nullptr;\n\tURef<VertexBuffer> vertexBuffer = nullptr;\n\tURef<VertexBuffer> normalBuffer = nullptr;\n\tURef<VertexBuffer> uvBuffer = nullptr;\n\tURef<VertexBuffer> tangentBuffer = nullptr;\n\tURef<VertexBuffer> bitangentBuffer = nullptr;\n\tURef<VertexBuffer> uniformBuffer = nullptr;\n\n\tstd::size_t vertexCount;\n\tstd::size_t triangleCount;\n\n\tIndexedMesh(const ExtendedTriangleMesh& shape);\n\tIndexedMesh(const float* vertices, const float* normals, const float* uvs, const unsigned int* indices, std::size_t vertexCount, std::size_t triangleCount);\n\n\tvirtual ~IndexedMesh();\n\tIndexedMesh(IndexedMesh&& other);\n\tIndexedMesh(const IndexedMesh&) = delete;\n\tIndexedMesh& operator=(IndexedMesh&& other);\n\tIndexedMesh& operator=(const IndexedMesh&) = delete;\n\n\tvoid addUniformBuffer(VertexBuffer* uniformBuffer);\n\tvoid updateUniformBuffer(const void* data, size_t sizeInBytes, int offset);\n\tvoid fillUniformBuffer(const void* data, size_t sizeInBytes, GLFLAG mode);\n\n\tvoid render() override;\n\tvoid render(GLFLAG mode);\n\tvoid renderInstanced(size_t primitives);\n\tvoid renderInstanced(size_t primitives, GLFLAG mode);\n\n\tvoid close() override;\n};\n\n};"
  },
  {
    "path": "graphics/mesh/pointMesh.cpp",
    "content": "#include \"core.h\"\n\n#include \"pointMesh.h\"\n\n#include \"buffers/vertexArray.h\"\n#include \"buffers/vertexBuffer.h\"\n#include \"renderer.h\"\n\nnamespace P3D::Graphics {\n\nPointMesh::PointMesh(const float* vertices, const size_t vertexCount, size_t capacity) : AbstractMesh(Renderer::POINT), vertexCount(vertexCount), capacity(capacity) {\n\tvertexBufferLayout = BufferLayout({\n\t\tBufferElement(\"vposition\", BufferDataType::FLOAT3),\n\t\tBufferElement(\"vsize\", BufferDataType::FLOAT),\n\t\tBufferElement(\"vcolor1\", BufferDataType::FLOAT3),\n\t\tBufferElement(\"vcolor2\", BufferDataType::FLOAT3)\n\t});\n\n\tvertexBuffer = new VertexBuffer(vertexBufferLayout, nullptr, 10 * capacity * sizeof(float), Renderer::DYNAMIC_DRAW);\n\t\n\tvao->addBuffer(vertexBuffer);\n}\n\nvoid PointMesh::render() {\n\tvao->bind();\n\tRenderer::drawArrays(renderMode, 0, vertexCount);\n}\n\nvoid PointMesh::close() {\n\tvertexBuffer->close();\n\tvao->close();\n}\n\nvoid PointMesh::update(const float* vertices, const size_t vertexCount) {\n\tvertexBuffer->bind();\n\tthis->vertexCount = vertexCount;\n\tif (vertexCount > capacity) {\n\t\tcapacity = vertexCount;\n\t\tLog::warn(\"Point buffer overflow, creating new buffer with size (%d)\", vertexCount);\n\t\tvertexBuffer->fill(vertices, capacity * vertexBufferLayout.stride * sizeof(float), Graphics::Renderer::DYNAMIC_DRAW);\n\t} else {\n\t\tvertexBuffer->update(vertices, vertexCount * vertexBufferLayout.stride * sizeof(float), 0);\n\t}\n}\n\n};"
  },
  {
    "path": "graphics/mesh/pointMesh.h",
    "content": "#pragma once\n\n#include \"abstractMesh.h\"\n\nnamespace P3D::Graphics {\n\nclass VertexBuffer;\n\nclass PointMesh : public AbstractMesh {\npublic:\n\tVertexBuffer* vertexBuffer = nullptr;\n\tBufferLayout vertexBufferLayout;\n\n\tsize_t vertexCount;\n\tsize_t capacity;\n\n\tPointMesh(const float* vertices, const size_t size) : PointMesh(vertices, size, size) {};\n\tPointMesh(const float* vertices, const size_t size, size_t capacity);\n\n\tvoid update(const float* vertices, const size_t vertexCount);\n\n\tvoid render() override;\n\tvoid close() override;\n};\n\n};"
  },
  {
    "path": "graphics/mesh/primitive.h",
    "content": "#pragma once\n\n#include \"../graphics/renderer.h\"\n#include <Physics3D/math/linalg/vec.h>\n\nnamespace P3D::Graphics {\n\nstruct Primitive {\n\tunsigned int vao;\n\tunsigned int vbo;\n\tint M;\n\tint N;\n\n\ttemplate<int M, int N>\n\tvoid resize(float(&vertices)[M][N]) {\n\t\tusing namespace Renderer;\n\t\t\n\t\tbindVertexArray(vao);\n\t\tbindBuffer(ARRAY_BUFFER, vbo);\n\t\tbufferSubData(ARRAY_BUFFER, 0, M * N * sizeof(float), vertices);\n\t\tbindBuffer(ARRAY_BUFFER, 0);\n\t\tbindVertexArray(0);\n\t}\n\n\tvirtual void render() = 0;\n\nprotected:\n\t// M is size of vertex, N is amount of vertices\n\tPrimitive(int M, int N) {\n\t\tusing namespace Renderer;\n\t\t\n\t\tthis->M = M;\n\t\tthis->N = N;\n\n\t\tgenVertexArrays(1, &vao);\n\t\tgenBuffers(1, &vbo);\n\n\t\tbindVertexArray(vao);\n\t\tbindBuffer(ARRAY_BUFFER, vbo);\n\n\t\tbufferData(ARRAY_BUFFER, sizeof(float) * M * N, 0, DYNAMIC_DRAW);\n\n\t\tenableVertexAttribArray(0);\n\t\tvertexAttribPointer(0, M, FLOAT, false, 0, 0);\n\n\t\tbindBuffer(ARRAY_BUFFER, 0);\n\t\tbindVertexArray(0);\n\t}\n\n\t~Primitive() {\n\t\tusing namespace Renderer;\n\n\t\tdelBuffers(1, &vbo);\n\t\tdelVertexArrays(1, &vao);\n\t}\n};\n\n\n// Quad\n\nstruct Quad : public Primitive {\n\n\tQuad() : Primitive(4, 4) {\n\t\tresize(Vec2f(-1, 1), Vec2f(2.0f, 2.0f));\n\t}\n\n\tQuad(Vec2f topLeft, Vec2f dimension) : Primitive(4, 4) {\n\t\tresize(topLeft, dimension);\n\t}\n\n\tvoid resize(Vec2f position, Vec2f dimension, Vec2f xRange, Vec2f yRange) {\n\t\tfloat dx = xRange.y - xRange.x;\n\t\tfloat dy = yRange.y - yRange.x;\n\n\t\tfloat u = (position.x - xRange.x) / dx;\n\t\tfloat v = (position.y - dimension.y - yRange.x) / dy;\n\t\tfloat du = dimension.x / dx;\n\t\tfloat dv = dimension.y / dy;\n\n\t\tfloat vertices[4][4] = {\n\t\t\t{ position.x,\t\t\t\tposition.y\t\t\t\t, u,      v + dv},\n\t\t\t{ position.x,\t\t\t\tposition.y - dimension.y, u,      v     },\n\t\t\t{ position.x + dimension.x, position.y - dimension.y, u + du, v     },\n\t\t\t{ position.x + dimension.x, position.y\t\t\t\t, u + du, v + dv}\n\t\t};\n\n\t\tPrimitive::resize(vertices);\n\t}\n\n\tvoid resize(Vec2f position, Vec2f dimension) {\n\n\t\tfloat vertices[4][4] = {\n\t\t\t{ position.x,\t\t\t\tposition.y\t\t\t\t, 0.0f, 1.0f},\n\t\t\t{ position.x,\t\t\t\tposition.y - dimension.y, 0.0f, 0.0f},\n\t\t\t{ position.x + dimension.x, position.y - dimension.y, 1.0f, 0.0f},\n\t\t\t{ position.x + dimension.x, position.y\t\t\t\t, 1.0f, 1.0f}\n\t\t};\n\n\t\tPrimitive::resize(vertices);\n\t}\n\n\tvoid render(int mode) {\n\t\tusing namespace Renderer;\n\n\t\tpolygonMode(FRONT_AND_BACK, mode);\n\n\t\tbindVertexArray(vao);\n\t\tdrawArrays(QUADS, 0, 4);\n\t\tbindVertexArray(0);\n\n\t\tpolygonMode(FRONT_AND_BACK, FILL);\n\t}\n\n\tvoid render() override {\n\t\trender(Renderer::FILL);\n\t}\n};\n\n\n// Line\n\nstruct LinePrimitive : public Primitive {\n\n\tvoid resize(Vec3f p1, Vec3f p2) {\n\t\tfloat vertices[2][3] = {\n\t\t\t{ p1.x,\tp1.y, p1.z },\n\t\t\t{ p2.x,\tp2.y, p2.z }\n\t\t};\n\n\t\tPrimitive::resize(vertices);\n\t}\n\n\tvoid resize(Vec2f p1, Vec2f p2) {\n\t\tfloat vertices[2][3] = {\n\t\t\t{ p1.x,\tp1.y, 0 },\n\t\t\t{ p2.x,\tp2.y, 0 }\n\t\t};\n\n\t\tPrimitive::resize(vertices);\n\t}\n\n\tLinePrimitive() : Primitive(3, 2) {\n\t\tresize(Vec3f::full(-1.0f), Vec3f::full(1.0f));\n\t}\n\n\tvoid render(int mode) {\n\t\tusing namespace Renderer;\n\t\t\n\t\tpolygonMode(FRONT_AND_BACK, mode);\n\n\t\tbindVertexArray(vao);\n\t\tdrawArrays(LINE_STRIP, 0, 2);\n\t\tbindVertexArray(0);\n\n\t\tpolygonMode(FRONT_AND_BACK, FILL);\n\t}\n\n\tvoid render() override {\n\t\trender(Renderer::FILL);\n\t}\n};\n\n\n// Triangle\n\nstruct TrianglePrimitive : public Primitive {\n\n\tbool patched;\n\n\tTrianglePrimitive(bool patched = false) : Primitive(3, 3) {\n\t\tthis->patched = patched;\n\t\tresize(Vec3f::full(-1.0f), Vec3f::full(1.0f), Vec3f(0.0f, 1.0f, -1.0f));\n\t}\n\n\tvoid resize(Vec3f p1, Vec3f p2, Vec3f p3) {\n\t\tfloat vertices[3][3] = {\n\t\t\t{ p1.x,\tp1.y, p1.z },\n\t\t\t{ p2.x,\tp2.y, p2.z },\n\t\t\t{ p3.x,\tp3.y, p3.z }\n\t\t};\n\n\t\tPrimitive::resize(vertices);\n\t}\n\n\tvoid resize(Vec2f p1, Vec2f p2, Vec2f p3) {\n\n\t\tfloat vertices[3][3] = {\n\t\t\t{ p1.x,\tp1.y, 0 },\n\t\t\t{ p2.x,\tp2.y, 0 },\n\t\t\t{ p3.x,\tp3.y, 0 }\n\t\t};\n\n\t\tPrimitive::resize(vertices);\n\t}\n\n\tvoid render(int mode) {\n\t\tusing namespace Renderer;\n\n\t\tpolygonMode(FRONT_AND_BACK, mode);\n\n\t\tbindVertexArray(vao);\n\t\tdrawArrays(patched ? PATCHES : TRIANGLES, 0, 3);\n\t\tbindVertexArray(0);\n\n\t\tpolygonMode(FRONT_AND_BACK, FILL);\n\t}\n\n\tvoid render() override {\n\t\trender(Renderer::FILL);\n\t}\n};\n\n};\n"
  },
  {
    "path": "graphics/mesh/vectorMesh.cpp",
    "content": "#include \"core.h\"\n\n#include \"vectorMesh.h\"\n\n#include \"renderer.h\"\n\n#include \"buffers/vertexBuffer.h\"\n#include \"buffers/vertexArray.h\"\n\nnamespace P3D::Graphics {\n\nVectorMesh::VectorMesh(const float* vertices, const size_t vertexCount, size_t capacity) : AbstractMesh(Graphics::Renderer::POINT), vertexCount(vertexCount), capacity(capacity) {\n\tvertexBufferLayout = BufferLayout({\n\t\tBufferElement(\"vposition\", BufferDataType::FLOAT3),\n\t\tBufferElement(\"vdirection\", BufferDataType::FLOAT3),\n\t\tBufferElement(\"vcolor\", BufferDataType::FLOAT3)\n\t});\n\tvertexBuffer = new VertexBuffer(vertexBufferLayout, vertices, 9 * capacity * sizeof(float), Graphics::Renderer::DYNAMIC_DRAW);\n\n\tvao->addBuffer(vertexBuffer);\n}\n\nvoid VectorMesh::render() {\n\tvao->bind();\n\tGraphics::Renderer::drawArrays(renderMode, 0, vertexCount);\n}\n\nvoid VectorMesh::close() {\n\tvertexBuffer->close();\n\tvao->close();\n}\n\nvoid VectorMesh::update(const float* vertices, const size_t vertexCount) {\n\tvertexBuffer->bind();\n\tthis->vertexCount = vertexCount;\n\tif (vertexCount > capacity) {\n\t\tcapacity = vertexCount;\n\t\tLog::warn(\"Vector buffer overflow, creating new buffer with size (%d)\", vertexCount);\n\t\tvertexBuffer->fill(vertices, capacity * vertexBufferLayout.stride * sizeof(float), Graphics::Renderer::DYNAMIC_DRAW);\n\t} else {\n\t\tvertexBuffer->update(vertices, vertexCount * vertexBufferLayout.stride * sizeof(float), 0);\n\t}\n}\n\n};"
  },
  {
    "path": "graphics/mesh/vectorMesh.h",
    "content": "#pragma once\n\n#include \"abstractMesh.h\"\n\nnamespace P3D::Graphics {\n\nclass VertexBuffer;\n\nclass VectorMesh : public AbstractMesh {\npublic:\n\tVertexBuffer* vertexBuffer = nullptr;\n\tBufferLayout vertexBufferLayout;\n\n\tsize_t vertexCount;\n\tsize_t capacity;\n\n\tVectorMesh(const float* vertices, const size_t size) : VectorMesh(vertices, size, size) {};\n\tVectorMesh(const float* vertices, const size_t size, size_t capacity);\n\n\tvoid update(const float* vertices, const size_t vertexCount);\n\n\tvoid render() override;\n\tvoid close() override;\n};\n\n};"
  },
  {
    "path": "graphics/meshRegistry.cpp",
    "content": "#include \"core.h\"\n#include \"meshRegistry.h\"\n\n#include <Physics3D/math/constants.h>\n#include <Physics3D/geometry/shapeLibrary.h>\n#include <Physics3D/geometry/builtinShapeClasses.h>\n\n#include \"mesh/indexedMesh.h\"\n\n#include <stdexcept>\n#include <cmath>\n#include <cstddef>\n\nnamespace P3D::Graphics::MeshRegistry {\n\nstd::vector<IndexedMesh*> meshes;\nstd::map<const ShapeClass*, Comp::Mesh> shapeClassMeshIds;\n\nComp::Mesh box;\nComp::Mesh sphere;\nComp::Mesh cylinder;\nComp::Mesh wedge;\nComp::Mesh corner;\nComp::Mesh hexagon;\nComp::Mesh quad;\n\nExtendedTriangleMesh createQuad(const Vec3f& center, const Vec3f& normal, const Vec2f& dimension) {\n\tVec3f up(0.0f, 1.0f, 0.0f);\n\tVec3f u = up % normal;\n\tVec3f v = normal % u;\n\n\tVec3f du = u * dimension.x / 2.0f;\n\tVec3f dv = v * dimension.y / 2.0f;\n\tVec3f bl = center - du - dv;\n\tVec3f br = center + du - dv;\n\tVec3f tl = center - du + dv;\n\tVec3f tr = center + du + dv;\n\n\tVec3f* vertexBuffer = new Vec3f[4] {\n\t\tbl,\n\t\tbr,\n\t\ttl,\n\t\ttr\n\t};\n\n\tTriangle* triangleBuffer = new Triangle[2] {\n\t\tTriangle { 0, 1, 3 },\n\t\tTriangle { 0, 3, 2 }\n\t};\n\n\tVec3f* normalBuffer = new Vec3f[4] {\n\t\tnormal,\n\t\tnormal,\n\t\tnormal,\n\t\tnormal,\n\t};\n\n\tVec2f* uvBuffer = new Vec2f[4] {\n\t\tVec2f { 0.0f, 0.0f },\n\t\tVec2f { 1.0f, 0.0f },\n\t\tVec2f { 0.0f, 1.0f },\n\t\tVec2f { 1.0f, 1.0f },\n\t};\n\n\tExtendedTriangleMesh mesh(vertexBuffer, 4, triangleBuffer, 2);\n\tmesh.setNormalBuffer(SRef<const Vec3f[]>(normalBuffer));\n\tmesh.setUVBuffer(SRef<const Vec2f[]>(uvBuffer));\n\n\treturn mesh;\n}\n\nExtendedTriangleMesh createCylinder(int sides, double radius, double height) {\n\tif (sides < 2)\n\t\tthrow std::logic_error(\"Cannot create cylinder with <2 sides\");\n\n\tint vertexCount = sides * 4;\n\tVec3f* vertexBuffer = new Vec3f[vertexCount];\n\n\tfloat r = static_cast<float>(radius);\n\tfloat h = static_cast<float>(height);\n\n\t// vertices\n\tfor (int i = 0; i < sides; i++) {\n\t\tfloat angle = i * pi<float>() * 2 / sides;\n\t\tVec3f bottom(std::cos(angle) * r, std::sin(angle) * r, h / 2);\n\t\tVec3f top(std::cos(angle) * r, std::sin(angle) * r, -h / 2);\n\t\tvertexBuffer[i * 2] = bottom;\n\t\tvertexBuffer[i * 2 + 1] = top;\n\t\tvertexBuffer[i * 2 + sides * 2] = bottom;\n\t\tvertexBuffer[i * 2 + 1 + sides * 2] = top;\n\t}\n\n\tint triangleCount = sides * 2 + (sides - 2) * 2;\n\tTriangle* triangleBuffer = new Triangle[triangleCount];\n\n\t// sides\n\tfor (int i = 0; i < sides; i++) {\n\t\tint bottomLeft = i * 2;\n\t\tint bottomRight = ((i + 1) % sides) * 2;\n\t\ttriangleBuffer[i * 2] = Triangle{bottomLeft, bottomLeft + 1, bottomRight}; // botLeft, botRight, topLeft\n\t\ttriangleBuffer[i * 2 + 1] = Triangle{bottomRight + 1, bottomRight, bottomLeft + 1}; // topRight, topLeft, botRight\n\t}\n\n\tTriangle* capOffset = triangleBuffer + static_cast<std::size_t>(sides) * 2;\n\t// top and bottom\n\tfor (int i = 0; i < sides - 2; i++) {\n\t\t// common corner is i=0\n\t\tcapOffset[i] = Triangle{sides * 2 + 0, sides * 2 + (i + 1) * 2, sides * 2 + (i + 2) * 2};\n\t\tcapOffset[i + (sides - 2)] = Triangle{sides * 2 + 1, sides * 2 + (i + 2) * 2 + 1, sides * 2 + (i + 1) * 2 + 1};\n\t}\n\n\tVec3f* normalBuffer = new Vec3f[vertexCount];\n\tfor (int i = 0; i < sides * 2; i++) {\n\t\tVec3f vertex = vertexBuffer[i];\n\t\tnormalBuffer[i] = normalize(Vec3(vertex.x, vertex.y, 0));\n\t}\n\n\tfor (int i = 0; i < sides; i++) {\n\t\tnormalBuffer[i * 2 + sides * 2] = Vec3f(0, 0, 1);\n\t\tnormalBuffer[i * 2 + sides * 2 + 1] = Vec3f(0, 0, -1);\n\t}\n\n\tVec2f* uvBuffer = new Vec2f[vertexCount];\n\tfor (int i = 0; i < vertexCount; i++) {\n\t\tVec3f& p = vertexBuffer[i];\n\n\t\tfloat u;\n\t\tfloat v = p.y / h;\n\t\tif (p.x >= 0) {\n\t\t\tif (p.x == 0) {\n\t\t\t\tu = std::asin(p.y / std::sqrt(p.x * p.x + p.y * p.y));\n\t\t\t} else {\n\t\t\t\tu = std::atan2(p.y, p.x);\n\t\t\t}\n\t\t} else {\n\t\t\tu = -std::asin(p.y / std::sqrt(p.x * p.x + p.y * p.y)) + PI;\n\t\t}\n\n\t\tuvBuffer[i] = Vec2f(u, v);\n\t}\n\n\tExtendedTriangleMesh cylinderShape(vertexBuffer, vertexCount, triangleBuffer, triangleCount);\n\tcylinderShape.setNormalBuffer(SRef<const Vec3f[]>(normalBuffer));\n\tcylinderShape.setUVBuffer(SRef<const Vec2f[]>(uvBuffer));\n\n\treturn cylinderShape;\n}\n\nExtendedTriangleMesh createSphere(double radius, int steps) {\n\tPolyhedron sphere(ShapeLibrary::createSphere(static_cast<float>(radius), steps));\n\tExtendedTriangleMesh sphereShape(sphere);\n\n\tint i = 0;\n\tVec3f* normalBuffer = new Vec3f[sphereShape.vertexCount];\n\tVec2f* uvBuffer = new Vec2f[sphereShape.vertexCount];\n\tfor (Vec3f vertex : sphereShape.iterVertices()) {\n\t\tVec3f normal = normalize(vertex);\n\t\tVec2f uv = Vec2f(atan2(normal.x, normal.z) / (2 * PI) + 0.5, normal.y * 0.5 + 0.5);\n\n\t\tnormalBuffer[i] = normal;\n\t\tuvBuffer[i] = uv;\n\n\t\ti++;\n\t}\n\n\tsphereShape.setNormalBuffer(SRef<const Vec3f[]>(normalBuffer));\n\tsphereShape.setUVBuffer(SRef<const Vec2f[]>(uvBuffer));\n\n\treturn sphereShape;\n}\n\nExtendedTriangleMesh createBox(float width, float height, float depth) {\n\tPolyhedron box(ShapeLibrary::createBox(width, height, depth));\n\tExtendedTriangleMesh boxShape = ExtendedTriangleMesh::generateSplitNormalsShape(box);\n\n\tVec2f* uvBuffer = new Vec2f[boxShape.triangleCount * 3];\n\tfor (std::size_t ti = 0; ti < boxShape.triangleCount; ti++) {\n\t\tTriangle t = boxShape.getTriangle(ti);\n\t\tVec3f v[3];\n\t\tv[0] = boxShape.getVertex(t.firstIndex);\n\t\tv[1] = boxShape.getVertex(t.secondIndex);\n\t\tv[2] = boxShape.getVertex(t.thirdIndex);\n\n\t\tVec3f normalVec = boxShape.getNormalVecOfTriangle(t);\n\n\t\tint side = getAbsMaxElementIndex(normalVec);\n\t\tVec3f sizes{width, height, depth};\n\n\t\tfor (std::size_t i = 0; i < 3; i++) {\n\t\t\tVec2f vec = withoutIndex(v[i], side);\n\t\t\tVec2f dim = withoutIndex(sizes, side);\n\t\t\tvec.x = (vec.x + dim.x / 2.0) / dim.x;\n\t\t\tvec.y = (vec.y + dim.y / 2.0) / dim.y;\n\t\t\tuvBuffer[ti * 3 + i] = vec;\n\t\t}\n\t}\n\n\tboxShape.setUVBuffer(SRef<const Vec2f[]>(uvBuffer));\n\n\treturn boxShape;\n}\n\nExtendedTriangleMesh createCube(float size) {\n\treturn createBox(size, size, size);\n}\n\nExtendedTriangleMesh createHexagon(float radius, float height) {\n\tExtendedTriangleMesh hexagonMesh(ShapeLibrary::createPrism(6, radius, height));\n\n\treturn hexagonMesh;\n}\n\nvoid generateCylindricalUVs(ExtendedTriangleMesh& mesh) {\n\tBoundingBox b = mesh.getBounds();\n\n\tVec2f* uvBuffer = new Vec2f[mesh.vertexCount];\n\tfor (int i = 0; i < mesh.vertexCount; i++) {\n\t\tVec3f p = mesh.getVertex(i);\n\t\tp.x /= static_cast<float>(b.getWidth());\n\t\tp.y /= static_cast<float>(b.getHeight());\n\t\tp.z /= static_cast<float>(b.getDepth());\n\n\t\tfloat phi = std::atan2(p.x, p.z);\n\t\tfloat u = phi / two_pi<float>();\n\t\tfloat v = (p.y + 1.0f) / 2.0f;\n\n\t\tuvBuffer[i] = Vec2f(u, v);\n\t}\n\n\tmesh.setUVBuffer(SRef<const Vec2f[]>(uvBuffer));\n}\n\nvoid generateSphericalUVs(ExtendedTriangleMesh& mesh) {\n\tBoundingBox b = mesh.getBounds();\n\n\tVec2f* uvBuffer = new Vec2f[mesh.vertexCount];\n\tfor (int i = 0; i < mesh.vertexCount; i++) {\n\t\tVec3f p = mesh.getVertex(i);\n\t\tp.x /= static_cast<float>(b.getWidth());\n\t\tp.y /= static_cast<float>(b.getHeight());\n\t\tp.z /= static_cast<float>(b.getDepth());\n\n\t\tfloat phi = std::atan2(p.x, p.z);\n\t\tfloat theta = std::acos(p.y);\n\t\tfloat u = phi / two_pi<float>();\n\t\tfloat v = 1.0f - theta * pi<float>();\n\n\t\tuvBuffer[i] = Vec2f(u, v);\n\t}\n\n\tmesh.setUVBuffer(SRef<const Vec2f[]>(uvBuffer));\n}\n\nvoid generateLightProbeUVs(ExtendedTriangleMesh& mesh) {\n\tBoundingBox b = mesh.getBounds();\n\n\tVec2f* uvBuffer = new Vec2f[mesh.vertexCount];\n\tfor (int i = 0; i < mesh.vertexCount; i++) {\n\t\tVec3f p = mesh.getVertex(i);\n\t\tp.x /= static_cast<float>(b.getWidth());\n\t\tp.y /= static_cast<float>(b.getHeight());\n\t\tp.z /= static_cast<float>(b.getDepth());\n\n\t\tfloat alpha = std::acos(p.z);\n\t\tfloat sinBeta = p.y / std::sqrt(p.x * p.x + p.y * p.y);\n\t\tfloat cosBeta = p.x / std::sqrt(p.x * p.x + p.y * p.y);\n\n\t\tfloat u = (1.0f + alpha / pi<float>() * cosBeta) / 2.0f;\n\t\tfloat v = (1.0f + alpha / pi<float>() * sinBeta) / 2.0f;\n\n\t\tuvBuffer[i] = Vec2f(u, v);\n\t}\n\n\tmesh.setUVBuffer(SRef<const Vec2f[]>(uvBuffer));\n}\n\nvoid init() {\n\tsphere = registerShapeClass(&SphereClass::instance, ExtendedTriangleMesh::generateSmoothNormalsShape(SphereClass::instance.asPolyhedron()));\n\tcylinder = registerShapeClass(&CylinderClass::instance, createCylinder(64, 1.0, 2.0));\n\tbox = registerShapeClass(&CubeClass::instance, createCube(2));\n\twedge = registerShapeClass(&WedgeClass::instance);\n\tcorner = registerShapeClass(&CornerClass::instance);\n\thexagon = registerShape(createHexagon(0.5, 1.0));\n\tquad = registerShape(createQuad(Vec3f(0.0f, 2.0f, 0.0f), Vec3f(0.0f, 0.0f, 1.0f), Vec2f(1.0f, 1.0f)));\n}\n\nComp::Mesh registerShape(IndexedMesh* mesh, Comp::Mesh::Flags flags) {\n\tstd::size_t id = meshes.size();\n\n\tmeshes.push_back(mesh);\n\n\treturn Comp::Mesh(id, flags);\n}\n\nComp::Mesh registerShape(const ExtendedTriangleMesh& mesh) {\n\tstd::size_t id = meshes.size();\n\n\tmeshes.push_back(new IndexedMesh(mesh));\n\n\treturn Comp::Mesh(id, mesh.getFlags());\n}\n\nComp::Mesh registerShapeClass(const ShapeClass* shapeClass, const ExtendedTriangleMesh& mesh) {\n\tComp::Mesh meshData = registerShape(mesh);\n\n\tauto iterator = shapeClassMeshIds.find(shapeClass);\n\tif (iterator != shapeClassMeshIds.end()) \n\t\titerator->second = meshData;\n\telse \n\t\tshapeClassMeshIds.emplace(shapeClass, meshData);\n\n\treturn meshData;\n}\n\nComp::Mesh registerShapeClass(const ShapeClass* shapeClass) {\n\tauto iterator = shapeClassMeshIds.find(shapeClass);\n\tif (iterator != shapeClassMeshIds.end())\n\t\treturn iterator->second;\n\n\tExtendedTriangleMesh shape = ExtendedTriangleMesh::generateSplitNormalsShape(shapeClass->asPolyhedron());\n\tgenerateSphericalUVs(shape);\n\treturn registerShapeClass(shapeClass, shape);\n}\n\nComp::Mesh getMesh(const ShapeClass* shapeClass) {\n\tauto iterator = shapeClassMeshIds.find(shapeClass);\n\n\tif (iterator != shapeClassMeshIds.end())\n\t\treturn iterator->second;\n\telse\n\t\treturn registerShapeClass(shapeClass);\n}\n\nstd::size_t getID(const ShapeClass* shapeClass) {\n\tauto iterator = shapeClassMeshIds.find(shapeClass);\n\n\tif (iterator != shapeClassMeshIds.end())\n\t\treturn iterator->second.id;\n\telse\n\t\treturn registerShapeClass(shapeClass).id;\n}\n\nIndexedMesh* get(std::size_t id) {\n\treturn meshes[id];\n}\n\nIndexedMesh* get(const Comp::Mesh& mesh) {\n\tif (mesh.id >= meshes.size())\n\t\treturn nullptr;\n\n\treturn get(mesh.id);\n}\n\nIndexedMesh* get(const ShapeClass* shapeClass) {\n\treturn get(getID(shapeClass));\n}\n\n};\n"
  },
  {
    "path": "graphics/meshRegistry.h",
    "content": "#pragma once\n\n#include \"extendedTriangleMesh.h\"\n#include \"mesh/indexedMesh.h\"\n#include <Physics3D/geometry/shapeClass.h>\n\nnamespace P3D::Graphics::MeshRegistry {\n\nextern std::vector<IndexedMesh*> meshes;\n\t\nextern std::map<const ShapeClass*, Comp::Mesh> shapeClassMeshIds;\n\nextern Comp::Mesh box;\nextern Comp::Mesh sphere;\nextern Comp::Mesh cylinder;\nextern Comp::Mesh wedge;\nextern Comp::Mesh corner;\nextern Comp::Mesh hexagon;\nextern Comp::Mesh quad;\n\nvoid init();\n\nComp::Mesh registerShape(IndexedMesh* mesh, Comp::Mesh::Flags flags);\nComp::Mesh registerShape(const ExtendedTriangleMesh& mesh);\nComp::Mesh registerShapeClass(const ShapeClass* shapeClass, const ExtendedTriangleMesh& mesh);\nComp::Mesh registerShapeClass(const ShapeClass* shapeClass);\n\nComp::Mesh getMesh(const ShapeClass* shapeClass);\nstd::size_t getID(const ShapeClass* shapeClass);\n\nIndexedMesh* get(std::size_t id);\nIndexedMesh* get(const Comp::Mesh& mesh);\nIndexedMesh* get(const ShapeClass* shapeClass);\n\nvoid generateCylindricalUVs(ExtendedTriangleMesh& mesh);\nvoid generateSphericalUVs(ExtendedTriangleMesh& mesh);\nvoid generateLightProbeUVs(ExtendedTriangleMesh& mesh);\n\nExtendedTriangleMesh createCube(float size);\nExtendedTriangleMesh createBox(float width, float height, float depth);\nExtendedTriangleMesh createSphere(double radius, int steps = 1);\nExtendedTriangleMesh createCylinder(int sides, double radius, double height);\nExtendedTriangleMesh createHexagon(float radius, float height);\n\n};\n"
  },
  {
    "path": "graphics/path/path.cpp",
    "content": "#include \"core.h\"\n\n#include \"path.h\"\n\n#include \"font.h\"\n#include <Physics3D/math/constants.h>\n#include \"../batch/guiBatch.h\"\n\n#define DEFAULT_PATTERN_2D(color) [color] (int i, const Vec2f& p) { return color; }\n\nnamespace P3D::Graphics {\n\nnamespace Path {\n\n\t#pragma region Batch\n\n\t//! Batch\n\n\tGuiBatch* batch = nullptr;\n\t\n\tvoid bind(GuiBatch* batch) {\n\t\tPath::batch = batch;\n\t}\n\n\tvoid submit() {\n\t\tif (batch)\n\t\t\tbatch->submit();\n\t}\n\n\t// Adds the vertices to the batch with the necessary indices, this does not reserve space on the batch. \n\t//? Expects vertices in counter-clockwise order\n\tvoid pushQuad(const Vec2f& a, const Vec2f& b, const Vec2f& c, const Vec2f& d, const Color& colorA = Color(1), const Color& colorB = Color(1), const Color& colorC = Color(1), const Color& colorD = Color(1), const Vec2f& uvA = Vec2f(0, 0), const Vec2f& uvB = Vec2f(1, 0), const Vec2f& uvC = Vec2f(1, 1), const Vec2f& uvD = Vec2f(0, 1)) {\n\t\tPath::batch->pushVertices({ { a, uvA, colorA }, { b, uvB, colorB }, { c, uvC, colorC }, { d, uvD, colorD } });\n\t\tPath::batch->pushIndices({ 0, 1, 2, 2, 3, 0 });\n\t\tPath::batch->endIndex();\n\t}\n\n\t// Adds the vertices to the batch with the necessary indices, this does not reserve space on the batch\n\t//? Expects vertices in counter-clockwise order\n\tvoid pushTriangle(const Vec2f& a, const Vec2f& b, const Vec2f& c, const Color& colorA = Color(1), const Color& colorB = Color(1), const Color& colorC = Color(1), const Vec2f& uvA = Vec2f(0, 0), const Vec2f& uvB = Vec2f(1, 0), const Vec2f& uvC = Vec2f(0.5, 1)) {\n\t\tPath::batch->pushVertices({ { a, uvA, colorA }, { b, uvB, colorB }, { c, uvC, colorC } });\n\t\tPath::batch->pushIndices({ 0, 1, 2 });\n\t\tPath::batch->endIndex();\n\t}\n\n\t// Adds the vertices to the batch with the necessary indices, this does not reserve space on the batch\n\tvoid pushLine(const Vec2f& a, const Vec2f& b, const Color& colorA, const Color& colorB, float thickness) {\n\t\tVec2f dxy = normalize(Vec2f(b.y - a.y, a.x - b.x)) / GUI::windowInfo.dimension.y * 3.0 * thickness;\n\n\t\tpushQuad(Vec2f(a + dxy), Vec2f(b + dxy), Vec2f(b - dxy), Vec2f(a - dxy), colorA, colorB, colorB, colorA);\n\t}\n\n\t#pragma endregion\n\n\t#pragma region Primitives\n\n\t//! Primitives\n\n\tvoid line(const Vec2f& a, const Vec2f& b, const Color& color, float thickness) {\n\t\tline(a, b, color, color, thickness);\n\t}\n\n\tvoid line(const Vec2f& a, const Vec2f& b, const Color& colorA, const Color& colorB, float thickness) {\n\t\tsize_t vertexCount = 4;\n\t\tsize_t indexCount = 6;\n\t\tPath::batch->reserve(vertexCount, indexCount);\n\n\t\tpushLine(a, b, colorA, colorB, thickness);\n\t}\n\n\tvoid circle(const Vec2f& center, float radius, const Color& color, float thickness, size_t precision) {\n\t\tsize_t vertexCount = 4 * precision;\n\t\tsize_t indexCount = 6 * precision;\n\t\tPath::batch->reserve(vertexCount, indexCount);\n\n\t\tVec2f oldPoint = center + Vec2f(radius, 0);\n\t\tfloat step = 2.0 * PI / (float) precision;\n\t\tfor (size_t i = 1; i <= precision; i++) {\n\t\t\tfloat angle = i * step;\n\n\t\t\tVec2f newPoint = Vec2f(center.x + radius * cos(angle), center.y + radius * sin(angle));\n\n\t\t\tpushLine(oldPoint, newPoint, color, color, thickness);\n\n\t\t\toldPoint = newPoint;\n\t\t}\n\t}\n\n\tvoid circleFilled(const Vec2f& center, float radius, const Color& color, size_t precision) {\n\t\tsize_t vertexCount = precision;\n\t\tsize_t indexCount = 3 * (precision - 2);\n\t\tPath::batch->reserve(vertexCount, indexCount);\n\t\t\t\t\n\t\tfloat step = 2.0f * PI / (float) precision;\n\t\tfor (size_t i = 0; i < precision; i++) {\n\t\t\tfloat angle = i * step;\n\n\t\t\tVec2f point = Vec2f(center.x + radius * cos(angle), center.y + radius * sin(angle));\n\t\t\tPath::batch->pushVertex({ point, Vec2(1.0, 1.0), color });\n\t\t}\n\n\t\tfor (size_t i = 1; i < precision - 1; i++)\n\t\t\tPath::batch->pushIndices({ 0, i + 1, i });\n\n\t\tPath::batch->endIndex();\n\t}\n\n\tvoid circleSegment(const Vec2f& center, float radius, float minAngle, float maxAngle, bool sides, const Color& color, float thickness, size_t precision) {\n\t\tsize_t vertexCount = 4 * (precision + (sides? 2 : 0));\n\t\tsize_t indexCount = 6 * (precision + (sides? 2 : 0));\n\t\tPath::batch->reserve(vertexCount, indexCount);\n\t\t\n\t\tVec2f oldPoint = Vec2f(center.x + radius * cos(minAngle), center.y + radius * sin(minAngle));\n\t\t\n\t\tif (sides)\n\t\t\tpushLine(center, oldPoint, color, color, thickness);\n\n\t\tfloat step = (maxAngle - minAngle) / (float)precision;\n\t\tfor (size_t i = 1; i <= precision; i++) {\n\t\t\tfloat angle = minAngle + i * step;\n\n\t\t\tVec2f newPoint = Vec2f(center.x + radius * cos(angle), center.y + radius * sin(angle));\n\n\t\t\tpushLine(oldPoint, newPoint, color, color, thickness);\n\n\t\t\toldPoint = newPoint;\n\t\t}\n\n\t\tif (sides)\n\t\t\tpushLine(center, oldPoint, color, color, thickness);\n\t}\n\n\tvoid circleSegmentFilled(const Vec2f& center, float radius, float minAngle, float maxAngle, const Color& color, size_t precision) {\n\t\tsize_t vertexCount = precision + 2;\n\t\tsize_t indexCount = 3 * precision;\n\t\tPath::batch->reserve(vertexCount, indexCount);\n\t\t\n\t\tVec2f oldPoint = Vec2f(center.x + radius * cos(minAngle), center.y + radius * sin(minAngle));\n\t\t\n\t\tPath::batch->pushVertex({ center, Vec2f(1.0f, 1.0f), color });\n\t\tPath::batch->pushVertex({ oldPoint, Vec2f(1.0f, 1.0f), color });\n\n\t\tfloat step = (maxAngle - minAngle) / (float) precision;\n\t\tfor (size_t i = 1; i <= precision; i++) {\n\t\t\tfloat angle = minAngle + i * step;\n\n\t\t\tVec2f newPoint = Vec2f(center.x + radius * cos(angle), center.y + radius * sin(angle));\n\n\t\t\tPath::batch->pushVertex({ newPoint, Vec2(1.0, 1.0), color });\n\t\t}\n\n\t\tfor (size_t i = 1; i <= precision + 1; i++)\n\t\t\tPath::batch->pushIndices({ 0, i + 1, i });\n\t\t\n\t\tPath::batch->endIndex();\n\t}\n\n\tvoid triangle(const Vec2f& a, const Vec2f& b, const Vec2f& c, const Color& color, float thickness) {\n\t\tsize_t vertexCount = 4 * 3;\n\t\tsize_t indexCount = 6 * 3;\n\t\tPath::batch->reserve(vertexCount, indexCount);\n\n\t\tpushLine(a, b, color, color, thickness);\n\t\tpushLine(b, c, color, color, thickness);\n\t\tpushLine(c, a, color, color, thickness);\n\t}\n\n\tvoid triangleFilled(const Vec2f& a, const Vec2f& b, const Vec2f& c, const Color& color) {\n\t\tsize_t vertexCount = 3;\n\t\tsize_t indexCount = 3;\n\t\tPath::batch->reserve(vertexCount, indexCount);\n\n\t\tpushTriangle(a, b, c, color, color, color);\n\t}\n\n\tvoid rect(const Vec2f& pos, const Vec2f& dim, float rounding, const Color& color, float thickness) {\n\t\t//if (rounding == 0.0) {\n\t\t\tquad(pos, pos + Vec2f(dim.x, 0), pos + Vec2f(dim.x, dim.y), pos + Vec2f(0, dim.y), color, thickness);\n\t\t//}\n\t\t// TODO add rounding\n\t}\n\n\tvoid rectFilled(const Vec2f& pos, const Vec2f& dim, float rounding, const Color& color) {\n\t\t//if (rounding == 0) {\n\t\t\tsize_t vertexCount = 4;\n\t\t\tsize_t indexCount = 6;\n\t\t\tPath::batch->reserve(vertexCount, indexCount);\n\n\t\t\tpushQuad(pos, pos + Vec2f(dim.x, 0), pos + Vec2f(dim.x, dim.y), pos + Vec2f(0, dim.y), color, color, color, color);\n\t\t//}\n\t\t// TODO add rounding\n\t}\n\n\tvoid rectUV(GLID id, const Vec2f& pos, const Vec2f& dim, const Vec2f& uvMin, const Vec2f& uvMax, const Color& color) {\n\t\tsize_t vertexCount = 4;\n\t\tsize_t indexCount = 6;\n\n\t\tVec2f a = pos;\n\t\tVec2f b = Vec2f(pos.x + dim.x, pos.y);\n\t\tVec2f c = Vec2f(pos.x + dim.x, pos.y + dim.y);\n\t\tVec2f d = Vec2f(pos.x, pos.y + dim.y);\n\t\tVec2f uvA = uvMin;\n\t\tVec2f uvB = Vec2f(uvMax.x, uvMin.y);\n\t\tVec2f uvC = uvMax;\n\t\tVec2f uvD = Vec2f(uvMin.x, uvMax.y);\n\n\t\tPath::batch->pushCommand(0);\n\t\tPath::batch->reserve(vertexCount, indexCount);\n\t\tpushQuad(a, b, c, d, color, color, color, color, uvA, uvB, uvC, uvD);\n\t\tPath::batch->pushCommand(id);\n\t}\n\n\tvoid rectUVRange(GLID id, const Vec2f& pos, const Vec2f& dim, const Vec2f& xRange, const Vec2f& yRange, const Color& color) {\n\t\tsize_t vertexCount = 4;\n\t\tsize_t indexCount = 6;\n\t\t\n\t\tfloat dx = xRange.y - xRange.x;\n\t\tfloat dy = yRange.y - yRange.x;\n\n\t\tfloat u = (pos.x - xRange.x) / dx;\n\t\tfloat v = (pos.y - dim.y - yRange.x) / dy;\n\t\tfloat du = dim.x / dx;\n\t\tfloat dv = dim.y / dy;\n\n\t\tVec2f a = pos;\n\t\tVec2f b = Vec2f(pos.x + dim.x, pos.y);\n\t\tVec2f c = Vec2f(pos.x + dim.x, pos.y - dim.y);\n\t\tVec2f d = Vec2f(pos.x, pos.y - dim.y);\n\t\tVec2f uvA = Vec2f(u, v + dv);\n\t\tVec2f uvB = Vec2f(u + du, v + dv);\n\t\tVec2f uvC = Vec2f(u + du, v);\n\t\tVec2f uvD = Vec2f(u, v);\n\n\t\tPath::batch->pushCommand(0);\n\t\tPath::batch->reserve(vertexCount, indexCount);\n\t\tpushQuad(a, b, c, d, color, color, color, color, uvA, uvB, uvC, uvD);\n\t\tPath::batch->pushCommand(id);\n\t}\n\n\tvoid quad(const Vec2f& a, const Vec2f& b, const Vec2f& c, const Vec2f& d, const Color& color, float thickness) {\n\t\tsize_t vertexCount = 4 * 4;\n\t\tsize_t indexCount = 6 * 4;\n\t\tPath::batch->reserve(vertexCount, indexCount);\n\n\t\tpushLine(a, b, color, color, thickness);\n\t\tpushLine(b, c, color, color, thickness);\n\t\tpushLine(c, d, color, color, thickness);\n\t\tpushLine(d, a, color, color, thickness);\n\t}\n\n\tvoid quadFilled(const Vec2f& a, const Vec2f& b, const Vec2f& c, const Vec2f& d, const Color& color) {\n\t\tsize_t vertexCount = 4;\n\t\tsize_t indexCount = 6;\n\t\tPath::batch->reserve(vertexCount, indexCount);\n\n\t\tpushQuad(a, b, c, d, color, color, color, color);\n\t}\n\n\tvoid quadUV(GLID id, const Vec2f& a, const Vec2f& b, const Vec2f& c, const Vec2f& d, const Vec2f& uvA, const Vec2f& uvB, const Vec2f& uvC, const Vec2f& uvD) {\n\t\tsize_t vertexCount = 4;\n\t\tsize_t indexCount = 6;\n\t\tPath::batch->pushCommand(0); \n\t\tPath::batch->reserve(vertexCount, indexCount);\n\t\tpushQuad(a, b, c, d, Color(1), Color(1), Color(1), Color(1), uvA, uvB, uvC, uvD);\n\t\tPath::batch->pushCommand(id);\n\t}\n\n\tvoid text(Font* font, const std::string& text, double size, const Vec2f& pos, const Color& color, char textPivot) {\n\t\tif (text.empty())\n\t\t\treturn;\n\n\t\tsize_t vertexCount = 4 * text.size();\n\t\tsize_t indexCount = 6 * text.size();\n\t\tVec2f textSize = font->size(text, size);\n\n\t\t// TextPivotHL default\n\t\tfloat x = pos.x;\n\n\t\t// TextPivotVB default\n\t\tfloat y = pos.y;\n\n\t\tif (textPivot & TextPivotHC)\n\t\t\tx -= textSize.x / 2.0f;\n\n\t\tif (textPivot & TextPivotHR)\n\t\t\tx -= textSize.x;\n\n\t\tif (textPivot & TextPivotVT)\n\t\t\ty -= textSize.y;\n\n\t\tif (textPivot & TextPivotVC)\n\t\t\ty -= textSize.y / 2.0f;\n\n\t\tPath::batch->pushCommand(0);\n\t\tPath::batch->reserve(vertexCount, indexCount);\n\t\tfor (char chr : text) {\n\t\t\tint ascii = (int) chr;\n\t\t\tconst Character& character = font->getCharacter(ascii);\n\t\t\tfloat descend = character.height - character.by;\n\t\t\tfloat xpos = x + character.bx * size;\n\t\t\tfloat ypos = y - descend * size;\n\n\t\t\tfloat w = character.width * size;\n\t\t\tfloat h = character.height * size;\n\n\t\t\tfloat s = float(character.x) / font->getAtlasWidth();\n\t\t\tfloat t = float(character.y) / font->getAtlasHeight();\n\t\t\tfloat ds = float(character.width) / font->getAtlasWidth();\n\t\t\tfloat dt = float(character.height) / font->getAtlasHeight();\n\n\t\t\tVec2f a = Vec2f(xpos, ypos);\n\t\t\tVec2f b = Vec2f(xpos + w, ypos);\n\t\t\tVec2f c = Vec2f(xpos + w, ypos + h);\n\t\t\tVec2f d = Vec2f(xpos, ypos + h);\n\t\t\tVec2f uvA = Vec2f(s, t + dt);\n\t\t\tVec2f uvB = Vec2f(s + ds, t + dt);\n\t\t\tVec2f uvC = Vec2f(s + ds, t);\n\t\t\tVec2f uvD = Vec2f(s, t);\n\n\t\t\tpushQuad(a, b, c, d, color, color, color, color, uvA, uvB, uvC, uvD);\n\n\t\t\tx += (character.advance >> 6) * size;\n\t\t}\n\n\t\tPath::batch->pushCommand(font->getAtlasID());\n\t}\n\n\tvoid bezier(const Vec2f& a, const Vec2f& b, const Vec2f& c, const Vec2f& d, const Color& color, float thickness, size_t precision) {\n\t\tbezier(a, b, c, d, DEFAULT_PATTERN_2D(color), thickness, precision);\n\t}\n\n\tvoid bezier(const Vec2f& a, const Vec2f& b, const Vec2f& c, const Vec2f& d, Pattern2D pattern, float thickness, size_t precision) {\n\t\tsize_t vertexCount = 4 * precision;\n\t\tsize_t indexCount = 6 * precision;\n\t\tPath::batch->reserve(vertexCount, indexCount);\n\n\t\tVec2f oldPoint = a;\n\t\tColor oldColor = pattern(0, oldPoint);\n\t\tfloat step = 1.0f / (float)precision;\n\t\tfor (size_t i = 1; i <= precision; i++) {\n\t\t\tfloat t = i * step;\n\t\t\tfloat s = 1 - t;\n\n\t\t\tfloat w1 = s * s * s;\n\t\t\tfloat w2 = 3.0f * s * s * t;\n\t\t\tfloat w3 = 3.0f * s * t * t;\n\t\t\tfloat w4 = t * t * t;\n\n\t\t\tVec2f newPoint = w1 * a + w2 * b + w3 * c + w4 * d;\n\t\t\tColor newColor = pattern(i, newPoint);\n\t\t\tpushLine(oldPoint, newPoint, oldColor, newColor, thickness);\n\n\t\t\toldPoint = newPoint;\n\t\t\toldColor = newColor;\n\t\t}\n\t}\n\n\tvoid bezierHorizontal(const Vec2f& start, const Vec2f& end, const Color& color, float thickness, size_t precision) {\n\t\tbezierHorizontal(start, end, DEFAULT_PATTERN_2D(color), thickness, precision);\n\t}\n\n\tvoid bezierHorizontal(const Vec2f& start, const Vec2f& end, Pattern2D pattern, float thickness, size_t precision) {\n\t\tfloat mid = (start.x + end.x) / 2.0f;\n\t\tVec2f c1 = Vec2f(mid, start.y);\n\t\tVec2f c2 = Vec2f(mid, end.y);\n\t\tbezier(start, c1, c2, end, pattern, thickness, precision);\n\t}\n\n\tvoid bezierVertical(const Vec2f& start, const Vec2f& end, const Color& color, float thickness, size_t precision) {\n\t\tbezierVertical(start, end, DEFAULT_PATTERN_2D(color), thickness, precision);\n\t}\n\n\tvoid bezierVertical(const Vec2f& start, const Vec2f& end, Pattern2D pattern, float thickness, size_t precision) {\n\t\tfloat mid = (start.y + end.y) / 2.0f;\n\t\tVec2f c1 = Vec2f(start.x, mid);\n\t\tVec2f c2 = Vec2f(end.x, mid);\n\t\tbezier(start, c1, c2, end, pattern, thickness, precision);\n\t}\n\n\tvoid polyLine(Vec2f* points, size_t size, const Color& color, float thickness, bool closed) {\n\t\tpolyLine(points, size, DEFAULT_PATTERN_2D(color), thickness, closed);\n\t}\n\n\tvoid polyLine(Vec2f* points, size_t size, Pattern2D pattern, float thickness, bool closed) {\n\t\tif (size == 0)\n\t\t\treturn; \n\n\t\tif (size == 1)\n\t\t\treturn; // Points not supported yet\n\n\t\tsize_t vertexCount = 4 * (size - (closed? 0 : 1));\n\t\tsize_t indexCount = 6 * (size - (closed ? 0 : 1));\n\n\t\tPath::batch->reserve(vertexCount, indexCount);\n\n\t\tColor oldColor = pattern(0, points[0]);\n\t\tfor (size_t i = 0; i < size - 1; i++) {\n\t\t\tColor newColor = pattern(i + 1, points[i + 1]);\n\t\t\tpushLine(points[i], points[i + 1], oldColor, newColor, thickness);\n\t\t\toldColor = newColor;\n\t\t}\n\t\t\n\t\tif (closed)\n\t\t\tpushLine(points[size - 1], points[0], oldColor, pattern(0, points[0]), thickness);\n\t}\n\n\tvoid polygonFilled(Vec2f* points, size_t size, const Color& color) {\n\t\tpolygonFilled(points, size, DEFAULT_PATTERN_2D(color));\n\t}\n\n\tvoid polygonFilled(Vec2f* points, size_t size, Pattern2D pattern) {\n\t\tif (size == 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (size == 1) {\n\t\t\t// point not supported\n\t\t\treturn;\n\t\t}\n\n\t\tif (size == 2) {\n\t\t\tline(points[0], points[1], pattern(0, points[0]), pattern(1, points[1]), 1.0f);\n\t\t\treturn;\n\t\t}\n\n\t\tsize_t vertexCount = size;\n\t\tsize_t indexCount = 3 * (size - 2);\n\n\t\tPath::batch->reserve(vertexCount, indexCount);\n\n\t\tfor (size_t i = 0; i < size; i++)\n\t\t\tPath::batch->pushVertex({ points[i], Vec2f(1.0f, 1.0f), pattern(i, points[i]) });\n\n\t\tfor (size_t i = 0; i < size - 2; i++)\n\t\t\tPath::batch->pushIndices({ 0, i + 1, i + 2 });\n\n\t\tPath::batch->endIndex();\n\t}\n\t\n\tvoid catmullRom(Vec2f* points, size_t size, const Color& color, int precision, float thickness, bool closed, float tension, float alpha) {\n\t\tcatmullRom(points, size, DEFAULT_PATTERN_2D(color), precision, thickness, closed, tension, alpha);\n\t}\n\n\tvoid catmullRom(Vec2f* points, size_t size, Pattern2D pattern, int precision, float thickness, bool closed, float tension, float alpha) {\n\t\t// Checks\n\t\tif (tension == 1.0f)\n\t\t\tpolyLine(points, size, pattern, thickness, closed);\n\n\t\tif (size == 0)\n\t\t\treturn;\n\n\t\tif (size == 1)\n\t\t\treturn; // Points not supported yet\n\n\t\tif (size == 2)\n\t\t\tline(points[0], points[1], pattern(0, points[0]), pattern(1, points[1]), 1.0f);\n\n\n\t\t// Build lists\n\t\tVec2f* pList = (Vec2f*) alloca((size + 1) * sizeof(Vec2f));\n\t\tfloat* tList = (float*) alloca((size + 1) * sizeof(float));\n\n\t\tVec2 start = points[0] * 2 - points[1];\n\t\tVec2 end = points[size - 1] * 2 - points[size - 2];\n\t\tfloat alpha2 = alpha / 2.0f;\n\n\t\tpList[0] = points[0] - start;\n\t\ttList[0] = pow(lengthSquared(pList[0]), alpha2);\n\n\t\tfor (size_t i = 1; i < size; i++) {\n\t\t\tpList[i] = points[i] - points[i - 1];\n\t\t\ttList[i] = pow(lengthSquared(pList[i]), alpha2);\n\t\t}\n\n\t\tpList[size] = end - points[size - 1];\n\t\ttList[size] = pow(lengthSquared(pList[size]), alpha2);\n\n\n\t\t// Reserve vertices\n\t\tsize_t vertexCount = 4 * size * precision;\n\t\tsize_t indexCount = 6 * size * precision;\n\n\t\tPath::batch->reserve(vertexCount, indexCount);\n\n\t\tfloat s = 1.0f - tension;\n\t\tfloat step = 1.0f / (float)precision;\n\n\t\tfor (size_t i = 1; i < size; i++) {\n\t\t\t// Calculate segment\n\t\t\tfloat t012 = tList[i - 1] + tList[i];\n\t\t\tVec2f p20 = pList[i - 1] + pList[i];\n\n\t\t\tfloat t123 = tList[i] + tList[i + 1];\n\t\t\tVec2f p31 = pList[i] + pList[i + 1];\n\n\t\t\tVec2f m1 = s * (pList[i] + tList[i] * (pList[i - 1] /  tList[i - 1] - p20 / t012));\n\t\t\tVec2f m2 = s * (pList[i] + tList[i] * (pList[i + 1] / tList[i + 1] - p31 / t123));\n\n\t\t\tVec2f a = -2.0f * pList[i] + m1 + m2;\n\t\t\tVec2f b = 3.0f * pList[i] - m1 - m1 - m2;\n\t\t\tVec2f c = m1;\n\t\t\tVec2f d = points[i - 1];\n\t\t\t\n\t\t\t// Split segment\n\t\t\tVec2f oldPoint = d;\n\t\t\tColor oldColor = pattern((i - 1) * precision, oldPoint);\n\t\t\tfor (size_t j = 1; j <= precision; j++) {\n\t\t\t\tfloat t = j * step;\n\t\t\t\tfloat w4 = 1.0f;\n\t\t\t\tfloat w3 = w4 * t;\n\t\t\t\tfloat w2 = w3 * t;\n\t\t\t\tfloat w1 = w2 * t;\n\n\t\t\t\tVec2f newPoint = a * w1 + b * w2 + c * w3 + d * w4;\n\t\t\t\tColor newColor = pattern((i - 1) * precision + j, newPoint);\n\n\t\t\t\tpushLine(oldPoint, newPoint, oldColor, newColor, thickness);\n\n\t\t\t\toldPoint = newPoint;\n\t\t\t\toldColor = newColor;\n\t\t\t}\n\t\t}\n\t}\n\n\t#pragma endregion\n\n\t#pragma region Path\n\n\t//! Path\n\n\tstd::vector<Vec2f> path;\n\n\tvoid lineTo(const Vec2f& vertex) {\n\t\tpath.push_back(vertex);\n\t}\n\n\tvoid arcTo(const Vec2f& center, float radius, float minAngle, float maxAngle, size_t precision) {\n\t\tif (precision == 0 || radius == 0.0f) {\n\t\t\tpath.push_back(center);\n\t\t\treturn;\n\t\t}\n\n\t\tpath.reserve(path.size() + precision + 1);\n\n\t\tfor (size_t i = 0; i <= precision; i++) {\n\t\t\tfloat angle = minAngle + ((float)i / (float)precision) * (maxAngle - minAngle);\n\t\t\tpath.push_back(Vec2f(center.x + radius * cos(angle), center.y + radius * sin(angle)));\n\t\t}\n\t}\n\n\tvoid bezierTo(const Vec2f& end, const Vec2f& tc1, const Vec2f& tc2, size_t precision) {\n\t\tVec2f start = path.back();\n\n\t\tfloat step = 1.0f / (float)precision;\n\t\tfor (int i = 1; i <= precision; i++) {\n\t\t\tfloat t = i * step;\n\t\t\tfloat s = 1 - t;\n\n\t\t\tfloat w1 = s * s * s;\n\t\t\tfloat w2 = 3.0f * s * s * t;\n\t\t\tfloat w3 = 3.0f * s * t * t;\n\t\t\tfloat w4 = t * t * t;\n\n\t\t\tpath.push_back(w1 * start + w2 * tc1 + w3 * tc2 + w4 * end);\n\t\t}\n\t}\n\n\tvoid bezierTo(const Vec2f& end, size_t precision) {\n\t\tVec2f start = path.back();\n\n\t\tfloat mid = (start.y + end.y) / 2.0f;\n\t\tVec2f c1 = Vec2f(start.x, mid);\n\t\tVec2f c2 = Vec2f(end.x, mid);\n\n\t\tbezierTo(end, c1, c2, precision);\n\t}\n\n\tvoid stroke(const Color& color, float thickness, bool closed) {\n\t\tstroke(DEFAULT_PATTERN_2D(color), thickness, closed);\n\t}\n\n\tvoid stroke(Pattern2D pattern, float thickness, bool closed) {\n\t\tpolyLine(path.data(), path.size(), pattern, thickness, closed);\n\n\t\tclear();\n\t}\n\n\tvoid fill(const Color& color) {\n\t\tfill(DEFAULT_PATTERN_2D(color));\n\t}\n\n\tvoid fill(Pattern2D pattern) {\n\t\tpolygonFilled(path.data(), path.size(), pattern);\n\n\t\tclear();\n\t}\n\n\tint size() {\n\t\treturn path.size();\n\t}\n\n\tvoid clear() {\n\t\tpath.clear();\n\t}\n\n\t#pragma endregion\n\n}\n\n};"
  },
  {
    "path": "graphics/path/path.h",
    "content": "#pragma once\n\n#include \"../gui/gui.h\"\n\n#define DEFAULT_SCISSOR Vec4f(0, 0, GUI::windowInfo.dimension.x, GUI::windowInfo.dimension.y);\n\nnamespace P3D::Graphics {\n\nnamespace Path {\n\n\t//! Pattern\n\n\ttypedef std::function<Color(int, const Vec2f&)> Pattern2D;\n\n\n\t//! Flags\n\n\tenum TextFlags : char {\n\t\t// Align text pivot horizontal left\n\t\tTextPivotHL = 1 << 0,\n\n\t\t// Align text pivot horizontal centered\n\t\tTextPivotHC = 1 << 1,\n\n\t\t// Align text pivot horizontal right\n\t\tTextPivotHR = 1 << 2,\n\n\t\t// Align text pivot vertical top\n\t\tTextPivotVT = 1 << 3,\n\n\t\t// Align text pivot vertical centered\n\t\tTextPivotVC = 1 << 4,\n\n\t\t// Align text pivot vertical bottom\n\t\tTextPivotVB = 1 << 5\n\t};\t\t\t\t\t  \n\n\n\t//! Batch\n\n\t// Current batch\n\textern GuiBatch* batch;\n\n\t// Binds the given batch\n\tvoid bind(GuiBatch* batch);\n\n\t// Submits the current batch\n\tvoid submit();\n\n\t//! Primitives\n\n\t// Adds a line to the batch\n\tvoid line(const Vec2f& a, const Vec2f& b, const Color& color = Colors::WHITE, float thickness = 1.0f);\n\n\t// Adds a line to the batch\n\tvoid line(const Vec2f& a, const Vec2f& b, const Color& colorA = Colors::WHITE, const Color& colorB = Colors::WHITE, float thickness = 1.0f);\n\n\t// Adds a circle to the the batch\n\tvoid circle(const Vec2f& center, float radius, const Color& color = Colors::WHITE, float thickness = 1.0f, size_t precision = 20);\n\n\t// Adds a filled circle to the batch\n\tvoid circleFilled(const Vec2f& center, float radius, const Color& color = Colors::WHITE, size_t precision = 20);\n\n\t// Adds a circle tott the batch\n\tvoid circleSegment(const Vec2f& center, float radius, float minAngle, float maxAngle, bool sides, const Color& color = Colors::WHITE, float thickness = 1.0f, size_t precision = 20);\n\n\t// Adds a filled circle to the batch\n\tvoid circleSegmentFilled(const Vec2f& center, float radius, float minAngle, float maxAngle, const Color& color = Colors::WHITE, size_t precision = 20);\n\n\t// Adds a triangle to the batch\n\tvoid triangle(const Vec2f& a, const Vec2f& b, const Vec2f& c, const Color& color = Colors::WHITE, float thickness = 1.0f);\n\n\t// Adds a filled triangle to the batch\n\tvoid triangleFilled(const Vec2f& a, const Vec2f& b, const Vec2f& c, const Color& color = Colors::WHITE);\n\n\t// Adds a rectangle to the batch, with pos being the bottomleft corner and dim the dimension\n\tvoid rect(const Vec2f& pos = Vec2f(0, 0), const Vec2f& dim = Vec2f(1, 1), float rounding = 0.0f, const Color& color = Colors::WHITE, float thickness = 1.0f);\n\n\t// Adds a filled rectangle to the batch, with pos being the bottomleft corner and dim the dimension\n\tvoid rectFilled(const Vec2f& pos = Vec2f(0, 0), const Vec2f& dim = Vec2f(1, 1), float rounding = 0.0f, const Color& color = Colors::WHITE);\n\n\t//? Adds a rect with UV coordinates and a texture id to the batch, with pos being the topleft corner and dim the dimension, uvMin starts default at lower left, uvMax at upper right\n\tvoid rectUV(GLID id, const Vec2f& pos = Vec2f(0, 0), const Vec2f& dim = Vec2f(1, 1), const Vec2f& uvMin = Vec2f(0, 0), const Vec2f& uvMax = Vec2f(1, 1), const Color& color = Colors::WHITE);\n\n\t//  Adds a rect with an UV range and a texture id to the batch, with pos being the bottomleft corner and dim the dimension\n\tvoid rectUVRange(GLID id, const Vec2f& pos, const Vec2f& dim, const Vec2f& xRange, const Vec2f& yRange, const Color& color = Colors::WHITE);\n\n\t// Adds a quad to the batch\n\tvoid quad(const Vec2f& a = Vec2f(0, 0), const Vec2f& b = Vec2f(1, 0), const Vec2f& c = Vec2f(1, 1), const Vec2f& d = Vec2f(0, 1), const Color& color = Colors::WHITE, float thickness = 1.0f);\n\n\t// Adds a filled quad to the batch\n\tvoid quadFilled(const Vec2f& a = Vec2f(0, 0), const Vec2f& b = Vec2f(1, 0), const Vec2f& c = Vec2f(1, 1), const Vec2f& d = Vec2f(0, 1), const Color& color = Colors::WHITE);\n\n\t//? Adds a quad with UV coordinates and a texture id to the batch, default starting at the upper left corner and going counter-clockwise\n\tvoid quadUV(GLID id, const Vec2f& a = Vec2f(0, 0), const Vec2f& b = Vec2f(1, 0), const Vec2f& c = Vec2f(1, 1), const Vec2f& d = Vec2f(0, 1), const Vec2f& uvA = Vec2f(0, 0), const Vec2f& uvB = Vec2f(1, 0), const Vec2f& uvC = Vec2f(1, 1), const Vec2f& uvD = Vec2f(0, 1));\n\n\t// Adds a string to the batch with the given font\n\tvoid text(Font* font, const std::string& text, double size, const Vec2f& pos, const Color& color = Colors::WHITE, char textPivot = TextPivotHL | TextPivotVB);\n\n\t// Adds a bezier curve to the batch, with the given control points\n\tvoid bezier(const Vec2f& a, const Vec2f& b, const Vec2f& c, const Vec2f& d, const Color& color = Colors::WHITE, float thickness = 1.0f, size_t precision = 20);\n\n\t// Adds a bezier curve to the batch, with the given control points\n\tvoid bezier(const Vec2f& a, const Vec2f& b, const Vec2f& c, const Vec2f& d, Pattern2D pattern, float thickness = 1.0f, size_t precision = 20);\n\n\t// Adds a horizontal oriented bezier curve to the batch, with the given start and end\n\tvoid bezierHorizontal(const Vec2f& start, const Vec2f& end, const Color& color = Colors::WHITE, float thickness = 1.0f, size_t precision = 20);\n\n\t// Adds a horizontal oriented bezier curve to the batch, with the given start and end\n\tvoid bezierHorizontal(const Vec2f& start, const Vec2f& end, Pattern2D pattern, float thickness = 1.0f, size_t precision = 20);\n\n\t// Adds a vertical oriented bezier curve to the batch, with the given start and end\n\tvoid bezierVertical(const Vec2f& start, const Vec2f& end, const Color& color = Colors::WHITE, float thickness = 1.0f, size_t precision = 20);\n\n\t// Adds a vertical oriented bezier curve to the batch, with the given start and end\n\tvoid bezierVertical(const Vec2f& start, const Vec2f& end, Pattern2D pattern, float thickness = 1.0f, size_t precision = 20);\n\n\t// Adds a polyline to the batch, through the given points\n\tvoid polyLine(Vec2f* points, size_t size, const Color& color = Colors::WHITE, float thickness = 1.0f, bool closed = false);\n\n\t// Adds a polyline to the batch, through the given points\n\tvoid polyLine(Vec2f* points, size_t size, Pattern2D pattern, float thickness = 1.0f, bool closed = false);\n\n\t// Adds a polygon to the batch, with the given points\n\tvoid polygonFilled(Vec2f* points, size_t size, const Color& color = Colors::WHITE);\n\n\t// Adds a polygon to the batch, with the given points\n\tvoid polygonFilled(Vec2f* points, size_t size, Pattern2D pattern);\n\n\t// Adds an Catmull-Rom spline to batch, interpolating the given control points\n\tvoid catmullRom(Vec2f* points, size_t size, const Color& color = Colors::WHITE, int precision = 20, float thickness = 1.0f, bool closed = false, float tension = 0.0f, float alpha = 0.5f);\n\n\t// Adds an Catmull-Rom spline to batch, interpolating the given control points\n\tvoid catmullRom(Vec2f* points, size_t size, Pattern2D pattern, int precision = 20, float thickness = 1.0f, bool closed = false, float tension = 0.0f, float alpha = 0.5f);\n\t\n\n\t//! Polygon building\n\n\t// Adds a vertex to the current path\n\tvoid lineTo(const Vec2f& vertex);\n\n\t// Adds and arc around the given center to the path\n\tvoid arcTo(const Vec2f& center, float radius, float minAngle, float maxAngle, size_t precision = 20);\n\n\t// Adds a bezier curve to the path with the given tangent control points, starting from the last point in the path\n\tvoid bezierTo(const Vec2f& end, const Vec2f& tc1, const Vec2f& tc2, size_t precision = 20);\n\n\t// Adds a bezier curve to the path, starting from the last point in the path\n\tvoid bezierTo(const Vec2f& end, size_t precision = 20);\n\n\t// Fills the convex polygon defined by the current path\n\tvoid fill(const Color& color = Colors::WHITE);\n\n\t// Fills the convex polygon defined by the current path\n\tvoid fill(Pattern2D pattern);\n\n\t// Draws the current path\n\tvoid stroke(const Color& color = Colors::WHITE, float thickness = 1.0f, bool closed = false);\n\t\n\t// Draws the current path\n\tvoid stroke(Pattern2D pattern, float thickness = 1.0f, bool closed = false);\n\n\t// Return the amount of vertices in the path\n\tint size();\n\n\t// Removes all vertices from the path\n\tvoid clear();\n}\n\n};"
  },
  {
    "path": "graphics/path/path3D.cpp",
    "content": "#include \"core.h\"\n\n#include \"path3D.h\"\n#include <Physics3D/math/constants.h>\n\n#define DEFAULT_PATTERN_3D(color) [color] (int i, const Vec3f& p) { return color; }\n\nnamespace P3D::Graphics {\n\nnamespace Path3D {\n\n\t//! Batch\n\n\tGraphics::Batch<Vertex>* batch = nullptr;\n\n\tvoid bind(Graphics::Batch<Vertex>* batch) {\n\t\tPath3D::batch = batch;\n\t}\n\n\n\t//! Primitives\n\n\tvoid line(const Vec3f& a, const Vec3f& b, const Color& colorA, const Color& colorB, float thickness) {\n\t\tsize_t vertexCount = 4;\n\t\tsize_t indexCount = 6;\n\t\tPath3D::batch->reserve(vertexCount, indexCount);\n\n\t\tPath3D::batch->pushVertices({ { a, colorA }, { b, colorB } });\n\t\tPath3D::batch->pushIndices({ 0, 1 });\n\n\t\tPath3D::batch->endIndex();\n\t}\n\n\tvoid circle(const Vec3f& center, float radius, const Vec3f& normal, float thickness, const Color& color, size_t precision) {\n\t\tVec3f n = normalize(normal);\n\t\tVec3f u = Vec3f(n.y, -n.x, 0);\n\n\t\tif (lengthSquared(u) == 0)\n\t\t\tu = Vec3f(n.z, 0, -n.x);\n\t\n\t\tu = normalize(u);\n\t\tVec3f v = n % u;\n\n\t\tsize_t vertexCount = precision;\n\t\tsize_t indexCount = 2 * precision;\n\n\t\tPath3D::batch->reserve(vertexCount, indexCount);\n\t\tVec3f point = center + radius * u;\n\t\tPath3D::batch->pushVertex({ point, color });\n\n\t\tfloat step = 2.0 * PI / (float) precision;\n\t\tfor (size_t i = 1; i < precision; i++) {\n\t\t\tfloat angle = i * step;\n\t\t\tpoint = center + radius * (std::cos(angle) * u + std::sin(angle) * v);\n\n\t\t\tPath3D::batch->pushVertex({ point, color });\n\t\t\tPath3D::batch->pushIndices({ i - 1, i });\n\t\t}\n\t\t\n\t\tPath3D::batch->pushIndices({ precision - 1, 0 });\n\t\tPath3D::batch->endIndex();\n\t}\n\n\tvoid triangle(const Vec3f& a, const Vec3f& b, const Vec3f& c, const Color& colorA, const Color& colorB, const Color& colorC, float thickness) {\n\t\tsize_t vertexCount = 3;\n\t\tsize_t indexCount = 6;\n\t\tPath3D::batch->reserve(vertexCount, indexCount);\n\n\t\tPath3D::batch->pushVertices({ { a, colorA }, { b, colorB }, { c, colorC } });\n\t\tPath3D::batch->pushIndices({ 0, 1, 1, 2, 2, 0 });\n\n\t\tPath3D::batch->endIndex();\n\t}\n\n\tvoid quad(const Vec3f& a, const Vec3f& b, const Vec3f& c, const Vec3f& d, const Color& colorA, const Color& colorB, const Color& colorC, Color colorD, float thickness) {\n\t\tsize_t vertexCount = 4;\n\t\tsize_t indexCount = 8;\n\t\tPath3D::batch->reserve(vertexCount, indexCount);\n\n\t\tPath3D::batch->pushVertices({ { a, colorA }, { b, colorB }, { c, colorC }, { d, colorD } });\n\t\tPath3D::batch->pushIndices({ 0, 1, 1, 2, 2, 3, 3, 0 });\n\n\t\tPath3D::batch->endIndex();\n\t}\n\n\tvoid polyLine(Vec3f* points, size_t size, Pattern3D pattern, float thickness, bool closed) {\n\t\tif (size == 0)\n\t\t\treturn;\n\n\t\tif (size == 1)\n\t\t\treturn; // Points not supported yet\n\n\t\tsize_t vertexCount = size;\n\t\tsize_t indexCount = 2 * (size - (closed ? 0 : 1));\n\n\t\tPath3D::batch->reserve(vertexCount, indexCount);\n\n\t\tPath3D::batch->pushVertex({ points[0], pattern(0, points[0]) });\n\n\t\tfor (size_t i = 1; i < size; i++) {\n\t\t\tPath3D::batch->pushVertex({ points[i], pattern(i, points[i]) });\n\t\t\tPath3D::batch->pushIndices({ i - 1, i });\n\t\t}\n\n\t\tif (closed)\n\t\t\tPath3D::batch->pushIndices({ size - 1, 0 });\n\n\n\t\tPath3D::batch->endIndex();\n\t}\n\n\tvoid polyLine(Vec3f* points, size_t size, const Color& color, float thickness, bool closed) {\n\t\tpolyLine(points, size, DEFAULT_PATTERN_3D(color));\n\t}\n\n\t//! Path\n\n\tstd::vector<Vec3f> path;\n\n\tvoid lineTo(const Vec3f& vertex) {\n\t\tpath.push_back(vertex);\n\t}\n\n\tvoid bezierTo(const Vec3f& end, const Vec3f& tc1, const Vec3f& tc2, size_t precision) {\n\t\tVec3f start = path.back();\n\n\t\tfloat step = 1.0f / (float)precision;\n\t\tfor (size_t i = 1; i <= precision; i++) {\n\t\t\tfloat t = i * step;\n\t\t\tfloat s = 1 - t;\n\n\t\t\tfloat w1 = s * s * s;\n\t\t\tfloat w2 = 3.0f * s * s * t;\n\t\t\tfloat w3 = 3.0f * s * t * t;\n\t\t\tfloat w4 = t * t * t;\n\n\t\t\tpath.push_back(w1 * start + w2 * tc1 + w3 * tc2 + w4 * end);\n\t\t}\n\t}\n\n\tvoid bezierTo(const Vec3f& end, size_t precision) {\n\t\tVec3f start = path.back();\n\n\t\tfloat midX = (start.y + end.y) / 2.0f;\n\t\tfloat midZ = (start.y + end.y) / 2.0f;\n\t\tVec3f c1 = Vec3f(midX, start.y, midZ);\n\t\tVec3f c2 = Vec3f(midX, end.y, midZ);\n\n\t\tbezierTo(end, c1, c2, precision);\n\t}\n\n\tvoid stroke(const Color& color, float thickness, bool closed) {\n\t\tstroke(DEFAULT_PATTERN_3D(color), thickness, closed);\n\t}\n\n\tvoid stroke(Pattern3D pattern, float thickness, bool closed) {\n\t\tpolyLine(path.data(), path.size(), pattern, thickness, closed);\n\t\tclear();\n\t}\n\n\tint size() {\n\t\treturn path.size();\n\t}\n\n\tvoid clear() {\n\t\tpath.clear();\n\t}\n}\n\n};"
  },
  {
    "path": "graphics/path/path3D.h",
    "content": "#pragma once\n\n#include \"../batch/batch.h\"\n#include \"../gui/gui.h\"\n\nnamespace P3D::Graphics {\n\nnamespace Path3D {\n\n\t//! Pattern\n\n\ttypedef std::function<Color(int, const Vec3f&)> Pattern3D;\n\n\n\t//! Batch\n\t\n\tstruct Vertex {\n\t\tVec3f pos;\n\t\tVec4f col;\n\t};\n\n\textern Graphics::Batch<Vertex>* batch;\n\n\tvoid bind(Graphics::Batch<Vertex>* batch);\n\n\n\t//! Primitives\n\n\t/* Adds a line to the batch */\n\tvoid line(const Vec3f& a, const Vec3f& b, const Color& colorA = Colors::WHITE, const Color& colorB = Colors::WHITE, float thickness = 1.0f);\n\n\t/* Adds a triangle to the batch */\n\tvoid triangle(const Vec3f& a, const Vec3f& b, const Vec3f& c, const Color& colorA = Colors::WHITE, const Color& colorB = Colors::WHITE, const Color& colorC = Colors::WHITE, float thickness = 1.0f);\n\n\t/* Adds a quad to the batch */\n\tvoid quad(const Vec3f& a, const Vec3f& b, const Vec3f& c, const Vec3f& d, const Color& colorA = Colors::WHITE, const Color& colorB = Colors::WHITE, const Color& colorC = Colors::WHITE, Color colorD = Colors::WHITE, float thickness = 1.0f);\n\n\t/* Adds a circle perpendicular to the given normal to the batch */\n\tvoid circle(const Vec3f& center, float radius, const Vec3f& normal, float thickness = 1.0f, const Color& color = Colors::WHITE, size_t precision = 20);\n\n\t/* Adds a linestrip to the batch */\n\tvoid polyLine(Vec3f* points, size_t size, const Color& color = Colors::WHITE, float thickness = 1.0f, bool closed = false);\n\n\t/* Adds a linestrip to the batch */\n\tvoid polyLine(Vec3f* points, size_t size, Pattern3D pattern, float thickness = 1.0f, bool closed = false);\n\n\n\t//! Polygon building\n\n\t/* Adds a vertex to the current path */\n\tvoid lineTo(const Vec3f& vertex);\n\n\t/* Adds a bezier curve to the path with the given tangent control points, starting from the last point in the path */\n\tvoid bezierTo(const Vec3f& end, const Vec3f& tc1, const Vec3f& tc2, size_t precision);\n\n\t/* Adds a bezier curve to the path, starting from the last point in the path*/\n\tvoid bezierTo(const Vec3f& end, size_t precision);\n\n\t/* Draws the current path */\n\tvoid stroke(const Color& color = Colors::WHITE, float thickness = 1.0f, bool closed = false);\n\n\t/* Draws the current path */\n\tvoid stroke(Pattern3D pattern, float thickness = 1.0f, bool closed = false);\n\n\t/* Returns the amount of vertices in the current path */\n\tint size();\n\n\t/* Removes all vertices from the path */\n\tvoid clear();\n\n}\n\n};"
  },
  {
    "path": "graphics/renderer.cpp",
    "content": "#include \"core.h\"\n\n#include <GL/glew.h>\n#include <stack>\n\n#include \"renderer.h\"\n\nnamespace P3D::Graphics {\n\nnamespace Renderer {\n\nGLFLAG WIREFRAME = GL_LINE;\nGLFLAG FILL = GL_FILL;\nGLFLAG POINT = GL_POINT;\nGLFLAG FRONT_AND_BACK = GL_FRONT_AND_BACK;\n\nGLFLAG STATIC_DRAW = GL_STATIC_DRAW;\nGLFLAG STREAM_DRAW = GL_STREAM_DRAW;\nGLFLAG DYNAMIC_DRAW = GL_DYNAMIC_DRAW;\n\nGLFLAG ARRAY_BUFFER = GL_ARRAY_BUFFER;\n\nGLFLAG PATCHES = GL_PATCHES;\nGLFLAG QUADS = GL_QUADS;\nGLFLAG LINE_STRIP = GL_LINE_STRIP;\nGLFLAG TRIANGLES = GL_TRIANGLES;\nGLFLAG LINES = GL_LINES;\nGLFLAG POINTS = GL_POINTS;\n\nGLFLAG FLOAT = GL_FLOAT;\nGLFLAG UINT = GL_UNSIGNED_INT;\n\nstd::stack<RenderState> states;\nRenderState current;\n\nRenderState saveState() {\n\tRenderState state;\n\n\tint intbuffer;\n\tunsigned char boolbuffer;\n\t/*glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &intbuffer);\n\tstate.dfbo = intbuffer;\n\tglGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &intbuffer);\n\tstate.rfbo = intbuffer;\n\tglGetIntegerv(GL_RENDERBUFFER_BINDING, &intbuffer);\n\tstate.rbo = intbuffer;*/\n\t// glGetIntegerv(GL_TEXTURE_BINDING_2D, &intbuffer);\n\t// state.texture = intbuffer;\n\t// glGetIntegerv(GL_CURRENT_PROGRAM, &intbuffer);\n\t// state.program = intbuffer;\n\t// glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &intbuffer);\n\t// state.vao = intbuffer;\n\t// glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &intbuffer);\n\t// state.vbo = intbuffer;\n\t// glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &intbuffer);\n\t// state.vbo = intbuffer;\n\tglGetBooleanv(GL_DEPTH_WRITEMASK, &boolbuffer);\n\tstate.depthmask = boolbuffer;\n\tglGetIntegerv(GL_ACTIVE_TEXTURE, &state.activeTexture);\n\tglGetIntegerv(GL_VIEWPORT, state.viewport);\n\tglGetIntegerv(GL_POLYGON_MODE, state.mode);\n\tstate.blend = glIsEnabled(GL_BLEND);\n\tstate.cull = glIsEnabled(GL_CULL_FACE);\n\tstate.depth = glIsEnabled(GL_DEPTH_TEST);\n\t//state.scissor = glIsEnabled(GL_SCISSOR_TEST);\n\n\treturn state;\n}\n\nvoid loadState(const RenderState& state) {\n\tcurrent = state;\n\n\t/*bindReadbuffer(state.rfbo);\n\tbindDrawbuffer(state.dfbo);\n\tbindRenderbuffer(state.rbo);*/\n\t// glUseProgram(state.program);\n\t// glBindVertexArray(state.vao);\n\t// glBindBuffer(GL_ARRAY_BUFFER, state.vbo);\n\t// glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, state.ibo);\n\t// glActiveTexture(state.activeTexture);\n\t// glBindTexture(GL_TEXTURE_2D, state.texture);\n\tglDepthMask(state.depthmask); \n\tglViewport(state.viewport[0], state.viewport[1], state.viewport[2], state.viewport[3]);\n\tglPolygonMode(state.mode[0], state.mode[1]);\n\tif (state.blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);\n\tif (state.cull) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);\n\tif (state.depth) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);\n\t//if (state.scissor) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);\n}\n\nRenderState getState() {\n\tRenderState state;\n\n\tint intbuffer;\n\tunsigned char boolbuffer;\n\tglGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &intbuffer);\n\tstate.dfbo = intbuffer;\n\tglGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &intbuffer);\n\tstate.rfbo = intbuffer;\n\tglGetIntegerv(GL_RENDERBUFFER_BINDING, &intbuffer);\n\tstate.rbo = intbuffer;\n\tglGetIntegerv(GL_TEXTURE_BINDING_2D, &intbuffer);\n\tstate.texture = intbuffer;\n\tglGetIntegerv(GL_CURRENT_PROGRAM, &intbuffer);\n\tstate.program = intbuffer;\n\tglGetIntegerv(GL_VERTEX_ARRAY_BINDING, &intbuffer);\n\tstate.vao = intbuffer;\n\tglGetIntegerv(GL_ARRAY_BUFFER_BINDING, &intbuffer);\n\tstate.vbo = intbuffer;\n\tglGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &intbuffer);\n\tstate.vbo = intbuffer;\n\tglGetBooleanv(GL_DEPTH_WRITEMASK, &boolbuffer);\n\tstate.depthmask = boolbuffer;\n\tglGetIntegerv(GL_ACTIVE_TEXTURE, &state.activeTexture);\n\tglGetIntegerv(GL_VIEWPORT, state.viewport);\n\tglGetIntegerv(GL_POLYGON_MODE, state.mode);\n\tstate.blend = glIsEnabled(GL_BLEND);\n\tstate.cull = glIsEnabled(GL_CULL_FACE);\n\tstate.depth = glIsEnabled(GL_DEPTH_TEST);\n\tstate.scissor = glIsEnabled(GL_SCISSOR_TEST);\n\n\treturn state;\n}\n\nvoid beginScene() {\n\tRenderState\tbackup = saveState();\n\tstates.push(backup);\n}\n\nvoid endScene() {\n\tRenderState backup = states.top();\n\tloadState(backup);\n\tstates.pop();\n}\n\nbool initGLEW() {\n\treturn glewInit() == GLEW_OK;\n}\n\nvoid clearDepth() {\n\tglClear(GL_DEPTH_BUFFER_BIT);\n}\n\nvoid clearColor() {\n\tglClear(GL_COLOR_BUFFER_BIT);\n}\n\nvoid clearStencil() {\n\tglClear(GL_STENCIL_BUFFER_BIT);\n}\n\nvoid lineStipple(int factor, short pattern) {\n\tglLineStipple(factor, pattern);\n}\n\nvoid lineWidth(float size) {\n\tglLineWidth(size);\n}\n\nvoid viewport(const Vec2i& origin, const Vec2i& dimension) {\n\tcurrent.viewport[0] = origin.x;\n\tcurrent.viewport[1] = origin.y;\n\tcurrent.viewport[2] = dimension.x;\n\tcurrent.viewport[3] = dimension.y;\n\tglViewport(origin.x, origin.y, dimension.x, dimension.y);\n}\n\nvoid enableDepthTest() {\n\tglEnable(GL_DEPTH_TEST);\n}\n\nvoid disableDepthTest() {\n\tglDisable(GL_DEPTH_TEST);\n}\n\nvoid enableDepthMask() {\n\tglDepthMask(GL_TRUE);\n}\n\nvoid disableDepthMask() {\n\tglDepthMask(GL_FALSE);\n}\n\nvoid enableCulling() {\n\tglEnable(GL_CULL_FACE);\n}\n\nvoid disableCulling() {\n\tglDisable(GL_CULL_FACE);\n}\n\nvoid enableBlending() {\n\tglEnable(GL_BLEND);\n}\n\nvoid disableBlending() {\n\tglDisable(GL_BLEND);\n}\n\nvoid standardBlendFunction() {\n\tglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n}\n\nvoid enableMultisampling() {\n\tglEnable(GL_MULTISAMPLE);\n}\n\nvoid polygonMode(int face, int mode) {\n\tglPolygonMode(face, mode);\n}\n\nconst char* getVendor() {\n\treturn reinterpret_cast<const char*>(glGetString(GL_VENDOR));\n}\n\nconst char* getVersion() {\n\treturn reinterpret_cast<const char*>(glGetString(GL_VERSION));\n}\n\nconst char* getRenderer() {\n\treturn reinterpret_cast<const char*>(glGetString(GL_RENDERER));\n}\n\nconst char* getShaderVersion() {\n\treturn reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION));\n}\n\nint parseShaderVersion(const char* version) {\n\treturn 100 * (version[0] - '0') + 10 * (version[1] - '0');\n}\n\nint getMaxTextureUnits() {\n\tint result;\n\tglGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &result);\n\treturn result;\n}\n\nvoid genBuffers(int count, GLID* id) {\n\tglGenBuffers(count, id);\n}\n\nvoid delBuffers(int count, GLID* id) {\n\tglDeleteBuffers(count, id);\n}\n\nvoid genVertexArrays(int count, GLID* id) {\n\tglGenVertexArrays(count, id);\n}\n\nvoid delVertexArrays(int count, GLID* id) {\n\tglDeleteVertexArrays(count, id);\n}\n\nvoid bindBuffer(GLFLAG target, GLID id) {\n\tglBindBuffer(target, id);\n}\n\nvoid bufferData(GLFLAG target, int size, int offset, GLFLAG type) {\n\tglBufferData(target, size, reinterpret_cast<const void*>(offset), type);\n}\n\nvoid bufferSubData(GLFLAG target, int offset, int size, const void* pointer) {\n\tglBufferSubData(target, offset, size, pointer);\n}\n\nvoid enableVertexAttribArray(GLID id) {\n\tglEnableVertexAttribArray(id);\n}\n\nvoid bindTexture2D(GLID id) {\n\tglBindTexture(GL_TEXTURE_2D, id);\n}\n\nvoid activeTexture(GLID unit) {\n\tglActiveTexture(GL_TEXTURE0 + unit);\n}\n\nvoid vertexAttribPointer(GLID id, int size, GLFLAG type, bool normalized, int stride, const void* pointer) {\n\tglVertexAttribPointer(id, size, type, normalized, stride, pointer);\n}\n\nvoid bindShader(GLID id) {\n\t//if (current.program != id) {\n\t//\tcurrent.program = id;\n\t\tglUseProgram(id);\n\t//}\n}\n\nvoid bindFramebuffer(GLID id) {\n\tglBindFramebuffer(GL_FRAMEBUFFER, id);\n}\n\nvoid bindDrawbuffer(GLID id) {\n\t//if (current.dfbo != id) {\n\t//\tcurrent.dfbo = id;\n\t\tglBindFramebuffer(GL_DRAW_BUFFER, id);\n\t//}\n}\n\nvoid bindReadbuffer(GLID id) {\n\t//if (current.rfbo != id) {\n\t//\tcurrent.rfbo = id;\n\t\tglBindFramebuffer(GL_READ_BUFFER, id);\n\t//}\n}\n\nvoid bindRenderbuffer(GLID id) {\n\t//if (current.rbo != id) {\n\t//\tcurrent.rbo = id;\n\t\tglBindRenderbuffer(GL_RENDERBUFFER, id);\n\t//}\n}\n\nvoid bindVertexArray(GLID id) {\n\tglBindVertexArray(id);\n}\n\nvoid scissor(int x, int y, int width, int height) {\n\tglScissor(x, y, width, height);\n}\n\nvoid drawElements(GLFLAG mode, std::size_t count, GLFLAG type, const void* offset) {\n\tglDrawElements(mode, count, type, offset);\n}\n\nvoid drawElementsInstanced(GLFLAG mode, std::size_t count, GLFLAG type, const void* offset, std::size_t primitives) {\n\tglDrawElementsInstanced(mode, count, type, offset, primitives);\n}\n\nvoid drawArrays(GLFLAG mode, int first, std::size_t count) {\n\tglDrawArrays(mode, first, count);\n}\n\nvoid defaultSettings(GLID defaultFrameBuffer) {\n\tbindFramebuffer(defaultFrameBuffer);\n\tstandardBlendFunction();\n\tenableDepthTest();\n\tglLineWidth(1.5);\n\tdisableCulling();\n\tclearColor();\n\tclearDepth();\n}\n\n}\n\n};"
  },
  {
    "path": "graphics/renderer.h",
    "content": "#pragma once\n\n#include \"bindable.h\"\n\n#include <Physics3D/math/linalg/vec.h>\n\ntypedef unsigned int GLFLAG;\n\nnamespace P3D::Graphics {\n\nnamespace Renderer {\n\n// GL constants\n\nextern GLFLAG WIREFRAME;\nextern GLFLAG FILL;\nextern GLFLAG POINT;\nextern GLFLAG FRONT_AND_BACK;\n\nextern GLFLAG STATIC_DRAW;\nextern GLFLAG DYNAMIC_DRAW;\nextern GLFLAG STREAM_DRAW;\n\nextern GLFLAG ARRAY_BUFFER;\n\nextern GLFLAG TRIANGLES;\nextern GLFLAG PATCHES;\nextern GLFLAG QUADS;\nextern GLFLAG LINE_STRIP;\nextern GLFLAG LINES;\nextern GLFLAG POINTS;\n\nextern GLFLAG UINT;\nextern GLFLAG FLOAT;\n\nstruct RenderState {\n\tGLID dfbo;\n\tGLID rfbo;\n\tGLID rbo;\n\tGLID texture;\n\tGLID program;\n\tGLID vao;\n\tGLID vbo;\n\tGLID ibo;\n\tint activeTexture;\n\tint viewport[4];\n\tint mode[2];\n\tbool blend;\n\tbool cull;\n\tbool depth;\n\tbool scissor;\n\tbool depthmask;\n};\n\n// GLEW binding\n\nextern bool initGLEW();\n\nextern void clearDepth();\nextern void clearColor();\nextern void clearStencil();\n\nextern void lineStipple(int factor, short pattern);\nextern void lineWidth(float size);\n\nextern void viewport(const Vec2i& origin, const Vec2i& dimension);\n\nextern void enableDepthMask();\nextern void disableDepthMask();\nextern void enableDepthTest();\nextern void disableDepthTest();\nextern void enableCulling();\nextern void disableCulling();\nextern void enableBlending();\nextern void disableBlending();\nextern void standardBlendFunction();\nextern void enableMultisampling();\n\nextern const char* getVendor();\nextern const char* getVersion();\nextern const char* getRenderer();\nextern const char* getShaderVersion();\nextern int getMaxTextureUnits();\nextern int parseShaderVersion(const char* version);\n\nextern void genBuffers(int count, GLID* id);\nextern void genVertexArrays(int count, GLID* id);\nvoid delBuffers(int count, GLID* id);\nvoid delVertexArrays(int count, GLID* id);\nextern void bindBuffer(GLFLAG target, GLID id);\nextern void bufferData(GLFLAG target, int size, int offset, GLFLAG type);\nextern void bufferSubData(GLFLAG target, int offset, int size, const void* pointer);\n\nextern void enableVertexAttribArray(GLID id);\nextern void vertexAttribPointer(GLID id, int size, GLFLAG type, bool normalized, int stride, const void* pointer);\n\t\nextern void bindShader(GLID id);\nextern void bindTexture2D(GLID id);\nextern void bindFramebuffer(GLID id);\nextern void bindDrawbuffer(GLID id);\nextern void bindReadbuffer(GLID id);\nextern void bindRenderbuffer(GLID id);\nextern void bindVertexArray(GLID id);\n\nvoid activeTexture(GLID unit);\n\nextern void polygonMode(int face, int mode);\nextern void scissor(int x, int y, int width, int height);\nextern void drawElementsInstanced(GLFLAG mode, size_t count, GLFLAG type, const void* offset, size_t primitives);\nextern void drawElements(GLFLAG mode, size_t count, GLFLAG type, const void* offset);\nextern void drawArrays(GLFLAG mode, int first, size_t count);\n\nextern void defaultSettings(GLID defaultFrameBuffer);\n\nextern RenderState getState();\nextern void beginScene();\nextern void endScene();\n\n}\n\n};"
  },
  {
    "path": "graphics/resource/fontResource.cpp",
    "content": "#include \"core.h\"\n\n#include \"fontResource.h\"\n\nnamespace P3D::Graphics {\n\nFontResource* FontAllocator::load(const std::string& name, const std::string& path) {\n\tFont font(path);\n\n\tif (font.getAtlasID() != 0) {\n\t\treturn new FontResource(name, path, std::move(font));\n\t} else {\n\t\treturn nullptr;\n\t}\n}\n\n};"
  },
  {
    "path": "graphics/resource/fontResource.h",
    "content": "#pragma once\n\n#include \"../util/resource/resource.h\"\n\n#include \"../font.h\"\n\nnamespace P3D::Graphics {\n\nclass FontResource;\n\nclass FontAllocator : public ResourceAllocator<FontResource> {\npublic:\n\tvirtual FontResource* load(const std::string& name, const std::string& path) override;\n};\n\nclass FontResource : public Resource, public Font {\npublic:\n\tDEFINE_RESOURCE(Font, \"../res/fonts/default/default.ttf\");\n\n\tFontResource(const std::string& path, Font&& font) : Resource(path, path), Font(std::move(font)) {\n\n\t}\n\n\tFontResource(const std::string& name, const std::string& path, Font&& font) : Resource(name, path), Font(std::move(font)) {\n\n\t}\n\n\tvirtual void close() override {\n\t\tFont::close();\n\t};\n\n\tstatic FontAllocator getAllocator() {\n\t\treturn FontAllocator();\n\t}\n};\n\n};"
  },
  {
    "path": "graphics/resource/shaderResource.cpp",
    "content": "#include \"core.h\"\n\n#include \"shaderResource.h\"\n\n#include <fstream>\n#include <istream>\n\nnamespace P3D::Graphics {\n\nShaderResource* ShaderAllocator::load(const std::string& name, const std::string& path) {;\n\treturn new ShaderResource(name, path, true);\n}\n\n};"
  },
  {
    "path": "graphics/resource/shaderResource.h",
    "content": "#pragma once\n\n#include \"../util/resource/resource.h\"\n#include \"../shader/shader.h\"\n\nnamespace P3D::Graphics {\n\nclass ShaderResource;\n\nclass ShaderAllocator : public ResourceAllocator<ShaderResource> {\npublic:\n\tvirtual ShaderResource* load(const std::string& name, const std::string& path) override;\n};\n\nclass ShaderResource : public Resource, public Shader {\npublic:\n\tDEFINE_RESOURCE(Shader, \"../res/shaders/basic.shader\");\n\n\tShaderResource() : Resource(\"\"), Shader() {}\n\tShaderResource(const std::string& name, const std::string& path, bool isPath = true) : Resource(name, path), Shader(name, path, isPath) {}\n\n\tvoid close() override {\n\t\tShader::close();\n\t}\n\n\tstatic ShaderAllocator getAllocator() {\n\t\treturn ShaderAllocator();\n\t}\n};\n\n};"
  },
  {
    "path": "graphics/resource/textureResource.cpp",
    "content": "#include \"core.h\"\n\n#include \"textureResource.h\"\n\nnamespace P3D::Graphics {\n\nTextureResource* TextureAllocator::load(const std::string& name, const std::string& path) {\n\tTexture texture = Texture::load(path);\n\n\tif (texture.getID() != 0) {\n\t\treturn new TextureResource(name, path, std::move(texture));\n\t} else {\n\t\treturn nullptr;\n\t}\n}\n\n};"
  },
  {
    "path": "graphics/resource/textureResource.h",
    "content": "#pragma once\n\n#include \"../util/resource/resource.h\"\n\n#include \"../texture.h\"\n\nnamespace P3D::Graphics {\n\nclass TextureResource;\n\nclass TextureAllocator : public ResourceAllocator<TextureResource> {\npublic:\n\tvirtual TextureResource* load(const std::string& name, const std::string& path) override;\n};\n\nclass TextureResource : public Resource, public Texture {\npublic:\n\tDEFINE_RESOURCE(Texture, \"../res/textures/default/default.png\");\n\n\tTextureResource(const std::string& path, Texture&& texture) : Resource(path, path), Texture(std::move(texture)) {\n\n\t}\n\n\tTextureResource(const std::string& name, const std::string& path, Texture&& texture) : Resource(name, path), Texture(std::move(texture)) {\n\n\t}\n\n\tvirtual void close() override {\n\t\tTexture::close();\n\t};\n\n\tstatic TextureAllocator getAllocator() {\n\t\treturn TextureAllocator();\n\t}\n};\n\n};"
  },
  {
    "path": "graphics/shader/lexer.cpp",
    "content": "#include \"lexer.h\"\n\nnamespace P3D::Graphics {\n\tconstexpr bool Lexer::isDigit(char c) noexcept {\n\t\treturn c >= '0' && c <= '9';\n\t}\n\n\tconstexpr bool Lexer::isSpace(char c) noexcept {\n\t\tswitch (c) {\n\t\t\tcase ' ':\n\t\t\tcase '\\r':\n\t\t\tcase '\\n':\n\t\t\tcase '\\t':\n\t\t\t\treturn true;\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\t}\n\n\tconstexpr bool Lexer::isLetter(char c) noexcept {\n\t\treturn c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z';\n\t}\n\n\tconstexpr bool Lexer::isIdentifierBody(char c) noexcept {\n\t\treturn isIdentifierPrefix(c) || isDigit(c);\n\t}\n\n\tconstexpr bool Lexer::isOperator(char c) noexcept {\n\t\tswitch (c) {\n\t\t\tcase '+':\n\t\t\tcase '-':\n\t\t\tcase '*':\n\t\t\tcase '/':\n\t\t\tcase '<':\n\t\t\tcase '>':\n\t\t\tcase '~':\n\t\t\tcase '&':\n\t\t\tcase '|':\n\t\t\tcase '!':\n\t\t\tcase '?':\n\t\t\t\treturn true;\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\t}\n\n\tconstexpr bool Lexer::isIdentifierPrefix(char c) noexcept {\n\t\treturn isLetter(c) || c == '_';\n\t}\n\n\tconstexpr Lexer::Token Lexer::lexNumber() noexcept {\n\t\tconst std::size_t start = current;\n\n\t\tpopChar();\n\t\tbool dot = false;\n\t\twhile (isDigit(peekChar()) || peekChar() == '.') {\n\t\t\tif (peekChar() == '.') {\n\t\t\t\tif (dot)\n\t\t\t\t\treturn Token(Token::Number, start, current);\n\t\t\t\telse\n\t\t\t\t\tdot = true;\n\t\t\t}\n\t\t\tpopChar();\n\t\t}\n\n\t\treturn Token(Token::Number, start, current);\n\t}\n\n\tconstexpr Lexer::Token Lexer::lexIdentifier() noexcept {\n\t\tconst std::size_t start = current;\n\n\t\tpopChar();\n\t\twhile (isIdentifierBody(peekChar()))\n\t\t\tpopChar();\n\n\t\tstd::string_view type = view(start, current);\n\n\t\tif (type == \"true\" || type == \"false\")\n\t\t\treturn Token(Token::Boolean, start, current);\n\t\t\n\t\tif (type == \"in\" || type == \"out\")\n\t\t\treturn Token(Token::InOut, start, current);\n\n\t\tif (type == \"uniform\")\n\t\t\treturn Token(Token::Uniform, start, current);\n\n\t\tif (type == \"const\" || type == \"smooth\" || type == \"flat\")\n\t\t\treturn Token(Token::Qualifier, start, current);\n\n\t\tif (type == \"struct\")\n\t\t\treturn Token(Token::Struct, start, current);\n\t\t\n\t\tif (type == \"layout\")\n\t\t\treturn Token(Token::Layout, start, current);\n\n\t\tif (type == \"bool\" || type == \"mat2\" || type == \"mat3\" || type == \"mat4\" || type == \"float\" || type == \"int\" || type == \"vec2\" || type == \"vec3\" || type == \"vec4\" || type == \"VS_OUT\" || type == \"void\" || type == \"sampler2D\" || type == \"sampler3D\" || type == \"color3\" || type == \"color4\")\n\t\t\treturn Token(Token::Datatype, start, current);\n\t\t\n\t\treturn Token(Token::Identifier, start, current);\n\t}\n\n\tconstexpr Lexer::Token Lexer::lexSingleComment() noexcept {\n\t\tconst std::size_t start = current;\n\n\t\twhile (peekChar() != '\\n' && peekChar() != '\\0')\n\t\t\tpopChar();\n\n\t\treturn Token(Token::Comment, start, current);\n\t}\n\n\tconstexpr Lexer::Token Lexer::lexMultiComment() noexcept {\n\t\tconst std::size_t start = current;\n\n\t\twhile (true) {\n\t\t\tswitch (peekChar()) {\n\t\t\t\tcase '\\0':\n\t\t\t\t\treturn Token(Token::Comment, start, current);\n\t\t\t\tcase '*':\n\t\t\t\t\tswitch (peekChar(1)) {\n\t\t\t\t\tcase '\\0':\n\t\t\t\t\t\tpopChar();\n\t\t\t\t\t\treturn Token(Token::Comment, start, current - 1);\n\t\t\t\t\tcase '/':\n\t\t\t\t\t\tpopChar();\n\t\t\t\t\t\tpopChar();\n\t\t\t\t\t\treturn Token(Token::Comment, start, current - 2);\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tpopChar();\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tconstexpr Lexer::Token Lexer::lexString(char type) noexcept {\n\t\tconst std::size_t start = current;\n\n\t\tpopChar();\n\t\twhile (peekChar() != type)\n\t\t\tpopChar();\n\n\t\tpopChar();\n\n\t\treturn Token(Token::String, start + 1, current - 1);\n\t}\n\n\tconstexpr Lexer::Token Lexer::lexOperator() noexcept {\n\t\tconst std::size_t start = current;\n\n\t\tpopChar();\n\t\twhile (isOperator(peekChar()))\n\t\t\tpopChar();\n\n\t\treturn Token(Token::Operator, start, current);\n\t}\n\n\tconstexpr Lexer::Token Lexer::lexOperatorOrComment() noexcept {\n\t\tchar next = peekChar();\n\t\tif (next == '/') {\n\t\t\tswitch (peekChar(1)) {\n\t\t\tcase '\\0':\n\t\t\t\treturn lexChar(Token::Operator);\n\t\t\tcase '/':\n\t\t\t\tpopChar();\n\t\t\t\tpopChar();\n\t\t\t\treturn lexSingleComment();\n\t\t\tcase '*':\n\t\t\t\tpopChar();\n\t\t\t\tpopChar();\n\t\t\t\treturn lexMultiComment();\n\t\t\tdefault:\n\t\t\t\treturn lexOperator();\n\t\t\t}\n\t\t}\n\n\t\tif (next == '-' || next == '+')\n\t\t\tif (isDigit(peekChar(1)))\n\t\t\t\treturn lexNumber();\n\n\t\treturn lexOperator();\n\t}\n\n\tconstexpr Lexer::Token Lexer::lexVersionOrPreprocessor() noexcept {\n\t\tconst auto start = current;\n\n\t\tpopChar();\n\t\n\t\tif (isIdentifierPrefix(peekChar()))\n\t\t\tpopChar();\n\t\telse\n\t\t\treturn Token(Token::Error, start, current);\n\n\t\twhile (isIdentifierBody(peekChar()))\n\t\t\tpopChar();\n\n\t\tif (view(start, current) == \"#version\")\n\t\t\treturn Token(Token::Version, start, current);\n\n\t\treturn Token(Token::Preprocessor, start, current);\n\t}\n\n\tconstexpr Lexer::Token Lexer::lexEnd() const noexcept {\n\t\treturn Token(Token::End, current, current + 1);\n\t}\n\n\tconstexpr Lexer::Token Lexer::lexChar(const Token::Type type) noexcept {\n\t\tstd::size_t start = current;\n\t\tcurrent++;\n\t\t\n\t\treturn Token(type, start, current);\n\t}\n\n\tconstexpr char Lexer::peekChar(std::size_t offset) const noexcept {\n\t\treturn code[current + offset];\n\t}\n\n\tconstexpr char Lexer::popChar() noexcept {\n\t\treturn code[current++];\n\t}\n\n\tLexer::Lexer(const char* code) noexcept : current(0), code(code) {\n\n\t}\n\n\tLexer::Token Lexer::peek(std::size_t offset) noexcept {\n\t\twhile (isSpace(peekChar()))\n\t\t\tpopChar();\n\t\t\n\t\tstd::size_t temp = current;\n\t\t\n\t\tToken token = next();\n\t\tfor (std::size_t index = 0; index < offset; index++)\n\t\t\ttoken = next();\n\t\t\n\t\tcurrent = temp;\n\n\t\treturn token;\n\t}\n\n\tvoid Lexer::advance(std::size_t offset) noexcept {\n\t\tcurrent += offset;\n\t}\n\n\tconstexpr std::string_view Lexer::view(std::size_t start, std::size_t stop) noexcept {\n\t\treturn std::string_view(this->code + start, stop - start);\n\t}\n\n\tstd::string Lexer::string(std::size_t start, std::size_t stop) noexcept {\n\t\treturn std::string(this->code + start, stop - start);\n\t}\n\n\tLexer::Token Lexer::next() noexcept {\n\t\twhile (isSpace(peekChar()))\n\t\t\tpopChar();\n\n\t\tconst char character = peekChar();\n\n\t\tif (character == 0)\n\t\t\treturn Token(Token::End, current, current);\n\n\t\tif (isIdentifierPrefix(character))\n\t\t\treturn lexIdentifier();\n\n\t\tif (isDigit(character))\n\t\t\treturn lexNumber();\n\n\t\tif (isOperator(character))\n\t\t\treturn lexOperatorOrComment();\n\n\t\tswitch (character) {\n\t\t\tcase '\\0':\n\t\t\t\treturn lexEnd();\n\t\t\tcase '#':\n\t\t\t\treturn lexVersionOrPreprocessor();\n\t\t\tcase ':':\n\t\t\t\treturn lexChar(Token::Colon);\n\t\t\tcase '=':\n\t\t\t\treturn lexChar(Token::Equals);\n\t\t\tcase '(':\n\t\t\t\treturn lexChar(Token::LeftParenthesis);\n\t\t\tcase ')':\n\t\t\t\treturn lexChar(Token::RightParenthesis);\n\t\t\tcase '{':\n\t\t\t\treturn lexChar(Token::LeftCurl);\n\t\t\tcase '}':\n\t\t\t\treturn lexChar(Token::RightCurl);\n\t\t\tcase '[':\n\t\t\t\treturn lexChar(Token::LeftBracket);\n\t\t\tcase ']':\n\t\t\t\treturn lexChar(Token::RightBracket);\n\t\t\tcase '\\'':\n\t\t\t\treturn lexChar(Token::SingleQuote);\n\t\t\tcase '\"':\n\t\t\t\treturn lexString('\"');\n\t\t\tcase '.':\n\t\t\t\treturn lexChar(Token::Dot);\n\t\t\tcase ',':\n\t\t\t\treturn lexChar(Token::Comma);\n\t\t\tcase ';':\n\t\t\t\treturn lexChar(Token::Semicolon);\n\t\t\tdefault:\n\t\t\t\treturn lexChar(Token::Error);\n\t\t}\n\t}\n\t\n}\n"
  },
  {
    "path": "graphics/shader/lexer.h",
    "content": "#pragma once\n\n#include <string_view>\n#include <string>\n\nnamespace P3D::Graphics {\n\tclass Lexer {\n\tpublic:\n\t\tstruct Range {\n\t\t\tstd::size_t start = 0;\n\t\t\tstd::size_t stop = 0;\n\n\t\t\t[[nodiscard]] constexpr std::size_t size() const {\n\t\t\t\treturn stop - start;\n\t\t\t}\n\n\t\t\t[[nodiscard]] constexpr const char* first(const char* code) const {\n\t\t\t\treturn code + start;\n\t\t\t}\n\n\t\t\t[[nodiscard]] constexpr const char* last(const char* code) const {\n\t\t\t\treturn code + stop;\n\t\t\t}\n\n\t\t\t[[nodiscard]] constexpr std::string_view view(const char* code) const {\n\t\t\t\treturn std::string_view(this->first(code), this->size());\n\t\t\t}\n\n\t\t\t[[nodiscard]] std::string string(const char* code) const {\n\t\t\t\treturn std::string(this->first(code), this->size());\n\t\t\t}\n\t\t};\n\t\t\n\t\tstruct Token {\n\t\t\tenum Type : char {\n\t\t\t\tError,\n\t\t\t\tComma,\n\t\t\t\tSemicolon,\n\t\t\t\tColon,\n\t\t\t\tLeftParenthesis,\n\t\t\t\tRightParenthesis,\n\t\t\t\tEquals,\n\t\t\t\tDot,\n\t\t\t\tInOut,\n\t\t\t\tLayout,\n\t\t\t\tUniform,\n\t\t\t\tQualifier,\n\t\t\t\tStruct,\n\t\t\t\tVersion,\n\t\t\t\tPreprocessor,\n\t\t\t\tDatatype,\n\t\t\t\tIdentifier,\n\t\t\t\tLeftCurl,\n\t\t\t\tRightCurl,\n\t\t\t\tLeftBracket,\n\t\t\t\tRightBracket,\n\t\t\t\tNumber,\n\t\t\t\tBoolean,\n\t\t\t\tOperator,\n\t\t\t\tSingleQuote,\n\t\t\t\tDoubleQuote,\n\t\t\t\tString,\n\t\t\t\tComment,\n\t\t\t\tEnd\n\t\t\t};\n\n\t\t\tType type;\n\t\t\tRange range;\n\n\t\t\tconstexpr Token(const Type type, std::size_t start, std::size_t stop) : type(type), range(Range { start, stop }) {}\n\n\t\t\t[[nodiscard]] constexpr std::size_t size() const {\n\t\t\t\treturn this->range.size();\n\t\t\t}\n\n\t\t\t[[nodiscard]] constexpr std::string_view view(const char* code) const {\n\t\t\t\treturn this->range.view(code);\n\t\t\t}\n\n\t\t\t[[nodiscard]] std::string string(const char* code) const {\n\t\t\t\treturn this->range.string(code);\n\t\t\t}\n\n\t\t\t[[nodiscard]] constexpr const char* first(const char* code) const {\n\t\t\t\treturn this->range.first(code);\n\t\t\t}\n\n\t\t\t[[nodiscard]] constexpr const char* last(const char* code) const {\n\t\t\t\treturn this->range.last(code);\n\t\t\t}\n\t\t};\n\t\t\n\tprivate:\n\t\tstd::size_t current;\n\t\t\n\t\t[[nodiscard]] constexpr static bool isDigit(char c) noexcept;\n\t\t[[nodiscard]] constexpr static bool isSpace(char c) noexcept;\n\t\t[[nodiscard]] constexpr static bool isLetter(char c) noexcept;\n\t\t[[nodiscard]] constexpr static bool isIdentifierPrefix(char c) noexcept;\n\t\t[[nodiscard]] constexpr static bool isIdentifierBody(char c) noexcept;\n\t\t[[nodiscard]] constexpr static bool isOperator(char c) noexcept;\n\n\t\t[[nodiscard]] constexpr Token lexString(char type) noexcept;\n\t\t[[nodiscard]] constexpr Token lexNumber() noexcept;\n\t\t[[nodiscard]] constexpr Token lexIdentifier() noexcept;\n\t\t[[nodiscard]] constexpr Token lexOperatorOrComment() noexcept;\n\t\t[[nodiscard]] constexpr Token lexVersionOrPreprocessor() noexcept;\n\t\t[[nodiscard]] constexpr Token lexSingleComment() noexcept;\n\t\t[[nodiscard]] constexpr Token lexMultiComment() noexcept;\n\t\t[[nodiscard]] constexpr Token lexOperator() noexcept;\n\t\t[[nodiscard]] constexpr Token lexChar(Token::Type type) noexcept;\n\t\t[[nodiscard]] constexpr Token lexEnd() const noexcept;\n\n\t\t[[nodiscard]] constexpr char peekChar(std::size_t offset = 0) const noexcept;\n\t\tconstexpr char popChar() noexcept;\n\n\tpublic:\n\t\tconst char* code;\n\t\t\n\t\texplicit Lexer(const char* code) noexcept;\n\n\t\tvoid advance(std::size_t offset) noexcept;\n\n\t\t[[nodiscard]] constexpr std::string_view view(std::size_t start, std::size_t stop) noexcept;\n\t\t[[nodiscard]] std::string string(std::size_t start, std::size_t stop) noexcept;\n\t\t[[nodiscard]] Token peek(std::size_t offset = 0) noexcept;\n\t\t[[nodiscard]] Token next() noexcept;\n\t};\n}\n"
  },
  {
    "path": "graphics/shader/parser.cpp",
    "content": "#include \"core.h\"\n\n#include \"parser.h\"\n#include \"lexer.h\"\n\n#include <sstream>\n\nnamespace P3D::Graphics {\n\n\tParser::Type Parser::parseType(std::string_view type) {\n\t\tif (type == \"void\")\n\t\t\treturn Type::Void;\n\t\tif (type == \"bool\")\n\t\t\treturn Type::Bool;\n\t\tif (type == \"int\")\n\t\t\treturn Type::Int;\n\t\tif (type == \"float\")\n\t\t\treturn Type::Float;\n\t\tif (type == \"mat2\")\n\t\t\treturn Type::Mat2;\n\t\tif (type == \"mat3\")\n\t\t\treturn Type::Mat3;\n\t\tif (type == \"mat4\")\n\t\t\treturn Type::Mat4;\n\t\tif (type == \"vec2\")\n\t\t\treturn Type::Vec2;\n\t\tif (type == \"vec3\")\n\t\t\treturn Type::Vec3;\n\t\tif (type == \"vec4\")\n\t\t\treturn Type::Vec4;\n\t\tif (type == \"struct\")\n\t\t\treturn Type::Struct;\n\t\tif (type == \"VS_OUT\")\n\t\t\treturn Type::VSOut;\n\t\tif (type == \"struct\")\n\t\t\treturn Type::Struct;\n\t\tif (type == \"sampler2d\")\n\t\t\treturn Type::Sampler2D;\n\t\tif (type == \"sampler3d\")\n\t\t\treturn Type::Sampler3D;\n\n\t\treturn Type::None;\n\t}\n\n\tParser::IO Parser::parseIO(std::string_view io) {\n\t\tif (io == \"in\")\n\t\t\treturn IO::In;\n\t\tif (io == \"out\")\n\t\t\treturn IO::Out;\n\n\t\treturn IO::None;\n\t}\n\n\tvoid parseUntil(Lexer& lexer, Lexer::Token::Type ltype, Lexer::Token::Type rtype) {\n\t\tint depth = -1;\n\t\tLexer::Token next = lexer.next();\n\t\twhile (next.type != Lexer::Token::End) {\n\t\t\tif (next.type == ltype) {\n\t\t\t\tdepth++;\n\t\t\t} else if (next.type == rtype) {\n\t\t\t\tif (depth == 0)\n\t\t\t\t\treturn;\n\n\t\t\t\tif (depth > 0)\n\t\t\t\t\tdepth--;\n\t\t\t}\n\t\t\t\n\t\t\tnext = lexer.next();\n\t\t}\n\t}\n\n\tvoid parseUntil(Lexer& lexer, Lexer::Token::Type type) {\n\t\tLexer::Token next = lexer.next();\n\n\t\twhile (next.type != Lexer::Token::End) {\n\t\t\tif (next.type == type)\n\t\t\t\treturn;\n\t\t\t\n\t\t\tnext = lexer.next();\n\t\t}\n\t}\n\n\tstd::size_t parseArray(Lexer& lexer, Parser::Parse& result) {\n\t\tLexer::Token leftBracket = lexer.peek();\n\t\tif (leftBracket.type == Lexer::Token::LeftBracket) {\n\t\t\tlexer.advance(leftBracket.size());\n\n\t\t\tLexer::Token next = lexer.next();\n\t\t\tswitch (next.type) {\n\t\t\t\tcase Lexer::Token::Number: {\n\t\t\t\t\tstd::size_t amount;\n\t\t\t\t\tstd::stringstream stream(std::string(next.first(lexer.code), next.size()));\n\t\t\t\t\tstream >> amount;\n\n\t\t\t\t\tif (stream.fail())\n\t\t\t\t\t\treturn static_cast<std::size_t>(-1);\n\t\t\t\t\t\n\t\t\t\t\treturn amount;\n\t\t\t\t} case Lexer::Token::Identifier: {\n\t\t\t\t\tstd::string define(next.string(lexer.code));\n\t\t\t\t\tif (auto iterator = result.defines.find(define); iterator != result.defines.end())\n\t\t\t\t\t\treturn static_cast<int>(iterator->second);\n\t\t\t\t\treturn static_cast<std::size_t>(-1);\n\t\t\t\t} case Lexer::Token::RightBracket: {\n\t\t\t\t\treturn 0;\n\t\t\t\t} default:\n\t\t\t\t\treturn static_cast<std::size_t>(-1);\n\t\t\t}\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tvoid parseUniform(Lexer& lexer, const Lexer::Token& current, Parser::Parse& result) {\n\t\tLexer::Token type = lexer.next();\n\t\tif (type.type != Lexer::Token::Datatype && type.type != Lexer::Token::Identifier)\n\t\t\treturn;\n\n\t\tif (type.type == Lexer::Token::Identifier && result.structs.find(type.string(lexer.code)) == result.structs.end())\n\t\t\treturn;\n\t\t\n\t\tLexer::Token name = lexer.next();\n\t\tif (name.type != Lexer::Token::Identifier)\n\t\t\treturn;\n\n\t\tstd::size_t amount = parseArray(lexer, result);\n\t\tif (amount == static_cast<std::size_t>(-1))\n\t\t\treturn;\n\n\t\tparseUntil(lexer, Lexer::Token::Semicolon);\n\n\t\tresult.uniforms.push_back(Parser::Local { type.range, name.range, amount });\n\t}\n\n\tParser::Locals parseScope(Lexer& lexer, Parser::Parse& result) {\n\t\tParser::Locals locals;\n\t\t\n\t\tLexer::Token next = lexer.next();\n\t\tif (next.type != Lexer::Token::LeftCurl)\n\t\t\treturn locals;\n\n\t\tint depth = 1;\n\t\twhile (next.type != Lexer::Token::End) {\n\t\t\tnext = lexer.next();\n\n\t\t\tif (next.type == Lexer::Token::LeftCurl) {\n\t\t\t\tdepth++;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (next.type == Lexer::Token::RightCurl) {\n\t\t\t\tdepth--;\n\t\t\t\t\n\t\t\t\tif (depth == 0)\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (next.type == Lexer::Token::Datatype || next.type == Lexer::Token::Identifier && result.structs.find(next.string(lexer.code)) != result.structs.end()) {\n\t\t\t\tLexer::Token type = next;\n\t\t\t\t\n\t\t\t\tLexer::Token name = lexer.next();\n\t\t\t\tif (name.type != Lexer::Token::Identifier)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tstd::size_t amount = parseArray(lexer, result);\n\t\t\t\tif (amount == static_cast<std::size_t>(-1))\n\t\t\t\t\tcontinue;\n\n\t\t\t\tlocals.push_back(Parser::Local { type.range, name.range, amount });\n\t\t\t}\n\t\t}\n\n\t\treturn locals;\n\t}\n\n\tvoid parseVSOut(Lexer& lexer, const Lexer::Token& type, const Parser::IO& io, Parser::Parse& result) {\n\t\tParser::Locals locals = parseScope(lexer, result);\n\n\t\tLexer::Token name = lexer.next();\n\t\tif (name.type != Lexer::Token::Identifier)\n\t\t\treturn;\n\n\t\tstd::size_t amount = parseArray(lexer, result);\n\t\tif (amount == static_cast<std::size_t>(-1))\n\t\t\treturn;\n\n\t\tresult.vsOuts.push_back(Parser::VSOut { io, type.range, name.range, amount, locals });\n\t}\n\n\tvoid parseGlobal(Lexer& lexer, const Lexer::Token& current, Parser::Parse& result) {\n\t\tParser::IO io = Parser::parseIO(current.view(lexer.code));\n\t\tif (io == Parser::IO::None)\n\t\t\treturn;\n\n\t\tLexer::Token type = lexer.next();\n\t\tif (type.type != Lexer::Token::Datatype)\n\t\t\treturn;\n\n\t\tif (Parser::parseType(type.view(lexer.code)) == Parser::Type::VSOut) {\n\t\t\tparseVSOut(lexer, type, io, result);\n\t\t\treturn;\n\t\t}\n\n\t\tLexer::Token name = lexer.next();\n\t\tif (name.type != Lexer::Token::Identifier)\n\t\t\treturn;\n\t\t\n\t\tstd::size_t amount = parseArray(lexer, result);\n\t\tif (amount == static_cast<std::size_t>(-1))\n\t\t\treturn;\n\n\t\tresult.globals.emplace_back(Parser::Global { io, type.range, name.range, amount });\n\t}\n\n\tvoid parseVersion(Lexer& lexer, const Lexer::Token& current, Parser::Parse& result) {\n\t\tLexer::Token versionToken = lexer.next();\n\t\tif (versionToken.type != Lexer::Token::Number)\n\t\t\treturn;\n\n\t\tstd::size_t version;\n\t\tstd::stringstream stream(std::string(versionToken.first(lexer.code), versionToken.size()));\n\t\tstream >> version;\n\n\t\tif (stream.fail())\n\t\t\treturn;\n\t\t\n\t\tbool core = false;\n\t\tLexer::Token coreToken = lexer.peek();\n\t\tif (coreToken.type == Lexer::Token::Identifier && coreToken.view(lexer.code) == \"core\") {\n\t\t\tlexer.advance(coreToken.size());\n\t\t\tcore = true;\n\t\t}\n\n\t\tresult.version = Parser::Version { version, core };\n\t}\n\n\tvoid parseDefine(Lexer& lexer, Parser::Parse& result) {\n\t\tLexer::Token name = lexer.next();\n\t\tif (name.type != Lexer::Token::Identifier)\n\t\t\treturn;\n\n\t\tint number = 1;\n\t\tLexer::Token numberToken = lexer.next();\n\t\tif (numberToken.type == Lexer::Token::Number) {\n\t\t\tstd::stringstream stream(std::string(numberToken.first(lexer.code), numberToken.size()));\n\t\t\tstream >> number;\n\n\t\t\tif (stream.fail())\n\t\t\t\treturn;\n\t\t}\n\n\t\tresult.defines[name.string(lexer.code)] = number;\n\t}\n\t\n\tvoid parsePreprocessor(Lexer& lexer, const Lexer::Token& current, Parser::Parse& result) {\n\t\tif (current.view(lexer.code) == \"#define\")\n\t\t\tparseDefine(lexer, result);\n\t}\n\n\tvoid parseIdentifier(Lexer& lexer, const Lexer::Token& current, Parser::Parse& result) {\n\t\tLexer::Token type = current;\n\t\tif (result.structs.find(current.string(lexer.code)) == result.structs.end())\n\t\t\treturn;\n\t\t\n\t\tLexer::Token name = lexer.next();\n\t\tif (name.type != Lexer::Token::Identifier)\n\t\t\treturn;\n\n\t\tstd::size_t amount = parseArray(lexer, result);\n\t\tif (amount == static_cast<std::size_t>(-1))\n\t\t\treturn;\n\n\t\tresult.locals.push_back(Parser::Local { type.range, name.range, amount });\n\t}\n\n\tvoid parseDatatype(Lexer& lexer, const Lexer::Token& current, Parser::Parse& result) {\n\t\tif (Parser::parseType(current.view(lexer.code)) == Parser::Type::Void || lexer.peek().type == Lexer::Token::Identifier && lexer.peek(1).type == Lexer::Token::LeftParenthesis) \n\t\t\tparseUntil(lexer, Lexer::Token::LeftCurl, Lexer::Token::RightCurl);\n\t\t\n\t}\n\t\n\tvoid parseStruct(Lexer& lexer, const Lexer::Token& current, Parser::Parse& result) {\n\t\tLexer::Token name = lexer.next();\n\t\tif (name.type != Lexer::Token::Identifier)\n\t\t\treturn;\n\n\t\tParser::Locals locals = parseScope(lexer, result);\n\n\t\tresult.structs[name.string(lexer.code)] = Parser::Struct { name.range, locals };\n\t}\n\n\t\n\t\n\tParser::Parse Parser::parse(const char* code) {\n\t\tParse result;\n\n\t\tLexer lexer(code);\n\t\tLexer::Token current = lexer.next();\n\t\twhile (current.type != Lexer::Token::End) {\n\t\t\tswitch (current.type) {\n\t\t\t\tcase Lexer::Token::Uniform: {\n\t\t\t\t\tparseUniform(lexer, current, result);\n\t\t\t\t\tbreak;\n\t\t\t\t} case Lexer::Token::InOut: {\n\t\t\t\t\tparseGlobal(lexer, current, result);\n\t\t\t\t\tbreak;\n\t\t\t\t} case Lexer::Token::Datatype: {\n\t\t\t\t\tparseDatatype(lexer, current, result);\n\t\t\t\t\tbreak;\n\t\t\t\t} case Lexer::Token::Layout: {\n\t\t\t\t\t// TODO\n\t\t\t\t\tbreak;\t\n\t\t\t\t} case Lexer::Token::Version: {\n\t\t\t\t\tparseVersion(lexer, current, result);\n\t\t\t\t\tbreak;\n\t\t\t\t} case Lexer::Token::Preprocessor: {\n\t\t\t\t\tparsePreprocessor(lexer, current, result);\n\t\t\t\t\tbreak;\n\t\t\t\t} case Lexer::Token::Struct: {\n\t\t\t\t\tparseStruct(lexer, current, result);\n\t\t\t\t\tbreak;\n\t\t\t\t} case Lexer::Token::Identifier: {\n\t\t\t\t\tparseIdentifier(lexer, current, result);\n\t\t\t\t\tbreak;\n\t\t\t\t} default:\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tcurrent = lexer.next();\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t\n}\n"
  },
  {
    "path": "graphics/shader/parser.h",
    "content": "#pragma once\n\n#include <string_view>\n#include <unordered_map>\n#include <vector>\n\n#include \"lexer.h\"\n\nnamespace P3D::Graphics {\n\nclass Parser {\npublic:\n\t\n\tenum class Type : char {\n\t\tNone,\n\t\tVoid,\n\t\tBool,\n\t\tInt,\n\t\tFloat,\n\t\tVec2,\n\t\tVec3,\n\t\tVec4,\n\t\tMat2,\n\t\tMat3,\n\t\tMat4,\n\t\tStruct,\n\t\tVSOut,\n\t\tSampler2D,\n\t\tSampler3D\n\t};\n\n\tenum class IO {\n\t\tNone,\n\t\tIn,\n\t\tOut\n\t};\n\n\tstruct Local {\n\t\tLexer::Range type;\n\t\tLexer::Range name;\n\t\tstd::size_t amount;\n\t};\n\ttypedef std::vector<Local> Locals;\n\n\tstruct Global {\n\t\tIO io;\n\t\tLexer::Range type;\n\t\tLexer::Range name;\n\t\tstd::size_t amount;\n\t};\n\ttypedef std::vector<Global> Globals;\n\n\tstruct Layout {\n\t\tstruct Attribute {\n\t\t\tLexer::Range attribute;\n\t\t\tLexer::Range value;\n\t\t};\n\t\t\n\t\tIO io;\n\t\tLexer::Range type;\n\t\tLexer::Range name;\n\t\tstd::vector<Attribute> attributes;\n\t};\n\ttypedef std::vector<Layout> Layouts;\n\n\tstruct VSOut {\n\t\tIO io;\n\t\tLexer::Range type;\n\t\tLexer::Range name;\n\t\tstd::size_t amount;\n\t\tLocals locals;\n\t};\n\ttypedef std::vector<VSOut> VSOuts;\n\n\tstruct Version {\n\t\tstd::size_t version = 0;\n\t\tbool core = false;\n\t};\n\n\tstruct Struct {\n\t\tLexer::Range name;\n\t\tLocals locals;\n\t};\n\t\n\ttypedef std::unordered_map<std::string, Struct> Structs;\n\ttypedef std::unordered_map<std::string, int> Defines;\n\n\tstruct Parse {\n\t\tVersion version;\n\t\tLayouts layouts;\n\t\tLocals uniforms;\n\t\tGlobals globals;\n\t\tVSOuts vsOuts;\n\t\tLocals locals;\n\t\tDefines defines;\n\t\tStructs structs;\n\t};\n\n\tstatic Type parseType(std::string_view type);\n\tstatic IO parseIO(std::string_view io);\n\t\n\tstatic Parse parse(const char* code);\n\t\n};\n\t\n}\n"
  },
  {
    "path": "graphics/shader/propertiesParser.cpp",
    "content": "#include \"core.h\"\n#include \"propertiesParser.h\"\n\n#include \"lexer.h\"\n\nnamespace P3D::Graphics {\n\n\tstd::optional<Property::Type> parseType(const Lexer& lexer, const Lexer::Token& token) {\n\t\tstd::string_view type = token.view(lexer.code);\n\n\t\tstatic std::unordered_map<std::string_view, Property::Type> map { {\n\t\t\t{ \"bool\" , Property::Type::Bool  },\n\t\t\t{ \"int\"  , Property::Type::Int   },\n\t\t\t{ \"float\", Property::Type::Float },\n\t\t\t{ \"vec2\" , Property::Type::Vec2  },\n\t\t\t{ \"vec3\" , Property::Type::Vec3  },\n\t\t\t{ \"vec4\" , Property::Type::Vec4  },\n\t\t\t{ \"mat2\" , Property::Type::Mat2  },\n\t\t\t{ \"mat3\" , Property::Type::Mat3  },\n\t\t\t{ \"mat4\" , Property::Type::Mat4  },\n\t\t\t{ \"col3\" , Property::Type::Col3  },\n\t\t\t{ \"col4\" , Property::Type::Col4  },\n\t\t} };\n\t\t\n\t\tauto iterator = map.find(type);\n\t\tif (iterator != map.end())\n\t\t\treturn std::make_optional(iterator->second);\n\n\t\treturn std::nullopt;\n\t}\n\n\tstd::size_t arity(const Property::Type& type) {\n\t\tstatic std::unordered_map<Property::Type, std::size_t> map { {\n\t\t\t{ Property::Type::Bool , 1  },\n\t\t\t{ Property::Type::Int  , 1  },\n\t\t\t{ Property::Type::Float, 1  },\n\t\t\t{ Property::Type::Vec2 , 2  },\n\t\t\t{ Property::Type::Vec3 , 3  },\n\t\t\t{ Property::Type::Vec4 , 4  },\n\t\t\t{ Property::Type::Mat2 , 4  },\n\t\t\t{ Property::Type::Mat3 , 9  },\n\t\t\t{ Property::Type::Mat4 , 16 },\n\t\t\t{ Property::Type::Col3 , 3  },\n\t\t\t{ Property::Type::Col4 , 4  },\n\t\t} };\n\n\t\treturn map.at(type);\n\t}\n\n\tstd::optional<Property::Default> parseDefault(Lexer& lexer, const Lexer::Token& token) {\n\t\tProperty::Default value;\n\n\t\tif (token.type == Lexer::Token::Boolean)\n\t\t\tvalue.value = token.view(lexer.code) == \"true\" ? 1.0f : 0.0f;\n\t\telse if (token.type == Lexer::Token::Number) {\n\t\t\tfloat number = std::stof(token.string(lexer.code));\n\t\t\tvalue.value = number;\n\t\t} else\n\t\t\treturn std::nullopt;\n\n\t\tif (lexer.peek().type != Lexer::Token::LeftParenthesis)\n\t\t\treturn value;\n\n\t\tLexer::Token parenthesis = lexer.next();\n\n\t\tLexer::Token start = lexer.next();\n\t\tif (start.type != Lexer::Token::Number)\n\t\t\treturn std::nullopt;\n\n\t\tif (lexer.next().type != Lexer::Token::Colon)\n\t\t\treturn std::nullopt;\n\n\t\tLexer::Token stop = lexer.next();\n\t\tif (start.type != Lexer::Token::Number)\n\t\t\treturn std::nullopt;\n\n\t\tvalue.range = { std::stof(start.string(lexer.code)), std::stof(stop.string(lexer.code)) };\n\n\t\tparenthesis = lexer.next();\n\t\tif (parenthesis.type != Lexer::Token::RightParenthesis)\n\t\t\treturn std::nullopt;\n\n\t\treturn std::make_optional(value);\n\t}\n\n\tstd::optional<Property> parseProperty(Lexer& lexer, const Lexer::Token& token) {\n\t\tProperty property;\n\t\t\n\t\tif (token.type != Lexer::Token::Datatype)\n\t\t\treturn std::nullopt;\n\n\t\tstd::optional<Property::Type> type = parseType(lexer, token);\n\t\tif (!type.has_value())\n\t\t\treturn std::nullopt;\n\t\t\n\t\tproperty.type = type.value();\n\n\t\tLexer::Token name = lexer.next();\n\t\tif (name.type != Lexer::Token::Identifier)\n\t\t\treturn std::nullopt;\n\t\t\n\t\tproperty.name = name.view(lexer.code);\n\n\t\tLexer::Token next = lexer.next();\n\t\tif (next.type == Lexer::Token::LeftParenthesis) {\n\t\t\tLexer::Token uniform = lexer.next();\n\n\t\t\tif (uniform.type != Lexer::Token::Identifier)\n\t\t\t\treturn std::nullopt;\n\n\t\t\tproperty.uniform = uniform.view(lexer.code);\n\n\t\t\tnext = lexer.next();\n\t\t\tif (next.type != Lexer::Token::RightParenthesis)\n\t\t\t\treturn std::nullopt;\n\n\t\t\tnext = lexer.next();\n\t\t} else {\n\t\t\tproperty.uniform = property.name;\n\t\t}\n\n\t\tif (next.type == Lexer::Token::Semicolon) {\n\t\t\tfor (std::size_t i = 0; i < arity(property.type); i++) {\n\t\t\t\tProperty::Default value { 0.0, std::nullopt };\n\t\t\t\tproperty.defaults.push_back(value);\n\t\t\t}\n\n\t\t\treturn std::make_optional(property);\n\t\t}\n\t\t\n\t\tif (next.type != Lexer::Token::Equals)\n\t\t\treturn std::nullopt;\n\n\t\tfor (std::size_t i = 0; i < arity(property.type); i++) {\n\t\t\tif (i != 0) {\n\t\t\t\tnext = lexer.next();\n\t\t\t\tif (next.type != Lexer::Token::Comma)\n\t\t\t\t\treturn std::nullopt;\n\t\t\t}\n\t\t\t\n\t\t\tstd::optional<Property::Default> value = parseDefault(lexer, lexer.next());\n\t\t\tif (!value.has_value())\n\t\t\t\treturn std::nullopt;\n\t\t\t\n\t\t\tproperty.defaults.push_back(value.value());\n\t\t}\n\n\t\tnext = lexer.next();\n\t\tif (next.type == Lexer::Token::Semicolon)\n\t\t\treturn std::make_optional(property);\n\n\t\treturn std::nullopt;\n\t}\n\n\tstd::vector<Property> PropertiesParser::parse(const char* source, std::string_view view) {\n\t\tstd::vector<Property> properties;\n\n\t\tstd::string code(view);\n\t\tstd::size_t source_offset = std::distance(source, view.data());\n\n\t\tLexer lexer(code.data());\n\t\tLexer::Token current = lexer.next();\n\t\twhile (current.type != Lexer::Token::End) {\n\t\t\tstd::optional<Property> property = parseProperty(lexer, current);\n\t\t\tif (property.has_value()) {\n\t\t\t\tstd::size_t property_offset = source_offset + std::distance(code.c_str(), property->name.data());\n\t\t\t\tproperty->name = std::string_view(source + property_offset, property->name.size());\n\n\t\t\t\tstd::size_t uniform_offset = source_offset + std::distance(code.c_str(), property->uniform.data());\n\t\t\t\tproperty->uniform = std::string_view(source + uniform_offset, property->uniform.size());\n\n\t\t\t\tproperties.push_back(property.value());\n\t\t\t}\n\n\t\t\tcurrent = lexer.next();\n\t\t}\n\n\t\treturn properties;\n\t}\n}\n"
  },
  {
    "path": "graphics/shader/propertiesParser.h",
    "content": "#pragma once\n\n#include <optional>\n\nnamespace P3D::Graphics {\n\t\n// <type> <name> [(<uniform>)] [= <default> [(<start> : <stop>)]];\n// vec3 TheInputColor (inputColor) = 0.1 (0:1), 0.2 (-10,10), 0.3;\n\nstruct Property {\n\t\n\tstruct Range {\n\t\tfloat min;\n\t\tfloat max;\n\t};\n\t\n\tstruct Default {\n\t\tfloat value = 0.0;\n\t\tstd::optional<Range> range;\n\t\tstd::optional<float> step;\n\t};\n\n\tenum class Type {\n\t\tNone,\n\t\tBool,\n\t\tInt,\n\t\tFloat,\n\t\tVec2,\n\t\tVec3,\n\t\tVec4,\n\t\tMat2,\n\t\tMat3,\n\t\tMat4,\n\t\tCol3,\n\t\tCol4,\n\t};\n\n\tstd::string_view name;\n\tstd::string_view uniform;\n\tType type = Type::None;\n\tstd::vector<Default> defaults;\n};\n\t\nclass PropertiesParser {\npublic:\n\tstatic std::vector<Property> parse(const char* source, std::string_view view);\n};\n\n}\n"
  },
  {
    "path": "graphics/shader/shader.cpp",
    "content": "#include \"core.h\"\n#include \"shader.h\"\n\n#include <fstream>\n\n#include <GL/glew.h>\n#include <Physics3D/misc/toString.h>\n\n#include \"renderer.h\"\n#include \"debug/guiDebug.h\"\n#include \"util/stringUtil.h\"\n#include \"util/systemVariables.h\"\n\nnamespace P3D::Graphics {\n\n\tShader::Stage::ID Shader::Stage::common = 1;\n\tShader::Stage::ID Shader::Stage::properties = 2;\n\tShader::Stage::ID Shader::Stage::vertex = GL_VERTEX_SHADER;\n\tShader::Stage::ID Shader::Stage::fragment = GL_FRAGMENT_SHADER;\n\tShader::Stage::ID Shader::Stage::geometry = GL_GEOMETRY_SHADER;\n\tShader::Stage::ID Shader::Stage::tesselationControl = GL_TESS_CONTROL_SHADER;\n\tShader::Stage::ID Shader::Stage::tesselationEvaluation = GL_TESS_EVALUATION_SHADER;\n\tShader::Stage::ID Shader::Stage::compute = GL_COMPUTE_SHADER;\n\n\tShader::Stage::Stage(const std::string_view& view) : view(view) {\n\t\t\n\t}\n\n\tShader::Shader() = default;\n\n\tShader::Shader(const std::string& name, const std::string& path, bool isPath) : name(name) {\n\t\tSource source;\n\n\t\t// Parsing\n\t\tif (isPath) {\n\t\t\tstd::ifstream istream;\n\t\t\tistream.open(path);\n\n\t\t\tif (!istream.is_open()) {\n\t\t\t\tLog::error(\"Failed to read path [%s] to parse shader [%s]\", path.c_str(), name.c_str());\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tsource = parse(istream);\n\t\t} else {\n\t\t\tstd::istringstream istream(path);\n\t\t\tsource = parse(istream);\n\t\t}\n\n\t\t// Compilation\n\t\tthis->id = compile(source);\n\n\t\t// Stages\n\t\tthis->code = source.source;\n\t\tfor (const auto& [stage, view] : source.views)\n\t\t\tthis->stages.emplace(stage, Stage(std::string_view(this->code.data() + view.first, view.second)));\n\n\t\t// Properties\n\t\tauto iterator = this->stages.find(Stage::properties);\n\t\tif (iterator != this->stages.end()) {\n\t\t\tthis->properties = PropertiesParser::parse(this->code.data(), iterator->second.view);\n\t\t}\n\t}\n\n\tShader::~Shader() {\n\t\t//Todo fix error Log::info(\"Deleted shader [%s] with id [%u]\", name.c_str(), id); \n\t\tShader::unbind();\n\t\tglDeleteProgram(id);\n\t}\n\n\t\n\tvoid Shader::bind() {\n\t\tRenderer::bindShader(id);\n\t}\n\n\tvoid Shader::unbind() {\n\t\tRenderer::bindShader(0);\n\t}\n\n\tvoid Shader::close() {\n\t\t// Todo remove\n\t}\n\n\tstd::string Shader::getStageName(const Stage::ID& stage) {\n\t\tif (stage == Stage::common)\n\t\t\treturn std::string(\"common\");\n\t\tif (stage == Stage::properties)\n\t\t\treturn std::string(\"properties\");\n\t\tif (stage == Stage::vertex)\n\t\t\treturn std::string(\"vertex\");\n\t\tif (stage == Stage::fragment)\n\t\t\treturn std::string(\"fragment\");\n\t\tif (stage == Stage::geometry)\n\t\t\treturn std::string(\"geometry\");\n\t\tif (stage == Stage::tesselationControl)\n\t\t\treturn std::string(\"tesselation control\");\n\t\tif (stage == Stage::tesselationEvaluation)\n\t\t\treturn std::string(\"tesselation evaluation\");\n\t\tif (stage == Stage::compute)\n\t\t\treturn std::string(\"compute\");\n\n\t\treturn std::string();\n\t}\n\n\tGLID Shader::compile(const Source& source) {\n\t\t// Only OpenGL > 330 is supported\n\t\tif (SystemVariables::get(\"OPENGL_SHADER_VERSION\") < 330) {\n\t\t\tLog::error(\"Shader version [%d] not supported\", SystemVariables::get(\"OPENGL_SHADER_VERSION\"));\n\t\t\treturn 0;\n\t\t}\n\n\t\t// Shader creation\n\t\tGLID program = glCreateProgram();\n\t\tif (program == 0) {\n\t\t\tLog::error(\"Compilation failed, could not create a new program\");\n\t\t\treturn 0;\n\t\t}\n\n\t\t// Get common source\n\t\tauto iterator = source.views.find(Stage::common);\n\t\tstd::string common = iterator != source.views.end() ? source.source.substr(iterator->second.first, iterator->second.second) : std::string();\n\n\t\t// Compilation and attachment\n\t\tstd::vector<GLID> compiledStages;\n\t\tfor (const auto& [stage, view] : source.views) {\n\t\t\tif (stage == Stage::common || stage == Stage::properties)\n\t\t\t\tcontinue;\n\n\t\t\tstd::string code = source.source.substr(view.first, view.second);\n\t\t\tGLID id = compile(common, code, stage);\n\t\t\tif (id == 0) {\n\t\t\t\tLog::error(\"Compilation failed\");\n\n\t\t\t\tfor (GLID compiledStage : compiledStages) {\n\t\t\t\t\tglDetachShader(program, compiledStage);\n\t\t\t\t\tglDeleteShader(compiledStage);\n\t\t\t\t}\n\n\t\t\t\tglDeleteProgram(program);\n\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tglAttachShader(program, id);\n\t\t\tcompiledStages.push_back(id);\n\t\t}\n\n\t\t// Linking and validation\n\t\tglCall(glLinkProgram(program));\n\t\tglCall(glValidateProgram(program));\n\n\t\t// Deletion of stages\n\t\tfor (GLID compiledStage : compiledStages)\n\t\t\tglDeleteShader(compiledStage);\n\n\t\tLog::info(\"Compilation of shader [%d] successful\", program);\n\n\t\treturn program;\n\t}\n\n\tGLID Shader::compile(const std::string& common, const std::string& source, const Stage::ID& stage) {\n\t\tGLID id = glCreateShader(stage);\n\n\t\tif (id == 0) {\n\t\t\tLog::error(\"Failed to create a %s stage\", getStageName(stage).c_str());\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst char* src[] = { common.c_str(), source.c_str() };\n\t\tconst int sizes[] = { static_cast<const int>(common.length()), static_cast<const int>(source.length()) };\n\t\tglShaderSource(id, 2, src, sizes);\n\t\tglCompileShader(id);\n\n\t\tint compiled;\n\t\tglGetShaderiv(id, GL_COMPILE_STATUS, &compiled);\n\t\tif (compiled == GL_FALSE) {\n\t\t\tint length; glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);\n\t\t\tchar* message = static_cast<char*>(alloca(length * sizeof(char)));\n\t\t\tglGetShaderInfoLog(id, length, &length, message);\n\n\t\t\tLog::error(\"Compilation of %s stage failed\", getStageName(stage).c_str());\n\t\t\tLog::error(message);\n\n\t\t\tglDeleteShader(id);\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn id;\n\t}\n\n\tShader::Source Shader::parse(std::istream& istream) {\n\t\tSource source;\n\t\tstd::stringstream code;\n\t\t\n\t\tconstexpr Stage::ID none = 0;\n\t\tStage::ID old = none;\n\t\tStage::ID current = none;\n\n\t\tstd::size_t start = 0;\n\t\tstd::size_t length = 0;\n\t\t\n\t\tstd::string line;\n\t\tstd::size_t lineNumber = 0;\n\t\twhile (getline(istream, line)) {\n\t\t\tcode << line << '\\n';\n\t\t\tlineNumber++;\n\t\t\t\n\t\t\tstd::string trimmedLine = Util::ltrim(line);\n\t\t\tif (trimmedLine.rfind(\"[vertex]\", 0) != std::string::npos) {\n\t\t\t\tcurrent = Stage::vertex;\n\t\t\t} else if (trimmedLine.rfind(\"[fragment]\", 0) != std::string::npos) {\n\t\t\t\tcurrent = Stage::fragment;\n\t\t\t} else if (trimmedLine.rfind(\"[geometry]\", 0) != std::string::npos) {\n\t\t\t\tcurrent = Stage::geometry;\n\t\t\t} else if (trimmedLine.rfind(\"[tesselation control]\", 0) != std::string::npos) {\n\t\t\t\tcurrent = Stage::tesselationControl;\n\t\t\t} else if (trimmedLine.rfind(\"[tesselation evaluate]\", 0) != std::string::npos) {\n\t\t\t\tcurrent = Stage::tesselationEvaluation;\n\t\t\t} else if (trimmedLine.rfind(\"[compute]\", 0) != std::string::npos) {\n\t\t\t\tcurrent = Stage::compute;\n\t\t\t} else if (trimmedLine.rfind(\"[common]\", 0) != std::string::npos) {\n\t\t\t\tcurrent = Stage::common;\n\t\t\t} else if (trimmedLine.rfind(\"[properties]\", 0) != std::string::npos) {\n\t\t\t\tcurrent = Stage::properties;\n\t\t\t}\n\t\t\t\n\t\t\tif (current == none)\n\t\t\t\tLog::warn(\"Code at line [%d] does not belong to a shader stage\", lineNumber);\n\n\t\t\tif (current != old) {\n\t\t\t\tif (old != none) {\n\t\t\t\t\tstd::pair<std::size_t, std::size_t> view(start, length);\n\t\t\t\t\tauto [iterator, inserted] = source.views.emplace(old, view);\n\t\t\t\t\tif (!inserted)\n\t\t\t\t\t\tLog::warn(\"Duplicate shader stages encountered, new stage is discarded\");\n\t\t\t\t}\n\n\t\t\t\tstart += length + line.length() + 1;\n\t\t\t\tlength = 0;\n\t\t\t\told = current;\n\t\t\t\t\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\tlength += line.length() + 1;\n\t\t}\n\n\t\t// Last stage\n\t\tstd::pair<std::size_t, std::size_t> view(start, length);\n\t\tauto [iterator, inserted] = source.views.emplace(old, view);\n\t\tif (!inserted)\n\t\t\tLog::warn(\"Duplicate shader stages encountered, new stage is discarded\");\n\n\t\tsource.source = code.str();\n\n\t\treturn source;\n\t}\n\n\tint Shader::getUniform(const std::string& uniform) {\n\t\tif (id == 0) {\n\t\t\tLog::warn(\"Requesting a uniform [%s] from an empty shader [%s]\", uniform.c_str(), name.c_str()); \\\n\t\t\t\treturn -1;\n\t\t}\n\t\t\n\t\tauto iterator = uniforms.find(uniform);\n\t\tif (iterator != uniforms.end())\n\t\t\treturn iterator->second;\n\n\t\tint location = glGetUniformLocation(id, uniform.c_str());\n\t\tif (location != -1) {\n\t\t\tLog::debug(\"Created uniform [%s] with id [%d] in shader [%s] \", uniform.c_str(), location, name.c_str());\n\t\t\tuniforms.emplace(uniform, location);\n\t\t\treturn location;\n\t\t}\n\t\t\n\t\tLog::warn(\"Uniform [%s] not found in shader [%s]\", uniform.c_str(), name.c_str());\n\t\tuniforms.emplace(uniform, location);\n\t\treturn -1;\n\t}\n\n\tvoid Shader::addUniform(const std::string& uniform) {\n\t\tif (uniforms.find(uniform) == uniforms.end())\n\t\t\tcreateUniform(uniform);\n\t}\n\n\tvoid Shader::createUniform(const std::string& uniform) {\n\t\tLog::subject s(name);\n\t\t\n\t\tif (id == 0) {\n\t\t\tLog::warn(\"Creating a uniform [%s] in an empty shader [%s]\", uniform.c_str(), name.c_str());\n\t\t\treturn;\n\t\t}\n\t\t\n\t\tbind();\n\t\tint location = glGetUniformLocation(id, uniform.c_str());\n\t\t\n\t\tif (location == -1) {\n\t\t\tLog::warn(\"Uniform [%s] not found in shader [%s]\", uniform.c_str(), name.c_str());\n\t\t\treturn;\n\t\t}\n\t\t\n\t\tuniforms.emplace(uniform, location);\n\t\tLog::debug(\"Created uniform [%s] with id [%d] in shader [%s] \", uniform.c_str(), location, name.c_str());\n\t}\n\n//Log::warn(\"Setting an unknown uniform [%s] in a shader [%s]\", uniform.c_str(), name.c_str()); \n#define UNIFORM_CHECK(uniform) \\\n\tthis->getUniform(uniform); \\\n\tif (id == 0) { \\\n\t\tLog::warn(\"Setting a uniform [%s] in an empty shader [%s]\", uniform.c_str(), name.c_str()); \\\n\t\treturn; \\\n\t} \\\n\tif (location == -1) \\\n\t\treturn;\n\t\n\tvoid Shader::setUniform(const std::string& uniform, GLID value) {\n\t\tint location = UNIFORM_CHECK(uniform);\n\n\t\tglUniform1i(location, value);\n\t}\n\n\tvoid Shader::setUniform(const std::string& uniform, int value) {\n\t\tint location = UNIFORM_CHECK(uniform);\n\n\t\tglUniform1i(location, value);\n\t}\n\n\tvoid Shader::setUniform(const std::string& uniform, float value) {\n\t\tint location = UNIFORM_CHECK(uniform);\n\t\t\n\t\tglUniform1f(location, value);\n\t}\n\n\tvoid Shader::setUniform(const std::string& uniform, const Vec2f& value) {\n\t\tint location = UNIFORM_CHECK(uniform);\n\n\t\tglUniform2f(location, value.x, value.y);\n\t}\n\n\tvoid Shader::setUniform(const std::string& uniform, const Vec3f& value) {\n\t\tint location = UNIFORM_CHECK(uniform);\n\n\t\tglUniform3f(location, value.x, value.y, value.z);\n\t}\n\n\tvoid Shader::setUniform(const std::string& uniform, const Position& value) {\n\t\tint location = UNIFORM_CHECK(uniform);\n\n\t\tglUniform3f(location, static_cast<float>(value.x), static_cast<float>(value.y), static_cast<float>(value.z));\n\t}\n\n\tvoid Shader::setUniform(const std::string& uniform, const Vec4f& value) {\n\t\tint location = UNIFORM_CHECK(uniform);\n\t\t\n\t\tglUniform4f(uniforms.at(uniform), value.x, value.y, value.z, value.w);\n\t}\n\n\tvoid Shader::setUniform(const std::string& uniform, const Mat2f& value) {\n\t\tint location = UNIFORM_CHECK(uniform);\n\t\t\n\t\tfloat buf[4];\n\t\tvalue.toColMajorData(buf);\n\t\tglUniformMatrix2fv(location, 1, GL_FALSE, buf);\n\t}\n\n\tvoid Shader::setUniform(const std::string& uniform, const Mat3f& value) {\n\t\tint location = UNIFORM_CHECK(uniform);\n\n\t\tfloat buf[9];\n\t\tvalue.toColMajorData(buf);\n\t\tglUniformMatrix3fv(location, 1, GL_FALSE, buf);\n\t}\n\n\tvoid Shader::setUniform(const std::string& uniform, const Mat4f& value) {\n\t\tint location = UNIFORM_CHECK(uniform);\n\t\t\n\t\tfloat buf[16];\n\t\tvalue.toColMajorData(buf);\n\t\tglUniformMatrix4fv(location, 1, GL_FALSE, buf);\n\t}\n\n\tCShader::CShader(const std::string& name, const std::string& path, bool isPath) : Shader(name, path, isPath) {\n\n\t}\n\n\tvoid CShader::dispatch(unsigned int x, unsigned int y, unsigned int z) {\n\t\tglDispatchCompute(x, y, z);\n\t}\n\n\tvoid CShader::barrier(unsigned int flags) {\n\t\tglMemoryBarrier(flags);\n\t}\n\t\n}\n"
  },
  {
    "path": "graphics/shader/shader.h",
    "content": "#pragma once\n\n#include \"../bindable.h\"\n#include \"propertiesParser.h\"\n\nnamespace P3D::Graphics {\n\n\tclass Shader : public Bindable {\n\tpublic:\n\t\tstruct Stage {\n\t\t\tusing ID = unsigned;\n\t\t\tstatic ID common;\n\t\t\tstatic ID properties;\n\t\t\tstatic ID vertex;\n\t\t\tstatic ID geometry;\n\t\t\tstatic ID fragment;\n\t\t\tstatic ID tesselationControl;\n\t\t\tstatic ID tesselationEvaluation;\n\t\t\tstatic ID compute;\n\t\t\t\n\t\t\tstd::string_view view;\n\t\t\t\n\t\t\texplicit Stage(const std::string_view& view);\n\t\t};\n\n\t\tstruct Source {\n\t\t\tstd::string source;\n\t\t\tstd::unordered_map<Stage::ID, std::pair<std::size_t, std::size_t>> views;\n\t\t};\n\n\t\tstd::string name;\n\t\tstd::string code;\n\t\tstd::unordered_map<Stage::ID, Stage> stages;\n\t\tstd::unordered_map<std::string, int> uniforms;\n\t\tstd::vector<Property> properties;\n\n\t\tShader();\n\t\tShader(const std::string& name, const std::string& path, bool isPath);\n\t\tvirtual ~Shader();\n\n\t\tShader(const Shader&) = delete;\n\t\tShader(Shader&&) noexcept = delete;\n\t\tShader& operator=(const Shader&) = delete;\n\t\tShader& operator=(Shader&& other) noexcept = delete;\n\n\t\t[[nodiscard]] static std::string getStageName(const Stage::ID& stage);\n\t\t[[nodiscard]] static GLID compile(const Source& source);\n\t\t[[nodiscard]] static GLID compile(const std::string& common, const std::string& source, const Stage::ID& stage);\n\t\t[[nodiscard]] static Source parse(std::istream& istream);\n\t\t\n\t\tvoid bind() override;\n\t\tvoid unbind() override;\n\t\tvoid close() override;\n\t\t\n\t\t[[nodiscard]] int getUniform(const std::string& uniform);\n\t\tvoid addUniform(const std::string& uniform);\n\t\tvoid createUniform(const std::string& uniform);\n\t\tvoid setUniform(const std::string& uniform, int value);\n\t\tvoid setUniform(const std::string& uniform, GLID value);\n\t\tvoid setUniform(const std::string& uniform, float value);\n\t\tvoid setUniform(const std::string& uniform, const Vec2f& value);\n\t\tvoid setUniform(const std::string& uniform, const Vec3f& value);\n\t\tvoid setUniform(const std::string& uniform, const Vec4f& value);\n\t\tvoid setUniform(const std::string& uniform, const Mat2f& value);\n\t\tvoid setUniform(const std::string& uniform, const Mat3f& value);\n\t\tvoid setUniform(const std::string& uniform, const Mat4f& value);\n\t\tvoid setUniform(const std::string& uniform, const Position& value);\n\t};\n\n\tclass CShader : public Shader {\n\tpublic:\n\t\tCShader(const std::string& name, const std::string& path, bool isPath);\n\t\t\n\t\tvoid dispatch(unsigned int x, unsigned int y, unsigned int z);\n\t\tvoid barrier(unsigned int flags);\n\t};\n\t\n}\n"
  },
  {
    "path": "graphics/shader/shaders.cpp",
    "content": "#include \"core.h\"\n\n#include \"shaders.h\"\n#include \"texture.h\"\n\n#include \"../util/resource/resourceManager.h\"\n#include \"../graphics/renderer.h\"\n\n#include <sstream>\n\nnamespace P3D::Graphics {\n\nnamespace Shaders {\nSRef<GuiShader> guiShader;\nSRef<QuadShader> quadShader;\nSRef<BlurShader> horizontalBlurShader;\nSRef<BlurShader> verticalBlurShader;\n\nvoid onInit() {\n\tstd::string guiShaderSource =\n\t\tR\"(\n\t\t\t[common]\n\t\t\t#version 330 core\n\t\t\t[vertex]\n\t\t\tlayout(location = 0) in vec2 vposition;\n\t\t\tlayout(location = 1) in vec2 vuv;\n\t\t\tlayout(location = 2) in vec4 vcolor;\n\t\t\tuniform mat4 projectionMatrix;\n\t\t\tout vec4 fcolor;out vec2 fuv;\n\t\t\tvoid main() {\n\t\t\t\tgl_Position = projectionMatrix * vec4(vposition, 0.0, 1.0);\n\t\t\t\tfcolor = vcolor;\n\t\t\t\tfuv = vuv;\n\t\t\t}\n\t\t\t[fragment]\n\t\t\tout vec4 outColor;\n\t\t\tin vec2 fuv;\n\t\t\tin vec4 fcolor;\n\t\t\tuniform sampler2D textureSampler;\n\t\t\tuniform bool textured = false;\n\t\t\tvoid main() {\n\t\t\t\toutColor = (textured) ? texture(textureSampler, fuv) * fcolor : fcolor;\n\t\t\t}\n\t\t)\";\n\n\tstd::string quadShaderSource =\n\t\tR\"(\n\t\t\t[common]\n\t\t\t#version 330 core\n\t\t\t[vertex]\n\t\t\tlayout(location = 0) \n\t\t\tin vec4 vposition;\n\t\t\tuniform mat4 projectionMatrix;\n\t\t\tout vec2 fUV;\n\t\t\tvoid main() {\n\t\t\t\tgl_Position = projectionMatrix * vec4(vposition.xy, 0.0, 1.0);fUV = vposition.zw;\n\t\t\t}\n\t\t\t[fragment]\n\t\t\tout vec4 outColor;\n\t\t\tin vec2 fUV;\n\t\t\tuniform bool textured;\n\t\t\tuniform sampler2D textureSampler;\n\t\t\tuniform vec4 color = vec4(1, 1, 1, 1);\n\t\t\tvoid main() {\n\t\t\t\toutColor = (textured) ? texture(textureSampler, fUV) * color : color;\n\t\t\t}\n\t\t)\";\n\n\tstd::string horizontalBlurShaderVertexSource =\n\t\tR\"(\n\t\t\t[common]\n\t\t\t#version 330\n\t\t\t[vertex]\n\t\t\tlayout(location = 0) in vec2 vposition;\n\t\t\tout vec2 fUV[15];\n\t\t\tuniform float width = 3.0;\n\t\t\tvoid main() {\n\t\t\t\tfloat part = 1.0 / width;\n\t\t\t\tvec2 UV = vposition * 0.5 + 0.5;\n\t\t\t\tgl_Position = vec4(vposition, 0.0, 1.0);\n\t\t\t\tfUV[0]  = UV + vec2(0.0, -part * 7.0);\n\t\t\t\tfUV[1]  = UV + vec2(0.0, -part * 6.0);\n\t\t\t\tfUV[2]  = UV + vec2(0.0, -part * 5.0);\n\t\t\t\tfUV[3]  = UV + vec2(0.0, -part * 4.0);\n\t\t\t\tfUV[4]  = UV + vec2(0.0, -part * 3.0);\n\t\t\t\tfUV[5]  = UV + vec2(0.0, -part * 2.0);\n\t\t\t\tfUV[6]  = UV + vec2(0.0, -part);\n\t\t\t\tfUV[7]  = UV;\n\t\t\t\tfUV[8]  = UV + vec2(0.0,  part);\n\t\t\t\tfUV[9]  = UV + vec2(0.0,  part * 2.0);\n\t\t\t\tfUV[10] = UV + vec2(0.0,  part * 3.0);\n\t\t\t\tfUV[11] = UV + vec2(0.0,  part * 4.0);\n\t\t\t\tfUV[12] = UV + vec2(0.0,  part * 5.0);\n\t\t\t\tfUV[13] = UV + vec2(0.0,  part * 6.0);\n\t\t\t\tfUV[13] = UV + vec2(0.0,  part * 7.0);\n\t\t\t}\n\t\t)\";\n\n\tstd::string verticalBlurShaderVertexSource =\n\t\tR\"(\n\t\t\t[common]\n\t\t\t#version 330\n\t\t\t[vertex]\n\t\t\tlayout(location = 0) in vec2 vposition;\n\t\t\tout vec2 fUV[15];\n\t\t\tuniform float width = 3.0;\n\t\t\tvoid main() {\n\t\t\t\tfloat part = 1.0 / width;\n\t\t\t\tvec2 UV = vposition * 0.5 + 0.5;\n\t\t\t\tgl_Position = vec4(vposition, 0.0, 1.0);\n\t\t\t\tfUV[0]  = UV + vec2(-part * 7.0, 0.0);\n\t\t\t\tfUV[1]  = UV + vec2(-part * 6.0, 0.0);\n\t\t\t\tfUV[2]  = UV + vec2(-part * 5.0, 0.0);\n\t\t\t\tfUV[3]  = UV + vec2(-part * 4.0, 0.0);\n\t\t\t\tfUV[4]  = UV + vec2(-part * 3.0, 0.0);\n\t\t\t\tfUV[5]  = UV + vec2(-part * 2.0, 0.0);\n\t\t\t\tfUV[6]  = UV + vec2(-part, 0.0);\n\t\t\t\tfUV[7]  = UV;\n\t\t\t\tfUV[8]  = UV + vec2(part, 0.0);\n\t\t\t\tfUV[9]  = UV + vec2(part * 2.0, 0.0);\n\t\t\t\tfUV[10] = UV + vec2(part * 3.0, 0.0);\n\t\t\t\tfUV[11] = UV + vec2(part * 4.0, 0.0);\n\t\t\t\tfUV[12] = UV + vec2(part * 5.0, 0.0);\n\t\t\t\tfUV[13] = UV + vec2(part * 6.0, 0.0);\n\t\t\t\tfUV[14] = UV + vec2(part * 7.0, 0.0);\n\t\t\t}\n\t\t)\";\n\n\tstd::string blurShaderFragmentSource =\n\t\tR\"(\n\t\t\t[fragment]\n\t\t\tin vec2 fUV[15];\n\t\t\tout vec4 outColor;\n\t\t\tuniform sampler2D image;\n\t\t\tvoid main() {\n\t\t\t\toutColor = vec4(0.0);\n\t\t\t\toutColor += texture(image, fUV[0]) * 0.0044299121055113265;\n\t\t\t\toutColor += texture(image, fUV[1]) * 0.00895781211794;\n\t\t\t\toutColor += texture(image, fUV[2]) * 0.0215963866053;\n\t\t\t\toutColor += texture(image, fUV[3]) * 0.0443683338718;\n\t\t\t\toutColor += texture(image, fUV[4]) * 0.0776744219933;\n\t\t\t\toutColor += texture(image, fUV[5]) * 0.115876621105;\n\t\t\t\toutColor += texture(image, fUV[6]) * 0.147308056121;\n\t\t\t\toutColor += texture(image, fUV[7]) * 0.159576912161;\n\t\t\t\toutColor += texture(image, fUV[8]) * 0.147308056121;\n\t\t\t\toutColor += texture(image, fUV[9]) * 0.115876621105;\n\t\t\t\toutColor += texture(image, fUV[10]) * 0.0776744219933;\n\t\t\t\toutColor += texture(image, fUV[11]) * 0.0443683338718;\n\t\t\t\toutColor += texture(image, fUV[12]) * 0.0215963866053;\n\t\t\t\toutColor += texture(image, fUV[13]) * 0.00895781211794;\n\t\t\t\toutColor += texture(image, fUV[14]) * 0.0044299121055113265;\n\t\t\t}\n\t\t)\";\n\n\t// GShader source init\n\tstd::string horizontalBlurShaderSource(horizontalBlurShaderVertexSource + blurShaderFragmentSource);\n\tstd::string verticalBlurShaderSource(verticalBlurShaderVertexSource + blurShaderFragmentSource);\n\n\t// GShader init\n\tguiShader = std::make_shared<GuiShader>(guiShaderSource);\n\tquadShader = std::make_shared<QuadShader>(quadShaderSource);\n\thorizontalBlurShader = std::make_shared<BlurShader>(horizontalBlurShaderSource);\n\tverticalBlurShader = std::make_shared<BlurShader>(verticalBlurShaderSource);\n\n\tResourceManager::add(guiShader.get());\n\tResourceManager::add(quadShader.get());\n\tResourceManager::add(horizontalBlurShader.get());\n\tResourceManager::add(verticalBlurShader.get());\n}\n\nvoid onClose() {\n\thorizontalBlurShader->close();\n\tverticalBlurShader->close();\n\tguiShader->close();\n\tquadShader->close();\n}\n}\n\n\n// GuiShader\n\nvoid GuiShader::init(const Mat4f& orthoMatrix) {\n\tbind();\n\tsetUniform(\"projectionMatrix\", orthoMatrix);\n\tsetUniform(\"textureSampler\", 0);\n}\n\nvoid GuiShader::setTextured(bool textured) {\n\tbind();\n\tsetUniform(\"textured\", textured);\n}\n\n\n// QuadShader\n\nvoid QuadShader::updateProjection(const Mat4f& projectionMatrix) {\n\tbind();\n\tsetUniform(\"projectionMatrix\", projectionMatrix);\n}\n\nvoid QuadShader::updateColor(const Vec4& color) {\n\tbind();\n\tsetUniform(\"textured\", false);\n\tsetUniform(\"color\", color);\n}\n\nvoid QuadShader::updateTexture(GLID texture, GLID unit) {\n\tupdateTexture(texture, unit, Vec4f::full(1.0f));\n}\n\nvoid QuadShader::updateTexture(GLID texture, GLID unit, const Vec4f& color) {\n\tbind();\n\tRenderer::activeTexture(unit);\n\tRenderer::bindTexture2D(texture);\n\tsetUniform(\"textured\", true);\n\tsetUniform(\"textureSampler\", unit);\n\tsetUniform(\"color\", color);\n}\n\n\n// BlurShader\nvoid BlurShader::updateWidth(float width) {\n\tbind();\n\tsetUniform(\"width\", width);\n}\n\nvoid BlurShader::updateTexture(SRef<Texture> texture) {\n\tbind();\n\ttexture->bind();\n\tsetUniform(\"image\", texture->getUnit());\n}\n\n};"
  },
  {
    "path": "graphics/shader/shaders.h",
    "content": "#pragma once\n\n#include \"shader.h\"\n#include \"../graphics/resource/shaderResource.h\"\n#include <Physics3D/math/linalg/mat.h>\n\nnamespace P3D::Graphics {\nclass Texture;\n\nstruct GuiShader : public ShaderResource {\n\texplicit GuiShader(const std::string& source) : ShaderResource(\"GuiShader\", source, false) {}\n\n\tvoid init(const Mat4f& orthoMatrix);\n\tvoid setTextured(bool textured);\n};\n\nstruct QuadShader : public ShaderResource {\n\texplicit QuadShader(const std::string& source) : ShaderResource(\"QuadShader\", source, false) {}\n\n\tvoid updateProjection(const Mat4f& projectionMatrix);\n\tvoid updateColor(const Vec4& color);\n\tvoid updateTexture(GLID texture, GLID unit);\n\tvoid updateTexture(GLID texture, GLID unit, const Vec4f& color);\n};\n\nstruct BlurShader : public ShaderResource {\n\texplicit BlurShader(const std::string& source) : ShaderResource(\"BlurShader\", source, false) {}\n\n\tvoid updateWidth(float width);\n\tvoid updateTexture(SRef<Texture> texture);\n};\n\nnamespace Shaders {\n\t\nextern SRef<GuiShader> guiShader;\nextern SRef<QuadShader> quadShader;\nextern SRef<BlurShader> horizontalBlurShader;\nextern SRef<BlurShader> verticalBlurShader;\n\nvoid onInit();\nvoid onClose();\n}\n\n};"
  },
  {
    "path": "graphics/texture.cpp",
    "content": "#include \"core.h\"\n\n#include \"texture.h\"\n\n#include <GL/glew.h>\n#include <GLFW/glfw3.h>\n\n#define STB_IMAGE_IMPLEMENTATION\n#include <stb_image.h>\n\nnamespace P3D::Graphics {\n\n#pragma region Texture\n\n//! Texture\n\nSRef<Texture> Texture::_white;\n\nint getChannelsFromFormat(int format) {\n\tswitch (format) {\n\t\tcase GL_RED:\n\t\tcase GL_GREEN:\n\t\tcase GL_BLUE:\n\t\tcase GL_ALPHA:\n\t\t\treturn 1;\n\t\tcase GL_RG:\n\t\t\treturn 2;\n\t\tcase GL_RGB:\n\t\t\treturn 3;\n\t\tcase GL_RGBA:\n\t\t\treturn 4;\n\t\tdefault:\n\t\t\tLog::warn(\"Unknown format: %x, assuming 4 channels\", format);\n\t\t\treturn 4;\n\t}\n\n}\n\nint getFormatFromChannels(int channels) {\n\tswitch (channels) {\n\t\tcase 1:\n\t\t\treturn GL_RED;\n\t\tcase 2:\n\t\t\treturn GL_RG;\n\t\tcase 3:\n\t\t\treturn GL_RGB;\n\t\tcase 4:\n\t\t\treturn GL_RGBA;\n\t\tdefault:\n\t\t\tLog::warn(\"Unknown amount of channels: %d, assuming RGB\", channels);\n\t\t\treturn GL_RGB;\n\t}\n}\n\nTexture Texture::load(const std::string& name) {\n\tint width;\n\tint height;\n\tint channels;\n\n\t//stbi_set_flip_vertically_on_load(true);\n\n\tunsigned char* data = stbi_load(name.c_str(), &width, &height, &channels, 0);\n\n\tif (data) {\n\t\tint format = getFormatFromChannels(channels);\n\n\t\tTexture texture(width, height, data, format);\n\n\t\tstbi_image_free(data);\n\n\t\treturn texture;\n\t} else {\n\t\tLog::subject s(name);\n\t\tLog::error(\"Failed to load texture\");\n\n\t\treturn Texture();\n\t}\n}\n\nSRef<Texture> Texture::white() {\n\tif (_white == nullptr) {\n\t\tColor buffer = Colors::WHITE;\n\t\t_white = std::make_shared<Texture>(1, 1, &buffer, GL_RGBA);\n\t}\n\n\treturn _white;\n}\n\nTexture::Texture() : width(0), height(0), internalFormat(0), format(0), target(0), type(0), unit(0), channels(0) {\n\n}\n\nTexture::Texture(int width, int height) : Texture(width, height, nullptr, GL_RGBA) {\n\n}\n\nTexture::Texture(int width, int height, const void* buffer, int format) : Texture(width, height, buffer, GL_TEXTURE_2D, format, format, GL_UNSIGNED_BYTE) {\n\n}\n\nTexture::Texture(int width, int height, const void* buffer, int target, int format, int internalFormat, int type) : width(width), height(height), target(target), format(format), internalFormat(internalFormat), type(type), unit(0) {\n\tglGenTextures(1, &id);\n\n\tchannels = getChannelsFromFormat(format);\n\n\tTexture::bind();\n\tTexture::create(target, 0, internalFormat, width, height, 0, format, type, buffer);\n\tglTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n\tglTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n\tglTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n\tglTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n\tTexture::unbind();\n}\n\nvoid Texture::create(int target, int level, int internalFormat, int width, int height, int border, int format, int type, const void* buffer) {\n\tglTexImage2D(target, 0, internalFormat, width, height, 0, format, type, buffer);\n}\n\nTexture::Texture(Texture&& other) : Bindable(other.id), width(other.width), height(other.height), internalFormat(other.internalFormat), format(other.format), target(other.target), type(other.type), unit(other.unit), channels(other.channels) {\n\tother.id = 0;\n\tother.width = 0;\n\tother.height = 0;\n\tother.type = 0;\n\tother.internalFormat = 0;\n\tother.format = 0;\n\tother.channels = 0;\n\tother.type = 0;\n\tother.unit = 0;\n}\n\t\nTexture& Texture::operator=(Texture&& other) {\n\tif (this != &other) {\n\t\tid = 0;\n\t\twidth = 0;\n\t\theight = 0;\n\t\ttype = 0;\n\t\tinternalFormat = 0;\n\t\tformat = 0;\n\t\tchannels = 0;\n\t\ttype = 0;\n\t\tunit = 0;\n\t\tstd::swap(id, other.id);\n\t\tstd::swap(width, other.width);\n\t\tstd::swap(height, other.height);\n\t\tstd::swap(internalFormat, other.internalFormat);\n\t\tstd::swap(format, other.format);\n\t\tstd::swap(target, other.target);\n\t\tstd::swap(type, other.type);\n\t\tstd::swap(unit, other.unit);\n\t\tstd::swap(channels, other.channels);\n\t}\n\treturn *this;\n}\n\nTexture::~Texture() {\n\tif (id == 0)\n\t\treturn;\n\n\tLog::warn(\"Closed texture #%d\", id);\n\tglDeleteTextures(1, &id);\n}\n\nvoid Texture::loadFrameBufferTexture(int width, int height) {\n\tbind();\n\tglCopyTexImage2D(target, 0, internalFormat, 0, 0, width, height, 0);\n\tunbind();\n}\n\nvoid Texture::resize(int width, int height, const void* buffer) {\n\tbind();\n\tglTexImage2D(target, 0, internalFormat, width, height, 0, format, type, buffer);\n\tunbind();\n}\n\t\nSRef<Texture> Texture::colored(const Color& color) {\n\tbind();\n\tunsigned char* buffer = (unsigned char*) malloc(width * height * channels);\n\n\tglGetTexImage(target, 0, format, type, buffer);\n\n\tfor (int j = 0; j < height; j++) {\n\t\tfor (int i = 0; i < width; i++) {\n\t\t\tfor (int k = 0; k < channels; k++) {\n\n\t\t\t\tint index = (i + height * j) * channels + k;\n\t\t\t\tunsigned char value = static_cast<unsigned char>(buffer[index] * color.data[k]);\n\t\t\t\tbuffer[index] = value;\n\t\t\t}\n\t\t}\n\t}\n\n\tSRef<Texture> texture = std::make_shared<Texture>(width, height, buffer, format);\n\n\tfree(buffer);\n\n\treturn texture;\n}\n\nvoid Texture::generateMipmap() {\n\tbind();\n\tglGenerateMipmap(target);\n\tglTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);\n}\n\nvoid Texture::resize(int width, int height) {\n\tresize(width, height, nullptr);\n}\n\nvoid Texture::bind(int unit) {\n\tthis->unit = unit;\n\tglActiveTexture(GL_TEXTURE0 + unit);\n\tglBindTexture(target, id);\n}\n\nvoid Texture::bind() {\n\tbind(unit);\n}\n\nvoid Texture::unbind() {\n\tglBindTexture(target, 0);\n}\n\nvoid Texture::close() {\n\t// Todo remove\n}\n\nfloat Texture::getAspect() const {\n\treturn static_cast<float>(width) / static_cast<float>(height);\n}\n\nint Texture::getWidth() const {\n\treturn width;\n}\n\nint Texture::getHeight() const {\n\treturn height;\n}\n\nint Texture::getInternalFormat() const {\n\treturn internalFormat;\n}\n\nint Texture::getFormat() const {\n\treturn format;\n}\n\nint Texture::getTarget() const {\n\treturn target;\n}\n\nint Texture::getType() const {\n\treturn type;\n}\n\nint Texture::getChannels() const {\n\treturn channels;\n}\n\nint Texture::getUnit() const {\n\treturn unit;\n}\n\nvoid Texture::setUnit(int unit) {\n\tthis->unit = unit;\n}\n\n#pragma endregion\n\n#pragma region HDRTexture\n\n//! HDRTexture\n\nHDRTexture::HDRTexture(int width, int height) : HDRTexture(width, height, nullptr) {\n\n};\n\nHDRTexture::HDRTexture(int width, int height, const void* buffer) : Texture(width, height, buffer, GL_TEXTURE_2D, GL_RGBA, GL_RGBA16F, GL_FLOAT) {\n\n}\n\n#pragma endregion\n\n#pragma region TextureMultisample\n\n//! TextureMultisample\n\nMultisampleTexture::MultisampleTexture(int width, int height, int samples) : Texture(width, height, nullptr, GL_TEXTURE_2D_MULTISAMPLE, 0, GL_RGBA, 0), samples(samples) {\n\tglGenTextures(1, &id);\n\tbind();\n\tcreate(target, 0, internalFormat, width, height, 0, format, type, nullptr);\n\tglTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST);\n\tglTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST);\n\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n\tunbind();\n}\n\nvoid MultisampleTexture::create(int target, int level, int internalFormat, int width, int height, int border, int format, int type, const void* buffer) {\n\tglTexImage2DMultisample(target, samples, internalFormat, width, height, GL_TRUE);\n}\n\nvoid MultisampleTexture::resize(int width, int height) {\n\tbind();\n\tglTexImage2DMultisample(target, samples, internalFormat, width, height, GL_TRUE);\n\tunbind();\n}\n\n#pragma endregion\n\n#pragma region CubeMap\n\n//! CubeMap\n\nCubeMap::CubeMap(const std::string& right, const std::string& left, const std::string& top, const std::string& bottom, const std::string& front, const std::string& back) : Texture(0, 0, nullptr, GL_TEXTURE_CUBE_MAP, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE) {\n\tbind();\n\tload(right, left, top, bottom, front, back);\n\tglTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);\n\tunbind();\n}\n\nvoid CubeMap::create(int target, int level, int internalFormat, int width, int height, int border, int format, int type, const void* buffer) {\n\n}\n\nvoid CubeMap::load(const std::string& right, const std::string& left, const std::string& top, const std::string& bottom, const std::string& front, const std::string& back) {\n\tunsigned char* data;\n\tstd::string faces[6] = { right, left, top, bottom, front, back };\n\n\tstbi_set_flip_vertically_on_load(false);\n\n\tfor (int i = 0; i < 6; i++) {\n\t\tdata = stbi_load(faces[i].c_str(), &width, &height, &channels, 0);\n\n\t\tformat = internalFormat = getFormatFromChannels(channels);\n\n\t\tif (data) {\n\t\t\tglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, format, width, height, 0, internalFormat, type, data);\n\t\t\t//glGenerateMipmap(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i);\n\t\t} else {\n\t\t\tLog::subject s(faces[i]);\n\t\t\tLog::error(\"Failed to load texture\");\n\t\t}\n\n\t\tstbi_image_free(data);\n\t}\n}\n\nvoid CubeMap::resize(int width, int height) {\n\tLog::error(\"Resizing of cubemap not supported yet\");\n}\n\n#pragma endregion\n\n#pragma region DepthTexture\n\n//! DepthTexture\n\nDepthTexture::DepthTexture(int width, int height) : Texture(width, height, nullptr, GL_TEXTURE_2D, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_FLOAT) {\n\n}\n\n#pragma endregion\n\n};"
  },
  {
    "path": "graphics/texture.h",
    "content": "#pragma once\n\n#include \"bindable.h\"\n#include \"gui/color.h\"\n\nnamespace P3D::Graphics {\n\nclass Texture : public Bindable {\nprivate:\n\tstatic SRef<Texture> _white;\n\nprotected:\n\tint width;\n\tint height;\n\tint internalFormat;\n\tint format;\n\tint target;\n\tint type;\n\n\tint unit;\n\tint channels;\n\n\tvirtual void create(int target, int level, int internalFormat, int width, int height, int border, int format, int type, const void* buffer);\n\npublic:\n\tTexture();\n\tTexture(int width, int height);\n\tTexture(int width, int height, const void* buffer, int format);\n\tTexture(int width, int height, const void* buffer, int target, int format, int internalFormat, int type);\n\n\t~Texture();\n\tTexture(Texture&& other);\n\tTexture(const Texture&) = delete;\n\tTexture& operator=(Texture&& other);\n\tTexture& operator=(const Texture&) = delete;\n\t\n\tvirtual void bind(int unit);\n\tvirtual void bind() override;\n\tvirtual void unbind() override;\n\tvirtual void close() override;\n\n\tvirtual void resize(int width, int height);\n\tvirtual void resize(int width, int height, const void* buffer);\n\n\tvoid loadFrameBufferTexture(int width, int height);\n\n\tSRef<Texture> colored(const Color& color);\n\tvoid generateMipmap();\n\n\tstatic Texture load(const std::string& name);\n\tstatic SRef<Texture> white();\n\n\t[[nodiscard]] float getAspect() const;\n\t[[nodiscard]] int getWidth() const;\n\t[[nodiscard]] int getHeight() const;\n\t[[nodiscard]] int getInternalFormat() const;\n\t[[nodiscard]] int getFormat() const;\n\t[[nodiscard]] int getTarget() const;\n\t[[nodiscard]] int getType() const;\n\t[[nodiscard]] int getChannels() const;\n\t[[nodiscard]] int getUnit() const;\n\n\tvoid setUnit(int unit);\n};\n\n\nclass HDRTexture : public Texture {\npublic:\n\tHDRTexture(int width, int height, const void* buffer);\n\tHDRTexture(int width, int height);\n};\n\nclass MultisampleTexture : public Texture {\nprotected:\n\tint samples;\n\n\tvirtual void create(int target, int level, int internalFormat, int width, int height, int border, int format, int type, const void* buffer) override;\n\npublic:\n\tMultisampleTexture(int width, int height, int samples);\n\n\tvoid resize(int width, int height) override;\n};\n\nclass CubeMap : public Texture {\nprotected:\n\tvirtual void create(int target, int level, int internalFormat, int width, int height, int border, int format, int type, const void* buffer) override;\n\npublic:\n\tCubeMap(const std::string& right, const std::string& left, const std::string& top, const std::string& bottom, const std::string& front, const std::string& back);\n\n\tvoid load(const std::string& right, const std::string& left, const std::string& top, const std::string& bottom, const std::string& front, const std::string& back);\n\n\tvoid resize(int width, int height) override;\n};\n\nclass DepthTexture : public Texture {\npublic:\n\tDepthTexture(int width, int height);\n};\n\n};"
  },
  {
    "path": "install/clean.bat",
    "content": "\ncd %~dp0..\n\nrmdir /S /Q include\nrmdir /S /Q vcpkg\nrmdir /S /Q build\n"
  },
  {
    "path": "install/clean.sh",
    "content": "\n# gets directory of this file to find the others\nINSTALLPATH=\"$( cd \"$(dirname \"$0\")\" >/dev/null 2>&1 ; pwd -P )\"\ncd $INSTALLPATH/..\n\nrm -rf include\nrm -rf build\nrm -rf vcpkg\n"
  },
  {
    "path": "install/setup.bat",
    "content": "\necho Installing dependencies\n\ncall %~dp0\\setupDependencies.bat\n\necho Creating build directories\n\ncall %~dp0\\setupBuild.bat\n\necho Done\n"
  },
  {
    "path": "install/setup.sh",
    "content": "#!/bin/sh\n\n# gets directory of this file to find the others\nINSTALLPATH=\"$( cd \"$(dirname \"$0\")\" >/dev/null 2>&1 ; pwd -P )\"\n\necho Installing dependencies\n\nsh $INSTALLPATH/setupDependencies.sh\n\necho Creating build directories\n\nsh $INSTALLPATH/setupBuild.sh\n\necho Done\n\n"
  },
  {
    "path": "install/setupBuild.bat",
    "content": "\nmkdir %~dp0..\\build\nmkdir %~dp0..\\build_debug\n\ncmake -DCMAKE_TOOLCHAIN_FILE=%~dp0..\\vcpkg\\scripts\\buildsystems\\vcpkg.cmake -DCMAKE_BUILD_TYPE=Release -S . -B build\ncmake -DCMAKE_TOOLCHAIN_FILE=%~dp0..\\vcpkg\\scripts\\buildsystems\\vcpkg.cmake -DCMAKE_BUILD_TYPE=Debug -S . -B build_debug\n\n"
  },
  {
    "path": "install/setupBuild.sh",
    "content": "#!/bin/sh\n\n# gets directory of this file to find the others\nINSTALLPATH=\"$( cd \"$(dirname \"$0\")\" >/dev/null 2>&1 ; pwd -P )\"\ncd $INSTALLPATH/..\n\nmkdir build\nmkdir build_debug\n\ntoolpath=\"$PWD/vcpkg/scripts/buildsystems/vcpkg.cmake\"\n\ncmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=$toolpath -S . -B build\ncmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=$toolpath -S . -B build_debug\n\n"
  },
  {
    "path": "install/setupBuildUbuntu.sh",
    "content": "#!/bin/sh\n\n# gets directory of this file to find the others\nINSTALLPATH=\"$( cd \"$(dirname \"$0\")\" >/dev/null 2>&1 ; pwd -P )\"\ncd $INSTALLPATH/..\n\nmkdir build\nmkdir build_debug\n\ncmake -DCMAKE_BUILD_TYPE=Release -S . -B build\ncmake -DCMAKE_BUILD_TYPE=Debug -S . -B build_debug\n\n"
  },
  {
    "path": "install/setupDependencies.bat",
    "content": "\ncd %~dp0..\n\nif NOT EXIST vcpkg (\n\tgit clone https://github.com/microsoft/vcpkg\n\n\tcall .\\vcpkg\\bootstrap-vcpkg.bat\n)\n\n.\\vcpkg\\vcpkg.exe install glfw3 opengl glew freetype stb --triplet x64-windows\n\nmkdir include\n\ncd include\n\ngit clone -b docking https://github.com/ocornut/imgui.git\ncd imgui\ngit checkout 05bc204dbd80dfebb3dab1511caf1cb980620c76\ncd ..\ncopy imgui\\examples\\imgui_impl_opengl3.cpp imgui\ncopy imgui\\examples\\imgui_impl_opengl3.h imgui\ncopy imgui\\examples\\imgui_impl_glfw.cpp imgui\ncopy imgui\\examples\\imgui_impl_glfw.h imgui\n\ncd ..\n\n"
  },
  {
    "path": "install/setupDependencies.sh",
    "content": "#!/bin/sh\n\n# gets directory of this file to find the others\nINSTALLPATH=\"$( cd \"$(dirname \"$0\")\" >/dev/null 2>&1 ; pwd -P )\"\ncd $INSTALLPATH/..\n\ngit clone https://github.com/microsoft/vcpkg\n./vcpkg/bootstrap-vcpkg.sh\n\n./vcpkg/vcpkg install glfw3 opengl glew freetype stb\n\nmkdir include\ncd include\n\ngit clone -b docking https://github.com/ocornut/imgui.git\ncd imgui\ngit checkout 05bc204dbd80dfebb3dab1511caf1cb980620c76\ncd ..\ncp imgui/examples/imgui_impl_opengl3.cpp imgui\ncp imgui/examples/imgui_impl_opengl3.h imgui\ncp imgui/examples/imgui_impl_glfw.cpp imgui\ncp imgui/examples/imgui_impl_glfw.h imgui\ncd ..\n"
  },
  {
    "path": "install/setupDependenciesUbuntu.sh",
    "content": "#!/bin/sh\n\nINSTALLPATH=\"$( cd \"$(dirname \"$0\")\" >/dev/null 2>&1 ; pwd -P )\"\ncd $INSTALLPATH/..\n\nsudo add-apt-repository universe\nsudo apt update\nsudo apt-get install build-essential freeglut3 freeglut3-dev mesa-common-dev libglfw3 libglfw3-dev libglew-dev git libfreetype6-dev libgl1-mesa-dev\nsudo apt install cmake\n\n\nmkdir include\ncd include\n\nwget https://raw.githubusercontent.com/nothings/stb/master/stb_image.h\n\ngit clone -b docking https://github.com/ocornut/imgui.git\ncd imgui\ngit checkout 05bc204dbd80dfebb3dab1511caf1cb980620c76\ncd ..\ncp imgui/examples/imgui_impl_opengl3.cpp imgui\ncp imgui/examples/imgui_impl_opengl3.h imgui\ncp imgui/examples/imgui_impl_glfw.cpp imgui\ncp imgui/examples/imgui_impl_glfw.h imgui\ncd ..\n"
  },
  {
    "path": "install/setupUbuntu.sh",
    "content": "#!/bin/sh\n\n# gets directory of this file to find the others\nINSTALLPATH=\"$( cd \"$(dirname \"$0\")\" >/dev/null 2>&1 ; pwd -P )\"\n\necho Installing dependencies\n\nsh $INSTALLPATH/setupDependenciesUbuntu.sh\n\necho Creating build directories\n\nsh $INSTALLPATH/setupBuildUbuntu.sh\n\necho Done\n\n"
  },
  {
    "path": "res/default_imgui.ini",
    "content": "[Window][Physics3D]\nPos=0,0\nSize=3440,1346\nCollapsed=0\n\n[Window][Debug##Default]\nPos=60,60\nSize=400,400\nCollapsed=0\n\n[Window][Skybox]\nPos=1916,777\nSize=702,569\nCollapsed=0\nDockId=0x00000004,1\n\n[Window][Properties]\nPos=2620,543\nSize=820,803\nCollapsed=0\nDockId=0x0000000F,0\n\n[Window][Layers]\nPos=1916,777\nSize=702,569\nCollapsed=0\nDockId=0x00000004,3\n\n[Window][Resources]\nPos=0,777\nSize=1914,569\nCollapsed=0\nDockId=0x00000005,1\n\n[Window][Environment]\nPos=1916,777\nSize=702,569\nCollapsed=0\nDockId=0x00000004,2\n\n[Window][Test]\nPos=0,25\nSize=2383,48\nCollapsed=0\nDockId=0x00000006,0\n\n[Window][Scene]\nPos=0,100\nSize=2618,675\nCollapsed=0\nDockId=0x0000000B,0\n\n[Window][Debug]\nPos=0,777\nSize=1914,569\nCollapsed=0\nDockId=0x00000005,0\n\n[Window][Tree]\nPos=2620,25\nSize=820,516\nCollapsed=0\nDockId=0x00000002,0\n\n[Window][Dear ImGui Demo]\nPos=0,100\nSize=2618,675\nCollapsed=0\nDockId=0x0000000B,1\n\n[Window][Example: Custom rendering]\nPos=142,220\nSize=1193,649\nCollapsed=0\n\n[Window][Example: Property editor]\nPos=60,60\nSize=430,450\nCollapsed=1\n\n[Window][Dear ImGui Style Editor]\nPos=470,57\nSize=502,910\nCollapsed=0\n\n[Window][Example: Simple layout]\nPos=60,60\nSize=500,440\nCollapsed=1\n\n[Window][Example: Console]\nPos=60,60\nSize=520,600\nCollapsed=0\n\n[Window][Example: Documents]\nPos=60,63\nSize=736,1136\nCollapsed=0\n\n[Window][Example: Constrained Resize]\nPos=922,255\nSize=1108,608\nCollapsed=0\nDockId=0x00000003,1\n\n[Window][Example: Long text display]\nPos=60,60\nSize=520,600\nCollapsed=1\n\n[Window][Transform]\nPos=651,282\nSize=120,95\nCollapsed=0\n\n[Window][Stacked 1]\nPos=675,334\nSize=449,232\nCollapsed=0\n\n[Window][Same title as another window##1]\nPos=16,503\nSize=496,75\nCollapsed=0\n\n[Window][###AnimatedTitle]\nPos=134,305\nSize=272,60\nCollapsed=0\n\n[Window][Same title as another window##2]\nPos=60,393\nSize=496,75\nCollapsed=0\n\n[Window][Example: Auto-resizing window]\nPos=60,60\nSize=496,330\nCollapsed=1\n\n[Window][Style]\nPos=1916,777\nSize=702,569\nCollapsed=0\nDockId=0x00000004,0\n\n[Window][Add component]\nPos=479,102\nSize=817,607\nCollapsed=0\n\n[Window][]\nPos=0,25\nSize=3440,106\nCollapsed=0\nDockId=0x0000000D\n\n[Window][DockSpace Demo]\nSize=3440,1346\nCollapsed=0\n\n[Window][Another Window]\nPos=1138,405\nSize=374,250\nCollapsed=0\n\n[Window][Toolbar]\nPos=0,25\nSize=2618,73\nCollapsed=0\nDockId=0x0000000A,0\n\n[Window][Error##ErrorModal]\nPos=761,403\nSize=279,93\nCollapsed=0\n\n[Docking][Data]\nDockSpace           ID=0xEB0AB953 Window=0x0DCF7F20 Pos=0,25 Size=3440,1321 Split=Y Selected=0x18B8C0DE\n  DockNode          ID=0x0000000D Parent=0xEB0AB953 SizeRef=1800,70\n  DockNode          ID=0x0000000E Parent=0xEB0AB953 SizeRef=1800,803 Split=X\n    DockNode        ID=0x00000007 Parent=0x0000000E SizeRef=1369,875 Split=Y\n      DockNode      ID=0x00000001 Parent=0x00000007 SizeRef=1707,750 Split=Y Selected=0x18B8C0DE\n        DockNode    ID=0x00000006 Parent=0x00000001 SizeRef=2383,48 HiddenTabBar=1 Selected=0x784DD132\n        DockNode    ID=0x00000008 Parent=0x00000001 SizeRef=2383,936 Split=Y Selected=0x18B8C0DE\n          DockNode  ID=0x0000000A Parent=0x00000008 SizeRef=2383,73 HiddenTabBar=1 Selected=0x507852CA\n          DockNode  ID=0x0000000B Parent=0x00000008 SizeRef=2383,675 Selected=0x18B8C0DE\n      DockNode      ID=0x00000003 Parent=0x00000007 SizeRef=1707,569 Split=X Selected=0xAD6468A3\n        DockNode    ID=0x00000005 Parent=0x00000003 SizeRef=1000,931 Selected=0xAD6468A3\n        DockNode    ID=0x00000004 Parent=0x00000003 SizeRef=367,931 Selected=0xF27C976E\n    DockNode        ID=0x00000009 Parent=0x0000000E SizeRef=429,875 Split=Y Selected=0xC89E3217\n      DockNode      ID=0x00000002 Parent=0x00000009 SizeRef=552,516 Selected=0x170CF1E2\n      DockNode      ID=0x0000000F Parent=0x00000009 SizeRef=552,803 Selected=0xC89E3217\n\n"
  },
  {
    "path": "res/shaders/basic.shader",
    "content": "[common]\n\n#version 330 core\n\nvec4 apply(mat4 matrix, vec3 vector) {\n\treturn matrix * vec4(vector, 0.0);\n}\n\nvec3 apply3(mat4 matrix, vec3 vector) {\n\treturn mat3(matrix) * vector;\n}\n\nvec4 applyT(mat4 matrix, vec3 vector) {\n\treturn matrix * vec4(vector, 1.0);\n}\n\nvec3 applyT3(mat4 matrix, vec3 vector) {\n\treturn (matrix * vec4(vector, 1.0)).xyz;\n}\n\nvec4 applyN(mat4 matrix, vec3 vector) {\n\treturn normalize(matrix * vec4(vector, 0.0));\n}\n\nvec3 apply3N(mat4 matrix, vec3 vector) {\n\treturn normalize(mat3(matrix) * vector);\n}\n\nvec4 applyTN(mat4 matrix, vec3 vector) {\n\treturn normalize(matrix * vec4(vector, 1.0));\n}\n\nvec3 applyT3N(mat4 matrix, vec3 vector) {\n\treturn normalize((matrix * vec4(vector, 1.0)).xyz);\n}\n\nvec4 rgba(vec3 color) {\n\treturn vec4(color, 1.0);\n}\n\nvec4 rgba(float color) {\n\treturn vec4(color, color, color, 1.0);\n}\n\n//------------------------------------------------------------------------------//\n\n[vertex]\n\nlayout(location = 0) in vec3 vPosition;\nlayout(location = 1) in vec3 vNormal;\nlayout(location = 2) in vec2 vUV;\nlayout(location = 3) in vec3 vTangent;\nlayout(location = 4) in vec3 vBitangent;\n\nsmooth out vec3 fPosition;\nsmooth out vec2 fUV;\nsmooth out vec3 fNormal;\n\nuniform mat4 viewMatrix;\nuniform mat4 modelMatrix;\nuniform mat4 projectionMatrix;\n\nvoid main() {\n\tfUV = vUV;\n\tfPosition = applyT3(modelMatrix, vPosition);\n\tmat3 normalMatrix = transpose(inverse(mat3(modelMatrix)));\n\tfNormal = normalMatrix * vNormal;\n\n\tgl_Position = applyT(projectionMatrix * viewMatrix, fPosition);\n}\n\n//------------------------------------------------------------------------------//\n\n[fragment]\n\n// Out\nout vec4 outColor;\n\n// In\nsmooth in vec2 fUV;\nsmooth in vec3 fPosition;\nsmooth in vec3 fNormal;\n\n// General\nvec3 N;\nvec3 V;\n\n// Material\nvec4 albedo;\nfloat roughness;\nfloat metalness;\nfloat ambientOcclusion;\n\n// Structs\nstruct Attenuation {\n\tfloat constant;\n\tfloat linear;\n\tfloat exponent;\n};\n\nstruct Light {\n\tvec3 position;\n\tvec3 color;\n\tfloat intensity;\n\tAttenuation attenuation;\n};\n\nstruct Material {\n\tvec4 albedo;\n\tfloat roughness;\n\tfloat metalness;\n\tfloat ambientOcclusion;\n\n\tsampler2D albedoMap;\n\tsampler2D normalMap;\n\tsampler2D metalnessMap;\n\tsampler2D roughnessMap;\n\tsampler2D ambientOcclusionMap;\n\n\tint textured;\n};\n\n// Material\nuniform Material material;\n\n// Transform\nuniform vec3 viewPosition;\n\n// Light\n#define maxLights 10\nuniform int lightCount;\nuniform Light lights[maxLights];\n\n// Environment\nuniform vec3 sunDirection = vec3(1, 1, 1);\nuniform vec3 sunColor = vec3(1, 1, 1);\nuniform float exposure = 1.0;\nuniform float gamma = 1.0;\nuniform float hdr = 1.0;\n\n// Constants\nconst float PI = 3.14159265359;\n\nfloat ggxTrowbridgeReitz(vec3 N, vec3 H, float roughness) {\n\tfloat alpha = roughness * roughness;\n\tfloat alpha2 = alpha * alpha;\n\tfloat NdotH = max(dot(N, H), 0.0);\n\tfloat NdotH2 = NdotH * NdotH;\n\n\tfloat numerator = alpha2;\n\tfloat denominator = (NdotH2 * (alpha2 - 1.0) + 1.0);\n\tdenominator = max(PI * denominator * denominator, 0.001);\n\n\treturn numerator / denominator;\n}\n\nfloat ggxSchlick(float NdotV, float roughness) {\n\tfloat r = roughness + 1.0;\n\tfloat k = (r * r) / 8.0;\n\n\tfloat numerator = NdotV;\n\tfloat denominator = NdotV * (1.0 - k) + k;\n\n\treturn numerator / denominator;\n}\n\nfloat smith(vec3 N, vec3 V, vec3 L, float roughness) {\n\tfloat NdotV = max(dot(N, V), 0.0);\n\tfloat NdotL = max(dot(N, L), 0.0);\n\tfloat ggx2 = ggxSchlick(NdotV, roughness);\n\tfloat ggx1 = ggxSchlick(NdotL, roughness);\n\n\treturn ggx1 * ggx2;\n}\n\nvec3 fresnelSchlick(float cosTheta, vec3 F0) {\n\t// F0: surface reflection at zero incidence\n\treturn F0 + (1.0 - F0) * pow(1.0 - min(cosTheta, 1.0), 5.0);\n}\n\nvec3 calcDirectionalLight() {\n\tvec3 directionalLight = normalize(sunDirection);\n\tfloat directionalFactor = 0.4 * max(dot(N, directionalLight), 0.0);\n\tvec3 directional = directionalFactor * sunColor;\n\treturn directional;\n}\n\nvec3 calcLightColor(Light light) {\n\t// General light variables\n\tvec3 L = normalize(light.position - fPosition);\n\tvec3 H = normalize(V + L);\n\tfloat distance = length(light.position - fPosition);\n\t//float scaledDistance = distance / light.intensity;\n\t//float attenuation = 1.0 / (light.attenuation.constant + light.attenuation.linear * scaledDistance + light.attenuation.exponent * scaledDistance * scaledDistance);\n\tfloat attenuation = 1.0 / (distance * distance);\n\tvec3 radiance = light.color * attenuation * light.intensity;\n\n\t// Fresnel\n\tvec3 F0_NM = vec3(0.04); // Non metallic F0\n\tvec3 F0 = mix(F0_NM, albedo.rgb, metalness);\n\tfloat cosTheta = max(dot(H, V), 0.0);\n\tvec3 F = fresnelSchlick(cosTheta, F0);\n\n\t// DFG\n\tfloat D = ggxTrowbridgeReitz(N, H, roughness);\n\tfloat G = smith(N, V, L, roughness);\n\tvec3 DFG = D * F * G;\n\n\t// Cook Torrance\n\tvec3 numerator = DFG;\n\tfloat denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0);\n\tvec3 specular = numerator / max(denominator, 0.001);\n\n\t// Light contribution constants\n\tvec3 kS = F;\n\tvec3 kD = vec3(1.0) - kS;\n\tkD *= 1.0 - metalness;\n\n\tfloat NdotL = max(dot(N, L), 0.0);\n\tvec3 Lo = (kD * albedo.rgb / PI + specular) * radiance * NdotL;\n\n\treturn Lo;\n}\n\nvec3 getNormalFromMap() {\n\tvec3 tangentNormal = texture(material.normalMap, fUV).xyz * 2.0 - 1.0;\n\n\tvec3 Q1 = dFdx(fPosition);\n\tvec3 Q2 = dFdy(fPosition);\n\tvec2 st1 = dFdx(fUV);\n\tvec2 st2 = dFdy(fUV);\n\n\tvec3 N = normalize(fNormal);\n\tvec3 T = normalize(Q1 * st2.t - Q2 * st1.t);\n\tvec3 B = -normalize(cross(N, T));\n\tmat3 TBN = mat3(T, B, N);\n\n\treturn TBN * tangentNormal;\n}\n\nvoid main() {\n\t/*if (material.textured == 1) {\n\t\tN = normalize(getNormalFromMap());\n\n\t\talbedo = texture(material.albedoMap, fUV) * texture(material.albedoMap, fUV);\n\t\troughness = 1 - texture(material.roughnessMap, fUV).r;\n\t\tmetalness = texture(material.metalnessMap, fUV).r;\n\t\tambientOcclusion = texture(material.ambientOcclusionMap, fUV).r;\n\t} else {*/\n\t\tN = normalize(fNormal);\n\n\t\talbedo = material.albedo;\n\t\troughness = material.roughness;\n\t\tmetalness = material.metalness;\n\t\tambientOcclusion = material.ambientOcclusion;\n\t/*}*/\n\n\tV = normalize(viewPosition - fPosition);\n\n\t// Light calculations\n\tvec3 Lo = vec3(0);\n\tfor (int i = 0; i < min(maxLights, lightCount); i++) {\n\t\tif (lights[i].intensity > 0) {\n\t\t\tLo += calcLightColor(lights[i]);\n\t\t}\n\t}\n\n\t// Ambient\n\tvec3 ambient = vec3(1.0) * albedo.rgb * ambientOcclusion;\n\n\t// Directional\n\tvec3 Ld = calcDirectionalLight();\n\n\t// Combine ambient and lighting\n\tvec3 color = ambient + Lo + Ld;\n\n\t// HDR \n\tcolor = hdr * (vec3(1.0) - exp(-color * exposure)) + (1.0 - hdr) * color;\n\n\t// Gamma\n\tcolor = pow(color, vec3(1.0 / gamma));\n\n\t// Outcolor\n\toutColor = vec4(color, albedo.a);\n}\n\n"
  },
  {
    "path": "res/shaders/blur.shader",
    "content": "[common]\n\n#version 330 core\n\n//------------------------------------------------------------------------------//\n\n[vertex]\n\nlayout(location = 0) in vec4 positions;\n\nout vec2 fUV;\n\nvoid main() {\n\tgl_Position = vec4(positions.xy, 0.0, 1.0);\n\tfUV = positions.zw;\n}\n\n//------------------------------------------------------------------------------//\n\n[fragment]\n\nout vec4 outColor;\n\nin vec2 fUV;\n\nuniform sampler2D image;\n\nuniform bool horizontal;\nuniform float weight[5] = { 0.227027f, 0.1945946f, 0.1216216f, 0.054054f, 0.016216f };\n\nvoid main() {\n\tvec2 offset = 4.0 / textureSize(image, 0);\n\tvec3 result = texture(image, fUV).rgb * weight[0];\n\n\tif (horizontal) {\n\t\tfor (int i = 1; i < 5; ++i) {\n\t\t\tresult += texture(image, fUV + vec2(offset.x * i, 0.0)).rgb * weight[i];\n\t\t\tresult += texture(image, fUV - vec2(offset.x * i, 0.0)).rgb * weight[i];\n\t\t}\n\t} else {\n\t\tfor (int i = 1; i < 5; ++i) {\n\t\t\tresult += texture(image, fUV + vec2(0.0, offset.y * i)).rgb * weight[i];\n\t\t\tresult += texture(image, fUV - vec2(0.0, offset.y * i)).rgb * weight[i];\n\t\t}\n\t}\n\toutColor = vec4(result, 1.0);\n}"
  },
  {
    "path": "res/shaders/compute.shader",
    "content": "[compute]\n#version 430\nlayout(local_size_x = 1, local_size_y = 1) in;\nlayout(rgba32f, binding = 0) uniform image2D img_output;\n\nvoid main() {\n\tvec4 pixel = vec4(1, 0, 0, 1);\n\t// get index in global work group i.e x,y position\n  \tivec2 pixel_coords = ivec2(gl_GlobalInvocationID.xy);\n\n\t// output to a specific pixel in the image\n\timageStore(img_output, pixel_coords, pixel);\n}\n  "
  },
  {
    "path": "res/shaders/debug.shader",
    "content": "[common]\n\n#version 400 core\n\n/* Usage:\n\t// Once\n\tApplicationShaders::debugShader.updateProjection(viewMatrix, projectionMatrix, viewPosition);\n\t// For every model\n\tApplicationShaders::debugShader.updateModel(modelMatrix);\n\tmesh->render();\n*/\n\n// Debug vector type defenitions\n#define FACES\t\t    fColor = vec4(0.8, 0.8, 0.8, 0.5); vec3 direction = vec3(viewPosition - center); /*if (dot(faceNormal, direction) < 0.0) return;*/ gl_Position = transform * gl_in[0].gl_Position; EmitVertex(); gl_Position = transform * gl_in[1].gl_Position; EmitVertex(); gl_Position = transform * gl_in[2].gl_Position; EmitVertex(); EndPrimitive();\n#define VERTEXNORMALS   fColor = vec4(0, 0, 1, 1); draw(transform, gl_in[0].gl_Position.xyz, gInput[0].gNormal); draw(transform, gl_in[1].gl_Position.xyz, gInput[1].gNormal); draw(transform, gl_in[2].gl_Position.xyz, gInput[2].gNormal);\n#define FACENORMALS     fColor = vec4(1, 0, 1, 1); draw(transform, center, faceNormal);\n#define TANGENTS        fColor = vec4(1, 0, 0, 1); draw(transform, gl_in[0].gl_Position.xyz, gInput[0].gTangent); draw(transform, gl_in[1].gl_Position.xyz, gInput[1].gTangent); draw(transform, gl_in[2].gl_Position.xyz, gInput[2].gTangent);\n#define BITANGENTS      fColor = vec4(0, 1, 0, 1); draw(transform, gl_in[0].gl_Position.xyz, gInput[0].gBitangent); draw(transform, gl_in[1].gl_Position.xyz, gInput[1].gBitangent); draw(transform, gl_in[2].gl_Position.xyz, gInput[2].gBitangent);\n\n// Amount of different debug vector to show (max 5)\n#define VECTOR_TYPES\t1\n\n// Reorder for different types\n#define TYPE_1\t\t\tFACES\n#define TYPE_2\t\t\tFACENORMALS\n#define TYPE_3\t\t\tVERTEXNORMALS\n#define TYPE_4\t\t\tTANGENTS\n#define TYPE_5\t\t\tBITANGENTS\n\n// Define to show arrow head\n//#define ARROW_HEAD\n#define ARROW_LENGTH\t0.05\n#define ARROW_WIDTH\t\t0.025\n\n//------------------------------------------------------------------------------//\n\n[vertex]\n\nlayout(location = 0) in vec3 vPosition;\nlayout(location = 1) in vec3 vNormal;\nlayout(location = 2) in vec2 vUV;\nlayout(location = 3) in vec3 vTangent;\nlayout(location = 4) in vec3 vBitangent;\n\nout vec3 gNormal;\nout vec3 gTangent;\nout vec3 getBitangent;\n\nout VS_OUT {\n\tvec3 gNormal;\n\tvec3 gTangent;\n\tvec3 gBitangent;\n} vOutput;\n\nuniform mat4 modelMatrix;\n\nvec4 applyT(mat4 matrix, vec3 vector) {\n\treturn matrix * vec4(vector, 1.0);\n}\n\nvec3 apply3(mat4 matrix, vec3 vector) {\n\treturn mat3(matrix) * vector;\n}\n\nvoid main() {\n\tmat3 invModelMatrix = transpose(inverse(mat3(modelMatrix)));\n\tvOutput.gNormal = normalize(invModelMatrix * vNormal);\n\tvOutput.gTangent = normalize(apply3(modelMatrix, vTangent));\n\tvOutput.gBitangent = normalize(apply3(modelMatrix, vBitangent));\n\n\tgl_Position = applyT(modelMatrix, vPosition);\n}\n\n//------------------------------------------------------------------------------//\n\n[geometry]\n\nlayout(triangles, invocations = VECTOR_TYPES) in;\nlayout(line_strip, max_vertices = 54) out;\n\nin VS_OUT {\n\tvec3 gNormal;\n\tvec3 gTangent;\n\tvec3 gBitangent;\n} gInput[];\n\nout vec4 fColor;\n\nuniform vec3 viewPosition;\nuniform mat4 viewMatrix;\nuniform mat4 projectionMatrix;\n\nvec3 center() {\n\treturn vec3(gl_in[0].gl_Position + gl_in[1].gl_Position + gl_in[2].gl_Position) / 3;\n}\n\nvec3 faceNormal() {\n\tvec3 a = vec3(gl_in[0].gl_Position) - vec3(gl_in[1].gl_Position);\n\tvec3 b = vec3(gl_in[2].gl_Position) - vec3(gl_in[1].gl_Position);\n\tvec3 norm = normalize(cross(a, b));\n\treturn -norm;\n}\n\nvoid draw(mat4 transform, vec3 center, vec3 normal) {\n\tfloat arrowHeight = 0.15 * ARROW_LENGTH;\n\tvec4 arrowTop = vec4(center + ARROW_LENGTH * normal, 1);\n\tvec3 norm = normalize(cross(arrowTop.xyz - viewPosition, normal));\n\tvec4 arrowLeft = arrowTop - vec4(arrowHeight * normal - ARROW_WIDTH * norm, 0);\n\tvec4 arrowRight = arrowTop - vec4(arrowHeight * normal + ARROW_WIDTH * norm, 0);\n\tvec4 arrowBase = arrowTop - arrowHeight * vec4(normal, 0);\n\n\tgl_Position = transform * vec4(center, 1); EmitVertex();\n#ifdef ARROW_HEAD\n\tgl_Position = transform * arrowBase; EmitVertex();\n\tgl_Position = transform * arrowLeft; EmitVertex();\n#endif\n\tgl_Position = transform * arrowTop; EmitVertex();\n#ifdef ARROW_HEAD\n\tgl_Position = transform * arrowRight; EmitVertex();\n\tgl_Position = transform * arrowBase; EmitVertex();\n#endif\n\tEndPrimitive();\n}\n\nvoid main() {\n\tvec3 center = center();\n\tvec3 faceNormal = faceNormal();\n\tmat4 transform = projectionMatrix * viewMatrix;\n\n\tswitch (gl_InvocationID) {\n\t\tcase 0: { TYPE_1 } break;\n\t\tcase 1: { TYPE_2 } break;\n\t\tcase 2: { TYPE_3 } break;\n\t\tcase 3: { TYPE_4 } break;\n\t\tcase 4: { TYPE_5 } break;\n\t}\n}\n\n\n//------------------------------------------------------------------------------//\n\n[fragment]\n\nin vec4 fColor;\nout vec4 outColor;\n\nvoid main() {\n\toutColor = fColor;\n}\n\n"
  },
  {
    "path": "res/shaders/depth.shader",
    "content": "[common]\n\n#version 330 core\n\n//------------------------------------------------------------------------------//\n\n[vertex]\n\nlayout(location = 0) in vec3 vPosition; \n\nuniform mat4 modelMatrix;\nuniform mat4 lightMatrix;\n\nvoid main() {\n\tgl_Position = lightMatrix * modelMatrix * vec4(vPosition, 1.0);\n}\n\n//------------------------------------------------------------------------------//\n\n[fragment]\n\nvoid main() {}"
  },
  {
    "path": "res/shaders/depthbuffer.shader",
    "content": "[common]\n\n#version 330 core\n\n[vertex]\n\nlayout(location = 0) in vec4 vPosition;\n\nuniform mat4 projectionMatrix;\n\nout vec2 fUV;\n\nvoid main() {\n\tgl_Position = vec4(vPosition.xy, 0.0, 1.0);\n\tfUV = vPosition.zw;\n}\n\n[fragment]\n\nout vec4 outColor;\n\nin vec2 fUV;\n\nuniform sampler2D depthMap;\nuniform float near;\nuniform float far;\n\nfloat linearizeDepth(float depth) {\n    float z = depth * 2.0 - 1.0; // Back to NDC \n    return (2.0 * near * far) / (far + near - z * (far - near));\t\n}\n\nvoid main() {             \n    float depthValue = texture(depthMap, fUV).r;\n    outColor = vec4(vec3(linearizeDepth(depthValue) / far), 1.0); // perspective\n    outColor = vec4(vec3(depthValue), 1.0); // orthographic\n}"
  },
  {
    "path": "res/shaders/font.shader",
    "content": "[common]\n\n#version 330 core\n\n//------------------------------------------------------------------------------//\n\n[vertex]\n\nlayout (location = 0) in vec4 vertex;\n\nout vec2 fUVTexture;\n\nuniform mat4 projectionMatrix;\n\nvoid main() {\n    gl_Position = projectionMatrix * vec4(vertex.xy, 0, 1);\n    fUVTexture = vertex.zw;\n}\n\n//------------------------------------------------------------------------------//\n\n[fragment]\n\nin vec2 fUVTexture;\nout vec4 outColor;\n\nuniform sampler2D text;\nuniform vec4 color;\n\nvoid main() {    \n    outColor = vec4(color.xyz, color.w * texture(text, fUVTexture).r);\n} "
  },
  {
    "path": "res/shaders/gui.shader",
    "content": "[common]\n\n#version 330 core\n\n//------------------------------------------------------------------------------//\n\n[vertex]\n\nlayout(location = 0) in vec2 vposition;\nlayout(location = 1) in vec2 vuv;\nlayout(location = 2) in vec4 vcolor;\n\nuniform mat4 projectionMatrix;\n\nout vec4 fcolor;\nout vec2 fuv;\n\nvoid main() {\n\tgl_Position = projectionMatrix * vec4(vposition, 0.0, 1.0);\n\tfcolor = vcolor;\n\tfuv = vuv;\n}\n\n//------------------------------------------------------------------------------//\n\n[fragment]\n\nout vec4 outColor;\n\nin vec2 fuv;\nin vec4 fcolor;\n\nuniform sampler2D textureSampler;\nuniform bool textured = false;\n\nvoid main() {\n\toutColor = (textured) ? texture(textureSampler, fuv) * fcolor : fcolor;\n}"
  },
  {
    "path": "res/shaders/instance.shader",
    "content": "[properties]\nint mode = 0;\nint reflectionSamples = 8;\n\n[common]\n\n#version 330 core\n\nvec4 apply(mat4 matrix, vec3 vector) {\n\treturn matrix * vec4(vector, 0.0);\n}\n\nvec3 apply3(mat4 matrix, vec3 vector) {\n\treturn mat3(matrix) * vector;\n}\n\nvec4 applyT(mat4 matrix, vec3 vector) {\n\treturn matrix * vec4(vector, 1.0);\n}\n\nvec3 applyT3(mat4 matrix, vec3 vector) {\n\treturn (matrix * vec4(vector, 1.0)).xyz;\n}\n\nvec4 applyN(mat4 matrix, vec3 vector) {\n\treturn normalize(matrix * vec4(vector, 0.0));\n}\n\nvec3 apply3N(mat4 matrix, vec3 vector) {\n\treturn normalize(mat3(matrix) * vector);\n}\n\nvec4 applyTN(mat4 matrix, vec3 vector) {\n\treturn normalize(matrix * vec4(vector, 1.0));\n}\n\nvec3 applyT3N(mat4 matrix, vec3 vector) {\n\treturn normalize((matrix * vec4(vector, 1.0)).xyz);\n}\n\nvec4 rgba(vec3 color) {\n\treturn vec4(color, 1.0);\n}\n\nvec4 rgba(float color) {\n\treturn vec4(color, color, color, 1.0);\n}\n\n//------------------------------------------------------------------------------//\n\n[vertex]\n\nlayout(location = 0) in vec3 vPosition;\nlayout(location = 1) in vec3 vNormal;\nlayout(location = 2) in vec2 vUV;\nlayout(location = 3) in vec3 vTangent;\nlayout(location = 4) in vec3 vBitangent;\nlayout(location = 5) in mat4 vModelMatrix;\nlayout(location = 9) in vec4 vAlbedo;\nlayout(location = 10) in vec3 vMRAo;\nlayout(location = 11) in uvec2 vTextureFlags;\n\nsmooth out vec3 fPosition;\nsmooth out vec3 fNormal;\nsmooth out vec2 fUV;\nsmooth out vec4 fLightSpacePosition;\n\nflat out vec4 fAlbedo;\nflat out float fMetalness;\nflat out float fRoughness;\nflat out float fAmbientOcclusion;\nflat out uvec2 fTextureFlags;\n\nuniform mat4 viewMatrix;\nuniform mat4 projectionMatrix;\nuniform mat4 lightMatrix;\n\nvoid main() {\n\tfAlbedo = vAlbedo;\n\tfMetalness = vMRAo.x;\n\tfRoughness = vMRAo.y;\n\tfAmbientOcclusion = vMRAo.z;\n\tfTextureFlags = vTextureFlags;\n\n\tfUV = vUV;\n\tfPosition = applyT3(vModelMatrix, vPosition);\n\tmat3 normalMatrix = transpose(inverse(mat3(vModelMatrix)));\n\tfNormal = normalMatrix * vNormal;\n\tfLightSpacePosition = applyT(lightMatrix, fPosition);\n\n\tgl_Position = applyT(projectionMatrix * viewMatrix, fPosition);\n}\n\n//------------------------------------------------------------------------------//\n\n[fragment]\n\n// Out\nout vec4 outColor;\n\n// In\nsmooth in vec2 fUV;\nsmooth in vec3 fPosition;\nsmooth in vec3 fNormal;\nsmooth in vec4 fLightSpacePosition;\n\nflat in vec4 fAlbedo;\nflat in float fRoughness;\nflat in float fMetalness;\nflat in float fAmbientOcclusion;\nflat in uvec2 fTextureFlags;\n\nconst ivec2 Flag_Albedo       = ivec2(0, 24);\nconst ivec2 Flag_Normal       = ivec2(0, 16);\nconst ivec2 Flag_Metalness    = ivec2(0, 8);\nconst ivec2 Flag_Roughness    = ivec2(0, 0);\nconst ivec2 Flag_AO           = ivec2(1, 24);\nconst ivec2 Flag_Gloss        = ivec2(1, 16);\nconst ivec2 Flag_Specular     = ivec2(1, 8);\nconst ivec2 Flag_Displacement = ivec2(1, 0);\n\t\t\t\t\t\t    \nconst int Mode_Default        = 0;\nconst int Mode_Position       = 1;\nconst int Mode_Normal         = 2;\nconst int Mode_UV             = 3;\nconst int Mode_LightSpace     = 4;\nconst int Mode_Albedo         = 5;\nconst int Mode_Metalness      = 6;\nconst int Mode_Roughness      = 7;\nconst int Mode_AO             = 8;\nconst int Mode_TextureFlags   = 9;\n\nuniform int mode = Mode_Default;\n\n// General\nvec3 N;\nvec3 V;\nvec4 albedo;\nfloat roughness;\nfloat metalness;\nfloat ambientOcclusion;\n\n// Attenuation\nstruct Attenuation {\n\tfloat constant;\n\tfloat linear;\n\tfloat exponent;\n};\n\n// Light\nstruct Light {\n\tvec3 position;\n\tvec3 color;\n\tfloat intensity;\n\tAttenuation attenuation;\n};\n\n#define maxLights 10\nuniform int lightCount;\nuniform Light lights[maxLights];\n\n// Shadow\nuniform sampler2D shadowMap;\n\n// Transform\nuniform vec3 viewPosition;\n\n// Textures\n//uniform sampler2D textures[##MAX_TEXTURE_IMAGE_UNITS];\nuniform sampler2D textures[31];\nuniform samplerCube skyboxTexture;\n\n// Environment\nuniform int reflectionSamples = 10;\nuniform vec3 sunDirection = vec3(1, 1, 1);\nuniform vec3 sunColor = vec3(1, 1, 1);\nuniform float exposure = 0.8;\nuniform float gamma = 1.0;\nuniform float hdr = 1.0;\n\n// Constants\nfloat PI = 3.14159265359;\nfloat TWOPI = 6.28318531;\n\nfloat ggxTrowbridgeReitz(vec3 N, vec3 H, float alpha) {\n\tfloat alpha2 = alpha * alpha;\n\tfloat NdotH = max(dot(N, H), 0.0);\n\tfloat NdotH2 = NdotH * NdotH;\n\n\tfloat numerator = alpha2;\n\tfloat denominator = (NdotH2 * (alpha2 - 1.0) + 1.0);\n\tdenominator = max(PI * denominator * denominator, 0.001);\n\n\treturn numerator / denominator;\n}\n\nfloat ggxSchlick(float NdotV, float alpha) {\n\tfloat t = alpha + 1.0;\n\tfloat k = (t * t) / 8.0;\n\n\tfloat numerator = NdotV;\n\tfloat denominator = NdotV * (1.0 - k) + k;\n\n\treturn numerator / denominator;\n}\n\nfloat smith(vec3 N, vec3 V, vec3 L, float k) {\n\tfloat NdotV = max(dot(N, V), 0.0);\n\tfloat NdotL = max(dot(N, L), 0.0);\n\tfloat ggx2 = ggxSchlick(NdotV, k);\n\tfloat ggx1 = ggxSchlick(NdotL, k);\n\n\treturn ggx1 * ggx2;\n}\n\nvec3 fresnelSchlick(float cosTheta, vec3 F0) {\n\treturn F0 + (1.0 - F0) * pow(1.0 - min(cosTheta, 1.0), 5.0);\n}\n\nvec3 calcDirectionalLight() {\n\tvec3 L = normalize(sunDirection);\n\tfloat directionalFactor = 0.4 * max(dot(N, -L), 0.0);\n\tvec3 directional = directionalFactor * sunColor;\n\treturn directional;\n}\n\nfloat calcShadow() {\n\t// perform perspective divide\n\tvec3 projCoords = fLightSpacePosition.xyz / fLightSpacePosition.w;\n\n\t// transform to [0,1] range\n\tprojCoords = projCoords * 0.5 + 0.5;\n\n\tif (projCoords.z > 1.0)\n\t\treturn 0.0;\n\n\t// check whether current frag pos is in shadow\n\t//float bias = 0.005;\n\tfloat bias = max(0.05 * (1.0 - dot(N, -sunDirection)), 0.005);\n\tfloat currentDepth = projCoords.z;\n\tfloat shadow = 0.0;\n\tvec2 texelSize = 0.5 / textureSize(shadowMap, 0);\n\tfor (int x = -2; x <= 2; ++x) {\n\t\tfor (int y = -2; y <= 2; ++y) {\n\t\t\tfloat pcfDepth = texture(shadowMap, projCoords.xy + vec2(x, y) * texelSize).r;\n\t\t\tshadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0;\n\t\t}\n\t}\n\tshadow /= 25.0;\n\n\treturn shadow;\n}\n\nvec3 calcLightColor(Light light) {\n\t// General light variables\n\tvec3 L = normalize(light.position - fPosition);\n\tvec3 H = normalize(V + L);\n\tfloat distance = length(light.position - fPosition);\n\tfloat cosTheta = max(dot(H, V), 0.0);\n\n\tfloat scaledDistance = distance/* / light.intensity*/;\n\tfloat attenuation = 1.0 / (light.attenuation.constant + light.attenuation.linear * scaledDistance + light.attenuation.exponent * scaledDistance * scaledDistance);\n\t//float attenuation = 1.0 / (distance * distance);\n\tvec3 radiance = light.color * attenuation * light.intensity * cosTheta;\n\n\t// Fresnel\n\tvec3 F0_NM = vec3(0.04); // Non metallic F0\n\tvec3 F0 = mix(F0_NM, albedo.rgb, metalness);\n\tvec3 F = fresnelSchlick(cosTheta, F0);\n\n\t// Cook Torrance\n\tfloat NDF = ggxTrowbridgeReitz(N, H, roughness * roughness);\n\tfloat G = smith(N, V, L, roughness);\n\tvec3 numerator = NDF * F * G;\n\tfloat denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.0001;\n\tvec3 specular = numerator / denominator;\n\n\t// Light contribution constants\n\tvec3 kS = F;\n\tvec3 kD = (vec3(1.0) - kS) * (1.0 - metalness);\n\n\tfloat NdotL = max(dot(N, L), 0.0);\n\tvec3 Lo = (kD / PI * albedo.rgb + specular) * radiance * NdotL;\n\n\treturn Lo;\n}\n\nfloat rand(float n) { return fract(sin(n) * 43758.5453123); }\n\nvec3 skybox() {\n\tvec3 wo = normalize(viewPosition - fPosition);\n\tvec3 wi = reflect(-wo, N);\n\n\tvec3 w = -wi;\n\tvec3 u = cross(vec3(0.0, 1.0, 0.0), w);\n\tvec3 v = cross(w, u);\n\n\tvec3 result = texture(skyboxTexture, wi).rgb;\n\tfor (int s = 1; s <= reflectionSamples; s++) {\n\t\tfloat progress = float(s) / float(reflectionSamples);\n\t\tfloat angle = (10.0 + 3.0 * rand(s)) * TWOPI * progress;\n\t\tvec3 offset = cos(angle) * u + sin(angle) * v;\n\t\tvec3 scaledOffset = (1.0 - metalness) * offset * mix(0.02, 0.35, progress);\n\t\tvec3 ws = normalize(wi + scaledOffset);\n\t\tresult += texture(skyboxTexture, ws).rgb;\n\t}\n\n\tresult /= max(float(reflectionSamples), 1.0);\n\t\n\treturn result;\n}\n\nint getTextureMapIndex(ivec2 flag) {\n\treturn int((fTextureFlags[flag.x] >> uint(flag.y)) & uint(0xFF));\n}\n\nvec4 getTextureMap(flat int map) {\n\treturn texture(textures[map - 1], fUV);\n}\n\nvec4 getAlbedo() {\n\tint map = getTextureMapIndex(Flag_Albedo);\n\t\n\tif (map == 0)\n\t\treturn fAlbedo;\n\n\treturn vec4(getTextureMap(map).rgb, 1.0);\n}\n\nvec3 getNormal() {\n\tint map = getTextureMapIndex(Flag_Normal);\n\n\tif (map == 0)\n\t\treturn normalize(fNormal);\n\n\t//return getTextureMap(map).rgb;\n\tvec3 tangentNormal = getTextureMap(map).xyz * 2.0 - 1.0;\n\n\tvec3 Q1 = dFdx(fPosition);\n\tvec3 Q2 = dFdy(fPosition);\n\tvec2 st1 = dFdx(fUV);\n\tvec2 st2 = dFdy(fUV);\n\n\tvec3 N = normalize(fNormal);\n\tvec3 T = normalize(Q1 * st2.t - Q2 * st1.t);\n\tvec3 B = -normalize(cross(N, T));\n\tmat3 TBN = mat3(T, B, N);\n\n\treturn TBN * tangentNormal;\n}\n\nfloat getMetalness() {\n\tint map = getTextureMapIndex(Flag_Metalness);\n\n\tif (map == 0)\n\t\treturn fMetalness;\n\n\treturn fMetalness * getTextureMap(map).r;\n}\n\nfloat getRoughness() {\n\tint map = getTextureMapIndex(Flag_Roughness);\n\n\tif (map == 0)\n\t\treturn fRoughness;\n\n\treturn fRoughness * getTextureMap(map).r;\n}\n\nfloat getAmbientOcclusion() {\n\tint map = getTextureMapIndex(Flag_AO);\n\n\tif (map == 0)\n\t\treturn fAmbientOcclusion;\n\n\treturn fAmbientOcclusion * getTextureMap(map).r;\n}\n\nvec3 hsv2rgb(vec3 c) {\n\tvec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n\tvec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n\treturn c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n}\n\nvoid main() {\n\talbedo = getAlbedo();\n\troughness = getRoughness();\n\tmetalness = getMetalness();\n\tambientOcclusion = getAmbientOcclusion();\n\n\tN = getNormal();\n\tV = normalize(viewPosition - fPosition);\n\n\t// Light calculations\n\tvec3 Lo = vec3(0);\n\tfor (int i = 0; i < min(maxLights, lightCount); i++)\n\t\tif (lights[i].intensity > 0)\n\t\t\tLo += calcLightColor(lights[i]);\n\n\t// Ambient\n\tvec3 ambient = albedo.rgb * mix(vec3(ambientOcclusion), skybox(), metalness);\n\n\t// Directional\n\tvec3 Ld = calcDirectionalLight();\n\n\t// Shadow\n\tfloat shadow = calcShadow();\n\n\t// Combine ambient and lighting\n\tvec3 color = ambient + (1.0 - shadow) * Ld * ambient + Lo;\n\n\t// HDR \n\tcolor = hdr * (vec3(1.0) - exp(-color * exposure)) + (1.0 - hdr) * color;\n\n\t// Gamma\n\tcolor = pow(color, vec3(1.0 / gamma));\n\n\t// Outcolor\n\tif (mode == Mode_Default)\n\t\toutColor = vec4(color, albedo.a);\n\telse if (mode == Mode_Position)\n\t\toutColor = vec4(fPosition, 1.0);\n\telse if (mode == Mode_Normal)\n\t\toutColor = vec4(N, 1.0);\n\telse if (mode == Mode_UV)\n\t\toutColor = vec4(fUV, 0.0, 1.0);\n\telse if (mode == Mode_LightSpace)\n\t\toutColor = vec4(fLightSpacePosition);\n\telse if (mode == Mode_Albedo)\n\t\toutColor = vec4(albedo);\n\telse if (mode == Mode_Metalness)\n\t\toutColor = vec4(vec3(metalness), 1.0);\n\telse if (mode == Mode_Roughness)\n\t\toutColor = vec4(vec3(roughness), 1.0);\n\telse if (mode == Mode_AO)\n\t\toutColor = vec4(vec3(ambientOcclusion), 1.0);\n\telse if (mode == Mode_TextureFlags)\n\t\toutColor = vec4(vec3(float(getTextureMapIndex(Flag_Albedo)) / 3.0), 1.0);\n\telse\n\t\toutColor = vec4(hsv2rgb(vec3(mod(gl_PrimitiveID, 50) / 50.0, 1.0, 1.0)), 1.0);\n\n\t//outColor = vec4(vec3(fbm(fNormal)), 1.0);\n}"
  },
  {
    "path": "res/shaders/lighting.shader",
    "content": "[common]\n\n#version 330 core\n\nvec4 apply(mat4 matrix, vec3 vector) {\n\treturn matrix * vec4(vector, 0.0);\n}\n\nvec3 apply3(mat4 matrix, vec3 vector) {\n\treturn mat3(matrix) * vector;\n}\n\nvec4 applyT(mat4 matrix, vec3 vector) {\n\treturn matrix * vec4(vector, 1.0);\n}\n\nvec3 applyT3(mat4 matrix, vec3 vector) {\n\treturn (matrix * vec4(vector, 1.0)).xyz;\n}\n\nvec4 applyN(mat4 matrix, vec3 vector) {\n\treturn normalize(matrix * vec4(vector, 0.0));\n}\n\nvec3 apply3N(mat4 matrix, vec3 vector) {\n\treturn normalize(mat3(matrix) * vector);\n}\n\nvec4 applyTN(mat4 matrix, vec3 vector) {\n\treturn normalize(matrix * vec4(vector, 1.0));\n}\n\nvec3 applyT3N(mat4 matrix, vec3 vector) {\n\treturn normalize((matrix * vec4(vector, 1.0)).xyz);\n}\n\nvec4 rgba(vec3 color) {\n\treturn vec4(color, 1.0);\n}\n\nvec4 rgba(float color) {\n\treturn vec4(color, color, color, 1.0);\n}\n\n//------------------------------------------------------------------------------//\n\n[vertex]\n\nlayout(location = 0) in vec3 vPosition;\nlayout(location = 1) in vec3 vNormal;\nlayout(location = 2) in vec2 vUV;\nlayout(location = 3) in vec3 vTangent;\nlayout(location = 4) in vec3 vBitangent;\nlayout(location = 5) in mat4 vModelMatrix;\nlayout(location = 9) in vec4 vAlbedo;\nlayout(location = 10) in vec3 vMRAo;\n\nsmooth out vec3 fPosition;\nsmooth out vec2 fUV;\nsmooth out vec3 fNormal;\n \nflat out vec4 fAlbedo;\nflat out float fMetallic;\nflat out float fRoughness;\nflat out float fAmbientOcclusion;\n\nuniform mat4 viewMatrix;\nuniform mat4 projectionMatrix;\n\nvoid main() {\n\tfAlbedo = vAlbedo;\n\tfMetallic = vMRAo.x;\n\tfRoughness = vMRAo.y;\n\tfAmbientOcclusion = vMRAo.z;\n\n\tfUV = vec2(vUV.x, 1-vUV.y);\n\tfPosition = applyT3(vModelMatrix, vPosition);\n\tfNormal = apply3(vModelMatrix, vNormal);\n\n\tgl_Position = applyT(projectionMatrix * viewMatrix, fPosition);\n}\n\n//------------------------------------------------------------------------------//\n\n[fragment]\n\n// Out\nout vec4 outColor;\n\n// In\nsmooth in vec2 fUV;\nsmooth in vec3 fPosition;\nsmooth in vec3 fNormal; \n\nflat in vec4 fAlbedo;\nflat in float fRoughness;\nflat in float fMetallic;\nflat in float fAmbientOcclusion;\n\n// General\nvec3 N;\nvec3 V;\nvec4 albedo;\nfloat roughness;\nfloat metallic;\nfloat ambientOcclusion;\n\n// Structs\nstruct Attenuation {\n\tfloat constant;\n\tfloat linear;\n\tfloat exponent;\n};\n\nstruct Light {\n\tvec3 position;\n\tvec3 color;\n\tfloat intensity;\n\tAttenuation attenuation;\n};\n\n// Transform\nuniform vec3 viewPosition;\n\n// Light\n#define maxLights 10\nuniform int lightCount;\nuniform Light lights[maxLights];\n\n// Textures\nuniform sampler2D albedoMap;\nuniform sampler2D normalMap;\nuniform sampler2D metallicMap;\nuniform sampler2D roughnessMap;\nuniform sampler2D ambientOcclusionMap;\nuniform int textured;\n\n// Environment\nuniform vec3 sunDirection = vec3(1, 1, 1);\nuniform vec3 sunColor = vec3(1, 1, 1);\nuniform float exposure = 1.0;\nuniform float gamma = 1.0;\nuniform float hdr = 1.0;\n\n// Constants\nconst float PI = 3.14159265359;\n\nfloat ggxTrowbridgeReitz(vec3 N, vec3 H, float roughness) {\n\tfloat alpha = roughness * roughness;\n\tfloat alpha2 = alpha * alpha;\n\tfloat NdotH = max(dot(N, H), 0.0);\n\tfloat NdotH2 = NdotH * NdotH;\n\n\tfloat numerator = alpha2;\n\tfloat denominator = (NdotH2 * (alpha2 - 1.0) + 1.0);\n\tdenominator = max(PI * denominator * denominator, 0.001);\n\n\treturn numerator / denominator;\n}\n\nfloat ggxSchlick(float NdotV, float roughness) {\n\tfloat r = roughness + 1.0;\n\tfloat k = (r * r) / 8.0;\n\n\tfloat numerator = NdotV;\n\tfloat denominator = NdotV * (1.0 - k) + k;\n\n\treturn numerator / denominator;\n}\n\nfloat smith(vec3 N, vec3 V, vec3 L, float roughness) {\n\tfloat NdotV = max(dot(N, V), 0.0);\n\tfloat NdotL = max(dot(N, L), 0.0);\n\tfloat ggx2 = ggxSchlick(NdotV, roughness);\n\tfloat ggx1 = ggxSchlick(NdotL, roughness);\n\n\treturn ggx1 * ggx2;\n}\n\nvec3 fresnelSchlick(float cosTheta, vec3 F0) {\n\t// F0: surface reflection at zero incidence\n\treturn F0 + (1.0 - F0) * pow(1.0 - min(cosTheta, 1.0), 5.0);\n}\n\nvec3 calcDirectionalLight() {\n\tvec3 directionalLight = normalize(sunDirection);\n\tfloat directionalFactor = 0.4 * max(dot(N, directionalLight), 0.0);\n\tvec3 directional = directionalFactor * sunColor;\n\treturn directional;\n}\n\nvec3 calcLightColor(Light light) {\n\t// General light variables\n\tvec3 L = normalize(light.position - fPosition);\n\tvec3 H = normalize(V + L);\n\tfloat distance = length(light.position - fPosition);\n\t//float scaledDistance = distance / light.intensity;\n\t//float attenuation = 1.0 / (light.attenuation.constant + light.attenuation.linear * scaledDistance + light.attenuation.exponent * scaledDistance * scaledDistance);\n\tfloat attenuation = 1.0 / (distance * distance);\n\tvec3 radiance = light.color * attenuation;\n\n\t// Fresnel\n\tvec3 F0_NM = vec3(0.04); // Non metallic F0\n\tvec3 F0 = mix(F0_NM, albedo.rgb, metallic);\n\tfloat cosTheta = max(dot(H, V), 0.0);\n\tvec3 F = fresnelSchlick(cosTheta, F0);\n\n\t// DFG\n\tfloat D = ggxTrowbridgeReitz(N, H, roughness);\n\tfloat G = smith(N, V, L, roughness);\n\tvec3 DFG = D * F * G;\n\n\t// Cook Torrance\n\tvec3 numerator = DFG;\n\tfloat denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0);\n\tvec3 specular = numerator / max(denominator, 0.001);\n\n\t// Light contribution constants\n\tvec3 kS = F;\n\tvec3 kD = vec3(1.0) - kS;\n\tkD *= 1.0 - metallic;\n\n\tfloat NdotL = max(dot(N, L), 0.0);\n\tvec3 Lo = (kD * albedo.rgb / PI + specular) * radiance * NdotL;\n\t\n\treturn Lo;\n}\n\nvec3 getNormalFromMap() {\n\tvec3 tangentNormal = texture(normalMap, fUV).xyz * 2.0 - 1.0;\n\n\tvec3 Q1 = dFdx(fPosition);\n\tvec3 Q2 = dFdy(fPosition);\n\tvec2 st1 = dFdx(fUV);\n\tvec2 st2 = dFdy(fUV);\n\n\tvec3 N = normalize(fNormal);\n\tvec3 T = normalize(Q1 * st2.t - Q2 * st1.t);\n\tvec3 B = -normalize(cross(N, T));\n\tmat3 TBN = mat3(T, B, N);\n\n\treturn normalize(TBN * tangentNormal);\n}\n\nvoid main() {\n\tif (textured == 1) {\n\t\talbedo = texture(albedoMap, fUV) * texture(albedoMap, fUV);\n\t\tN = getNormalFromMap();\n\t\troughness = 1-texture(roughnessMap, fUV).r;\n\t\tmetallic = texture(metallicMap, fUV).r;\n\t\tambientOcclusion = texture(ambientOcclusionMap, fUV).r;\n\t} else {\n\t\talbedo = fAlbedo;\n\t\troughness = fRoughness;\n\t\tmetallic = fMetallic;\n\t\tambientOcclusion = fAmbientOcclusion;\n\t}\n\n\tV = normalize(viewPosition - fPosition);\n\n\t// Light calculations\n\tvec3 Lo = vec3(0);\n\tfor (int i = 0; i < min(maxLights, lightCount); i++) {\n\t\tif (lights[i].intensity > 0) {\n\t\t\tLo += calcLightColor(lights[i]);\n\t\t}\n\t}\n\n\t// Ambient\n\tvec3 ambient = vec3(0.03) * albedo.rgb * ambientOcclusion;\n\n\t// Combine ambient and lighting\n\tvec3 color = ambient + Lo;\n\n\t// HDR \n\tcolor = hdr * (vec3(1.0) - exp(-color * exposure)) + (1.0 - hdr) * color;\n\n\t// Gamma\n\tcolor = pow(color, vec3(1.0 / gamma));\n\n\t// Outcolor\n\toutColor = vec4(color, albedo.a);\n\n\t//outColor = rgba(N);\n\t//outColor = texture(normalMap, fUV);\n\t//outColor = texture(textureMap, fUV);\n\t//outColor = vec4(fUV, 0, 1);\n}\n\n"
  },
  {
    "path": "res/shaders/line.shader",
    "content": "[common]\n\n#version 330 core\n\n//------------------------------------------------------------------------------//\n\n[vertex]\n\nlayout (location = 0) in vec3 vposition;\nlayout (location = 1) in vec4 vcolor;\n\nout vec4 fcolor;\n\nuniform mat4 viewMatrix;\nuniform mat4 projectionMatrix;\n\nvoid main() {\n\tgl_Position = projectionMatrix * viewMatrix * vec4(vposition, 1.0);\n\tfcolor = vcolor;\n}\n\n//------------------------------------------------------------------------------//\n\n[fragment]\n\nin vec4 fcolor;\n\nout vec4 outColor;\n\nvoid main() {\n\toutColor = fcolor;\n}"
  },
  {
    "path": "res/shaders/mask.shader",
    "content": "[common]\n\n#version 330 core\n\n//------------------------------------------------------------------------------//\n\n[vertex]\n\nlayout(location = 0) in vec3 vPosition;\n\nuniform mat4 projectionMatrix;\nuniform mat4 modelMatrix;\nuniform mat4 viewMatrix;\nuniform vec3 viewPosition;\n\nvoid main() {\n\tgl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(vPosition, 1.0);\n}\n\n//------------------------------------------------------------------------------//\n\n[fragment]\n\nout vec4 outColor;\n\nuniform vec4 color = vec4(1, 1, 1, 1);\n\nvoid main() {\n\toutColor = color;\n}"
  },
  {
    "path": "res/shaders/origin.shader",
    "content": "[common]\n\n#version 330 core\n\n//------------------------------------------------------------------------------//\n\n[vertex]\n\nlayout(location = 0) in vec3 rotation;\n\nvoid main() {\n\tgl_Position = vec4(0.8, -0.8, -1, 1);\n}\n\n//------------------------------------------------------------------------------//\n\n[geometry]\n\nlayout(points) in;\nlayout(line_strip, max_vertices = 256) out;\n\nuniform mat4 rotatedViewMatrix;\nuniform mat4 viewMatrix;\nuniform mat4 projectionMatrix;\nuniform mat4 orthoMatrix;\nuniform vec3 viewPosition;\n\nout vec3 fcolor;\n\nint gridSize = 32;\n\nvoid main() {\n\tvec3 unitVectors[3] = vec3[](vec3(1, 0, 0), vec3(0, 1, 0), vec3(0, 0, 1));\n\n\tfloat size = 0.1;\n\tfor (int i = 0; i < 3; i++) {\n\t\tvec3 rotatedUnitVector = (rotatedViewMatrix * vec4(unitVectors[i], 0)).xyz * size;\n\n\t\tfloat arrowLength = 0.025;\n\t\tfloat arrowWidth = 0.00625;\n\t\tvec4 origin = vec4(0, 0, gl_in[0].gl_Position.zw);\n\t\tvec4 arrowTop = origin + vec4(rotatedUnitVector, 0);\n\t\tvec3 norm = normalize(cross(arrowTop.xyz, rotatedUnitVector));\n\t\tvec3 unitRotation = normalize(rotatedUnitVector);\n\t\tvec4 arrowLeft = arrowTop - vec4(arrowLength * unitRotation - arrowWidth * norm, 0);\n\t\tvec4 arrowRight = arrowTop - vec4(arrowLength * unitRotation + arrowWidth * norm, 0);\n\t\tvec4 arrowBase = arrowTop - arrowLength * vec4(unitRotation, 0);\n\n\t\tfcolor = unitVectors[i];\n\t\tvec4 position = vec4(gl_in[0].gl_Position.xy, 0, 0);\n\t\tgl_Position = position + orthoMatrix * origin; EmitVertex();\n\t\tgl_Position = position + orthoMatrix * arrowBase; EmitVertex();\n\t\tgl_Position = position + orthoMatrix * arrowLeft; EmitVertex();\n\t\tgl_Position = position + orthoMatrix * arrowTop; EmitVertex();\n\t\tgl_Position = position + orthoMatrix * arrowRight; EmitVertex();\n\t\tgl_Position = position + orthoMatrix * arrowBase; EmitVertex();\n\t\tEndPrimitive();\n\t}\n\n\t/*float camerax = floor(viewPosition.x);\n\tfloat cameraz = floor(viewPosition.z);\n\t\n\tfor (float t = 0.0; t < gridSize / 2; t++) {\t\n\t\tfcolor = vec3(0.5 - t / gridSize);\n\t\tgl_Position = projectionMatrix * viewMatrix * vec4(camerax - gridSize / 2, 0, cameraz + t, 1); EmitVertex();\n\t\tgl_Position = projectionMatrix * viewMatrix * vec4(camerax + gridSize / 2, 0, cameraz + t, 1); EmitVertex();\n\t\tEndPrimitive();\n\n\t\tgl_Position = projectionMatrix * viewMatrix * vec4(camerax - gridSize / 2, 0, cameraz - t, 1); EmitVertex();\n\t\tgl_Position = projectionMatrix * viewMatrix * vec4(camerax + gridSize / 2, 0, cameraz - t, 1); EmitVertex();\n\t\tEndPrimitive();\n\n\t\tgl_Position = projectionMatrix * viewMatrix * vec4(camerax + t, 0, cameraz - gridSize / 2, 1); EmitVertex();\n\t\tgl_Position = projectionMatrix * viewMatrix * vec4(camerax + t, 0, cameraz + gridSize / 2, 1); EmitVertex();\n\t\tEndPrimitive();\n\n\t\tgl_Position = projectionMatrix * viewMatrix * vec4(camerax - t, 0, cameraz - gridSize / 2, 1); EmitVertex();\n\t\tgl_Position = projectionMatrix * viewMatrix * vec4(camerax - t, 0, cameraz + gridSize / 2, 1); EmitVertex();\n\t\tEndPrimitive();\n\t}*/\n}\n\n//------------------------------------------------------------------------------//\n\n[fragment]\n\nlayout(location = 0) out vec4 outColor;\n\nin vec3 fcolor;\n\nvoid main() {\n\toutColor = vec4(fcolor, 1);\n}"
  },
  {
    "path": "res/shaders/point.shader",
    "content": "[common]\n\n#version 330 core\n\n//------------------------------------------------------------------------------//\n\n[vertex]\n\nlayout(location = 0) in vec3 vposition;\nlayout(location = 1) in float vsize;\nlayout(location = 2) in vec3 vcolor1;\nlayout(location = 3) in vec3 vcolor2;\n\nout vec3 gcolor1;\nout vec3 gcolor2;\nout float gsize;\n\nvoid main() { \n\tgcolor1 = vcolor1;\n\tgcolor2 = vcolor2;\n\tgsize = vsize;\n\tgl_Position = vec4(vposition, 1);\n}\n\n//------------------------------------------------------------------------------//\n\n[geometry]\n\nlayout(points) in;\nlayout(triangle_strip, max_vertices = 24) out;\n\nin vec3 gcolor1[];\nin vec3 gcolor2[];\nin float gsize[];\n\nout vec3 fcolor;\n\nuniform mat4 viewMatrix;\nuniform mat4 projectionMatrix;\nuniform vec3 viewPosition;\n\nvoid makeTriangle(vec4 a, vec4 b, vec4 c, vec3 color) {\n\tfcolor = color;\n\tgl_Position = projectionMatrix * viewMatrix * a;\n\tEmitVertex();\n\n\tgl_Position = projectionMatrix * viewMatrix * b;\n\tEmitVertex();\n\n\tgl_Position = projectionMatrix * viewMatrix * c;\n\tEmitVertex();\n\tEndPrimitive();\n}\n\nvoid main() {\n\tvec4 origin = gl_in[0].gl_Position;\n\tfloat size = gsize[0] * sqrt(length(origin.xyz-viewPosition));\n\tvec3 colorA = gcolor1[0];\n\tvec3 colorB = gcolor2[0];\n\tvec4 xPos = origin + vec4(size, 0, 0, 0);\n\tvec4 xNeg = origin + vec4(-size, 0, 0, 0);\n\tvec4 yPos = origin + vec4(0, size, 0, 0);\n\tvec4 yNeg = origin + vec4(0, -size, 0, 0);\n\tvec4 zPos = origin + vec4(0, 0, size, 0);\n\tvec4 zNeg = origin + vec4(0, 0, -size, 0);\n\n\n\tmakeTriangle(xPos, yPos, zPos, colorA);\n\tmakeTriangle(zPos, yPos, xNeg, colorB);\n\tmakeTriangle(xNeg, yPos, zNeg, colorA);\n\tmakeTriangle(zNeg, yPos, xPos, colorB);\n\n\tmakeTriangle(zNeg, yNeg, xNeg, colorB);\n\tmakeTriangle(xPos, yNeg, zNeg, colorA);\n\tmakeTriangle(zPos, yNeg, xPos, colorB);\n\tmakeTriangle(xNeg, yNeg, zPos, colorA);\n}\n\n//------------------------------------------------------------------------------//\n\n[fragment]\n\nlayout(location = 0) out vec4 outColor;\n\nin vec3 fcolor;\n\nvoid main() {\n\toutColor = vec4(fcolor, 1);\n}"
  },
  {
    "path": "res/shaders/postprocess.shader",
    "content": "[common]\n\n#version 330 core\n\n//------------------------------------------------------------------------------//\n\n[vertex]\n\nlayout(location = 0) in vec4 positions;\n\nout vec2 fUV;\n\nvoid main() {\n\tgl_Position = vec4(positions.xy, 0.0, 1.0);\n\tfUV = positions.zw;\n}\n\n//------------------------------------------------------------------------------//\n\n[fragment]\n\nin vec2 fUV;\nout vec4 outColor;\n\nuniform sampler2D textureSampler;\n\nconst float offset = 1.0 / 600.0;\n\nfloat rbgToLin(float channel) {\n\tif (channel <= 0.04045) {\n\t\treturn channel / 12.92;\n\t} else {\n\t\treturn pow((channel + 0.055) / 1.055, 2.4);\n\t}\n}\n\nvec4 kernelEffect() {\n\tvec2 offsets[9] = vec2[](\n\t\tvec2(-offset, offset),\n\t\tvec2(0.0f, offset),\n\t\tvec2(offset, offset),\n\t\tvec2(-offset, 0.0f),\n\t\tvec2(0.0f, 0.0f),\n\t\tvec2(offset, 0.0f),\n\t\tvec2(-offset, -offset),\n\t\tvec2(0.0f, -offset),\n\t\tvec2(offset, -offset)\n\t\t);\n\n\tfloat gx[9] = float[](\n\t\t-1, 0, 1,\n\t\t-1, 0, 1,\n\t\t-1, 0, 1\n\t\t);\n\n\tfloat gy[9] = float[](\n\t\t-1, -1, -1,\n\t\t0, 0, 0,\n\t\t1, 1, 1\n\t\t);\n\n\tfloat kernel[9] = float[](\n\t\t0, 0, 0,\n\t\t0, 1, 0,\n\t\t0, 0, 0\n\t\t);\n\n\tvec3 sampleGrayTexture[9];\n\tvec3 sampleColorTexture[9];\n\tvec3 color = vec3(0.0);\n\tvec3 sx = vec3(0.0);\n\tvec3 sy = vec3(0.0);\n\n\tfor (int i = 0; i < 9; i++) {\n\t\tvec3 rgb = vec3(texture(textureSampler, fUV.st + offsets[i]));\n\n\t\tsampleColorTexture[i] = rgb;\n\t\tcolor += rgb * kernel[i];\n\t\t\n\t\t//float y = 0.2126 * rbgToLin(rgb.x) + 0.7152 * rbgToLin(rgb.y) + 0.0722 * rbgToLin(rgb.z);\n\t\t//sampleGrayTexture[i] = vec3(y);\n\t\t//sx += sampleGrayTexture[i] * gx[i];\n\t\t//sy += sampleGrayTexture[i] * gy[i];\n\t}\n\n\t//vec3 s = vec3(1.0) - sqrt(sx*sx + sy*sy);\n\n\treturn vec4(color, 1.0);\n}\n\nvec4 defaultEffect() {\n\treturn texture(textureSampler, fUV.st);\n}\n\nvec4 pixelEdgeEffect() {\n\tvec4 color = vec4(fwidth(defaultEffect().x * 64.0));\n\treturn 1.0 - floor(color);\n}\n\nvec4 knitEffect() {\n\tvec2 resolution = vec2(1920, 1080);\n\tvec2 tileSize = vec2(16.0, 16.0);\n\tfloat threads = 10.0;\n\n\tvec2 posInTile = mod(gl_FragCoord.xy, tileSize);\n\tvec2 tileNum = floor(gl_FragCoord.xy / tileSize);\n\n\tvec2 nrmPosInTile = posInTile / tileSize;\n\ttileNum.y += floor(abs(nrmPosInTile.x - 0.5) + nrmPosInTile.y);\n\n\tvec2 texCoord = tileNum * tileSize / resolution;\n\t//texCoord.y = 1.0 - texCoord.y;\n\n\tvec3 color = texture(textureSampler, texCoord).rgb;\n\n\tcolor *= fract((nrmPosInTile.y + abs(nrmPosInTile.x - 0.5)) * floor(threads));\n\n\treturn vec4(color, 1.0);\n}\n\nvoid main() {\n\toutColor = defaultEffect();\n}"
  },
  {
    "path": "res/shaders/quad.shader",
    "content": "[common]\n\n#version 330 core\n\n//------------------------------------------------------------------------------//\n\n[vertex]\n\nlayout(location = 0) in vec4 vPosition;\n\nuniform mat4 projectionMatrix;\n\nout vec2 fUV;\n\nvoid main() {\n\tgl_Position = projectionMatrix * vec4(vPosition.xy, 0.0, 1.0);\n\tfUV = vPosition.zw;\n}\n\n//------------------------------------------------------------------------------//\n\n[fragment]\n\nout vec4 outColor;\n\nin vec2 fUV;\n\nuniform bool textured;\nuniform sampler2D textureSampler;\nuniform vec4 color = vec4(1, 1, 1, 1);\n\nvoid main() {\n\toutColor = (textured) ? texture(textureSampler, fUV) * color : color;\n}"
  },
  {
    "path": "res/shaders/sky.shader",
    "content": "[properties]\nfloat densityFalloff (uniform_ddkd) = 4 (0:100);\nint inScatterPoints = 10 (1:100);\nint opticalDepthPoints = 10 (1:100);\nvec3 sunPosition = 10.0, 20.0, 0.0;\nvec3 waveLengths = 700, 530, 440;\nfloat scatteringStrength = 1.0 (1.0:10.0);\nfloat atmosphereScale = 1.0 (0.0:5.0);\n\n[common]\n\n#version 330 core\n\nconst float INFINITY = 1.0 / 0.0;\nconst float EPSILON = 0.0001;\nconst float PI = 3.14159265358979323846;\n\nuniform mat4 uViewMatrix;\nuniform mat4 uProjectionMatrix;\n\nuniform float densityFalloff = 4.0;\nuniform int inScatterPoints = 10;\nuniform int opticalDepthPoints = 10;\nuniform vec3 sunPosition = vec3(10.0, 20.0, 0.0);\nuniform vec3 waveLengths = vec3(700, 530, 440);\nuniform float scatteringStrength = 1.0;\nuniform float atmosphereScale = 1.0;\n\nvec4 applyT(mat4 matrix, vec3 vector) {\n\treturn matrix * vec4(vector, 1.0);\n}\n\nvec3 applyT3(mat4 matrix, vec3 vector) {\n\treturn (matrix * vec4(vector, 1.0)).xyz;\n}\n\n///////////////////////////////////////////////////////////////////////////////////////\n\n[vertex]\n\nlayout(location = 0) in vec4 vPositionUV;\n\nsmooth out vec2 fUV;\n\nvoid main() {\n\tfUV = vPositionUV.zw;\n\tgl_Position = vec4(vPositionUV.xy, 0.0, 1.0);\n}\n\n///////////////////////////////////////////////////////////////////////////////////////\n\n[fragment]\n\n// Structs\nstruct Sphere {\n\tvec3 center;\n\tfloat radius;\n};\n\nstruct Plane {\n\tvec3 center;\n\tvec3 normal;\n};\n\nstruct Ray {\n\tvec3 origin;\n\tvec3 direction;\n};\n\nstruct Hit {\n\tfloat t;\n\tfloat dt;\n};\n\nstruct Screen {\n\tvec2 dimension;\n};\n\n// In\nsmooth in vec2 fUV;\n\n// Out\nout vec4 outColor;\n\nuniform Sphere uAtmosphere = Sphere(vec3(0.0, 0.0, 0.0), 10.0);\nuniform Plane uGround = Plane(vec3(0.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0));\nuniform Ray uCamera = Ray(vec3(0.0, 0.0, 0.0), vec3(0.0, 0.0, 1.0));\nuniform Screen uScreen = Screen(vec2(1.0, 1.0));\n\nuniform sampler2D uOriginalColor;\n\n// Functions\nbool inside(vec3 point, Sphere sphere) {\n\treturn length(point - sphere.center) <= sphere.radius;\n}\n\nbool above(vec3 point, Plane plane) {\n\treturn dot(point - plane.center, plane.normal) > 0.0;\n}\n\nHit hitSphere(Sphere sphere, Ray ray) {\n\tvec3 offset = ray.origin - sphere.center;\n\n\tfloat a = 1.0;\n\tfloat b = 2.0 * dot(offset, ray.direction);\n\tfloat c = dot(offset, offset) - sphere.radius * sphere.radius;\n\tfloat d = b * b - 4.0 * a * c;\n\n\tif (d > 0.0) {\n\t\tfloat s = sqrt(d);\n\t\tfloat near = (-b - s) / (2.0 * a);\n\t\tfloat far = (-b + s) / (2.0 * a);\n\n\t\t// Behind\n\t\tif (near < 0.0 && far < 0.0)\n\t\t\treturn Hit(INFINITY, 0.0);\n\n\t\t// Inside\n\t\tif (near * far < 0.0)\n\t\t\treturn Hit(max(near, far), 0.0);\n\n\t\t// Outside\n\t\treturn Hit(min(near, far), 0.0);\n\t}\n\n\t// Miss\n\treturn Hit(INFINITY, 0.0);\n}\n\nHit hitPlane(Plane plane, Ray ray) {\n\tfloat denominator = dot(ray.direction, plane.normal);\n\n\t// Parallel\n\tif (abs(denominator) < EPSILON)\n\t\treturn Hit(INFINITY, 0.0);\n\n\tfloat t = -dot(plane.center - ray.origin, plane.normal) / denominator;\n\n\t// Behind\n\tif (t < 0.0)\n\t\treturn Hit(INFINITY, 0.0);\n\n\treturn Hit(t, 0.0);\n}\n\nHit hitDisk(Plane plane, Sphere sphere, Ray ray) {\n\tHit planeHit = hitPlane(plane, ray);\n\n\tif (planeHit.t == INFINITY)\n\t\treturn Hit(INFINITY, 0.0);\n\n\tvec3 point = ray.origin + planeHit.t * ray.direction;\n\tif (!inside(point, sphere))\n\t\treturn Hit(INFINITY, 0.0);\n\n\treturn planeHit;\n}\n\nHit hitHemisphere(Plane plane, Sphere sphere, Ray ray) {\n\tHit sphereHit = hitSphere(sphere, ray);\n\tHit planeHit = hitPlane(plane, ray);\n\tHit hit = Hit(min(sphereHit.t, planeHit.t), 0.0);\n\n\treturn hit;\n}\n\nfloat densityAtPoint(vec3 densitySamplePoint) {\n\tfloat heightAboveSurface = dot(densitySamplePoint - uGround.center, uGround.normal);\n\tfloat atmosphereHeight = uAtmosphere.radius;\n\tfloat normalizedHeightAboveSurface = heightAboveSurface / atmosphereHeight;\n\tfloat localDensity = exp(-normalizedHeightAboveSurface * (densityFalloff / 10.0)) * (1.0 - normalizedHeightAboveSurface);\n\n\treturn localDensity;\n}\n\nfloat opticalDepth(Ray ray, float rayLength) {\n\tvec3 densityAtSamplePoint = ray.origin;\n\tfloat stepSize = rayLength / float(opticalDepthPoints - 1);\n\t\n\tfloat opticalDepth = 0.0;\n\tfor (int i = 0; i < opticalDepthPoints; i++) {\n\t\tfloat localDensity = densityAtPoint(densityAtSamplePoint);\n\n\t\topticalDepth += localDensity * stepSize;\n\t\tdensityAtSamplePoint += ray.direction * stepSize;\n\t}\n\n\treturn opticalDepth;\n}\n\nvec3 calculateLight(Ray ray, float rayLength, vec3 originalColor) {\n\tvec3 scatteringCoefficients = pow(vec3(400.0) / waveLengths, vec3(4.0)) * scatteringStrength;\n\n\tvec3 inScatterPoint = ray.origin;\n\tfloat stepSize = rayLength / float(inScatterPoints - 1);\n\tfloat viewRayOpticalDepth = 0.0;\n\tvec3 inScatteredLight = vec3(0.0);\n\tfor (int i = 0; i < inScatterPoints; i++) {\n\t\tRay sunRay = Ray(inScatterPoint, normalize(sunPosition - inScatterPoint));\n\t\tRay viewRay = Ray(inScatterPoint, -ray.direction);\n\n\t\tfloat sunRayLength = hitSphere(uAtmosphere, sunRay).t;\n\t\tfloat viewRayLength = stepSize * float(i);\n\n\t\tfloat sunRayOpticalDepth = opticalDepth(sunRay, sunRayLength);\n\t\tviewRayOpticalDepth = opticalDepth(viewRay, viewRayLength);\n\n\t\tvec3 transmittance = exp(-(sunRayOpticalDepth + viewRayOpticalDepth) * scatteringCoefficients);\n\t\tfloat localDensity = densityAtPoint(inScatterPoint);\n\n\t\tinScatteredLight += localDensity * transmittance * scatteringCoefficients * stepSize;\n\t\tinScatterPoint += ray.direction * stepSize;\n\t}\n\n\tfloat originalColorTransmittance = exp(-viewRayOpticalDepth);\n\n\treturn originalColor * originalColorTransmittance + normalize(inScatteredLight);\n}\n\nfloat atan2(float y, float x) {\n\tbool s = abs(x) > abs(y);\n\treturn mix(PI / 2.0 - atan(x, y), atan(y, x), s);\n}\n\nconst float pi = 3.14159265359;\nconst float invPi = 1.0 / pi;\n\nconst float zenithOffset = 0.1;\nconst float multiScatterPhase = 0.1;\nconst float density = 0.7;\n\nconst float anisotropicIntensity = 0.0; //Higher numbers result in more anisotropic scattering\n\nconst vec3 skyColor = vec3(0.39, 0.57, 1.0) * (1.0 + anisotropicIntensity); //Make sure one of the conponents is never 0.0\n\n#define smooth(x) x*x*(3.0-2.0*x)\n#define zenithDensity(x) density / pow(max(x - zenithOffset, 0.35e-2), 0.75)\n\nvec3 getSkyAbsorption(vec3 x, float y) {\n\n\tvec3 absorption = x * -y;\n\tabsorption = exp2(absorption) * 2.0;\n\n\treturn absorption;\n}\n\nfloat getSunPoint(vec2 p, vec2 lp) {\n\treturn smoothstep(0.03, 0.026, distance(p, lp)) * 50.0;\n}\n\nfloat getRayleigMultiplier(vec2 p, vec2 lp) {\n\treturn 1.0 + pow(1.0 - clamp(distance(p, lp), 0.0, 1.0), 2.0) * pi * 0.5;\n}\n\nfloat getMie(vec2 p, vec2 lp) {\n\tfloat disk = clamp(1.0 - pow(distance(p, lp), 0.1), 0.0, 1.0);\n\n\treturn disk * disk * (3.0 - 2.0 * disk) * 2.0 * pi;\n}\n\nvec3 getAtmosphericScattering(vec2 p, vec2 lp) {\n\tvec2 correctedLp = lp / max(uScreen.dimension.x, uScreen.dimension.y) * uScreen.dimension.xy;\n\n\tfloat zenith = zenithDensity(p.y);\n\tfloat sunPointDistMult = clamp(length(max(correctedLp.y + multiScatterPhase - zenithOffset, 0.0)), 0.0, 1.0);\n\n\tfloat rayleighMult = getRayleigMultiplier(p, correctedLp);\n\n\tvec3 absorption = getSkyAbsorption(skyColor, zenith);\n\tvec3 sunAbsorption = getSkyAbsorption(skyColor, zenithDensity(correctedLp.y + multiScatterPhase));\n\tvec3 sky = skyColor * zenith * rayleighMult;\n\tvec3 sun = getSunPoint(p, correctedLp) * absorption;\n\tvec3 mie = getMie(p, correctedLp) * sunAbsorption;\n\n\tvec3 totalSky = mix(sky * absorption, sky / (sky + 0.5), sunPointDistMult);\n\ttotalSky += sun + mie;\n\ttotalSky *= sunAbsorption * 0.5 + 0.5 * length(sunAbsorption);\n\n\treturn totalSky;\n}\n\nvec3 jodieReinhardTonemap(vec3 c) {\n\tfloat l = dot(c, vec3(0.2126, 0.7152, 0.0722));\n\tvec3 tc = c / (c + 1.0);\n\n\treturn mix(c / (l + 1.0), tc, tc);\n}\n\n// Main\nvoid main() {\n\tfloat s = 1;\n\tvec3 up = vec3(0.0, 1.0, 0.0);\n\tvec3 w = -uCamera.direction;\n\tvec3 u = cross(up, w);\n\tvec3 v = cross(w, u);\n\tvec3 cam = vec3((gl_FragCoord.xy - uScreen.dimension / 2.0) / uScreen.dimension.x * s, -1.0);\n\t//vec3 cam = vec3(fUV * 2.0 - vec2(1.0), -1);\n\tvec3 dir = normalize(cam.x * u + cam.y * v + cam.z * w);\n\tRay ray = Ray(uCamera.origin, dir);\n\n\tfloat distanceThroughAtmosphere = hitHemisphere(uGround, uAtmosphere, ray).t;\n\n\tvec3 originalColor = texture(uOriginalColor, fUV).rgb;\n\t/*if (distanceThroughAtmosphere != INFINITY) {\n\t\t//vec3 pointInAtmosphere = ray.origin + ray.direction * (distanceThroughAtmosphere + EPSILON);\n\t\tvec3 light = calculateLight(Ray(ray.origin, ray.direction), distanceThroughAtmosphere - EPSILON * 2.0, originalColor);\n\n\t\toutColor = vec4(light, 1.0);\n\t} else {\n\t\toutColor = vec4(originalColor, 1.0);\n\t}*/\n\n\t/*if (distanceThroughAtmosphere != INFINITY)\n\t\toriginalColor *= 0.6;\n\n\toutColor = vec4(originalColor, 1.0);*/\n\t\n\t//outColor = vec4(dir / 2.0 + vec3(0.5), 1.0);\n\n\tvec2 iMouse = uScreen.dimension / 2.0;\n\tvec2 position = gl_FragCoord.xy / max(uScreen.dimension.x, uScreen.dimension.y) * 2.0;\n\tvec2 lightPosition = iMouse.xy / uScreen.dimension.xy * 2.0 + ((iMouse.x + iMouse.y) == 0.0 ? vec2(1.0, 0.4) : vec2(0.0));\n\n\tvec3 color = originalColor*getAtmosphericScattering(position, lightPosition) * pi;\n\tcolor = jodieReinhardTonemap(color);\n\tcolor = pow(color, vec3(2.2)); //Back to linear\n\n\toutColor = vec4(color, 1.0);\n}"
  },
  {
    "path": "res/shaders/skybox.shader",
    "content": "[common]\n\n#version 330 core\n\n//------------------------------------------------------------------------------//\n\n[vertex]\n\nlayout (location = 0) in vec3 vposition;\n\nout vec3 ftextureUV;\n\nuniform mat4 projectionMatrix;\nuniform mat4 viewMatrix;\nuniform vec3 viewPosition;\nuniform vec3 lightDirection;\n\nconst float PI = 3.141592654;\nconst vec4 Esun = vec4(1.0, 1.0, 1.0, 12.0);\nconst float g = 5.2;\n\nfloat density(float h) {\n\tfloat H = 8500;\n\treturn exp(-h / H);\n}\n\nvec3 Bm(float h) {\n\tvec3 cBm = vec3(4e-6, 6e-6, 2.4e-6);\n\treturn cBm;\n}\n\nvec3 Br(float h) {\n\tvec3 cBr = vec3(0.00000519673, 0.0000121427, 0.0000296453);\n\treturn density(h) * cBr;\n}\n\nvec3 rayleigh(float h, float cosphi) {\n\tfloat phase = 1.0 + cosphi * cosphi;\n\treturn 3.0 / 16.0 / PI * Br(h) * phase;\n}\n\nvec3 mie(float h, float cosphi) {\n\tfloat phase = pow(1.0 - g, 2.0) / pow(1.0 + g * g - 2.0 * g * cosphi, 1.5);\n\treturn 1.0 / 4.0 / PI * Bm(h) * phase;\n}\n\nvec3 Fex(float h, float s) {\n\treturn exp(-(Br(h) + Bm(h)) * s);\n}\n\nvec3 scatter(float h, float s, float cosphi) {\n\treturn (rayleigh(h, cosphi) + mie(h, cosphi)) / (Br(h) + Bm(h)) * Esun.w * (1.0 - Fex(h, s));\n}\n\nvoid main() {\n\tvec4 position = projectionMatrix * vec4((viewMatrix * vec4(vposition, 0.0)).xyz, 1.0);\n\tvec3 light = lightDirection;\n\tvec3 normal = vposition;\n\n\t/*float distance = (1.05 - pow(normal.y, 0.2)) * 150000;\n\tfloat cosphi = dot(normal, light) / length(light) / length(normal);\n\tfloat h = position.y;\n\tscattering = scatter(h, distance, cosphi);\n\textinction = Fex(h, distance);*/\n\n\tftextureUV = vposition;\n\tgl_Position = position;\n}\n\n//------------------------------------------------------------------------------//\n\n[fragment]\n\nout vec4 outColor;\n\nin vec3 ftextureUV;\n\nuniform samplerCube skyboxTexture;\n\nvoid main() {    \n\tvec4 skybox = texture(skyboxTexture, ftextureUV);\n\toutColor = skybox;\n}"
  },
  {
    "path": "res/shaders/test.shader",
    "content": "[common]\n\n#version 410 core\n\n//------------------------------------------------------------------------------//\n\n[vertex]\n\nlayout(location = 0) in vec3 vposition;\nlayout(location = 1) in vec3 vnormal;\nlayout(location = 2) in vec2 vUV;\n\nuniform mat4 modelMatrix;\n\nout vec3 tcposition;\nout vec3 tcnormal;\nout vec2 tcUV;\n\nvoid main() {\n\ttcposition = (modelMatrix * vec4(vposition, 1.0)).xyz;\n\ttcnormal = (modelMatrix * vec4(vnormal, 0.0)).xyz;\n\ttcUV = vUV;\n}\n\n//------------------------------------------------------------------------------//\n\n[tesselation control]\n\n// define the number of CPs in the output patch                                                 \nlayout(vertices = 4) out;\n\nuniform vec3 viewPosition;\n\n// attributes of the input CPs                                                                  \nin vec3 tcposition[];\nin vec3 tcnormal[];\nin vec2 tcUV[];\n\n// attributes of the output CPs                                                                 \nout vec3 teposition[];\nout vec3 tenormal[];\nout vec2 teUV[];\n\nvoid main() {\n\t// Set the control points of the output patch                                               \n\tteposition[gl_InvocationID] = tcposition[gl_InvocationID];\n\ttenormal[gl_InvocationID] = tcnormal[gl_InvocationID];\n\tteUV[gl_InvocationID] = tcUV[gl_InvocationID];\n\n\t// Calculate the distance from the camera to the three control points \n\tif (gl_InvocationID == 0) {\n\t\tgl_TessLevelInner[0] = 5.0;\n\t\tgl_TessLevelInner[1] = 5.0;\n\t\tgl_TessLevelOuter[0] = 5.0;\n\t\tgl_TessLevelOuter[1] = 5.0;\n\t\tgl_TessLevelOuter[2] = 5.0;\n\t\tgl_TessLevelOuter[3] = 5.0;\n\t}\n}\n\n//------------------------------------------------------------------------------//\n\n[tesselation evaluate]\n\nlayout(quads, equal_spacing, ccw) in;\n\nuniform mat4 viewMatrix;\nuniform mat4 projectionMatrix;\n\nuniform sampler2D displacementMap;\n//uniform float gDispFactor;\n\nin vec3 teposition[];\nin vec3 tenormal[];\nin vec2 teUV[];\n\nout vec3 fposition;\nout vec3 fnormal;\nout vec2 fUV;\n\nvec2 interpolate(vec2 v0, vec2 v1, vec2 v2, vec2 v3) {\n\t// interpolate in horizontal direction between vert. 0 and 3\n\tvec2 p0 = mix(v0, v3, gl_TessCoord.x);\n\t// interpolate in horizontal direction between vert. 1 and 2\n\tvec2 p1 = mix(v1, v2, gl_TessCoord.x);\n\n\t// interpolate in vertical direction\n\tvec2 p = mix(p0, p1, gl_TessCoord.y);\n\n\treturn p;\n}\n\nvec3 interpolate(vec3 v0, vec3 v1, vec3 v2, vec3 v3) {\n\t// interpolate in horizontal direction between vert. 0 and 3\n\tvec3 p0 = mix(v3, v0, gl_TessCoord.x);\n\t// interpolate in horizontal direction between vert. 1 and 2\n\tvec3 p1 = mix(v2, v1, gl_TessCoord.x);\n\n\t// interpolate in vertical direction\n\tvec3 p = mix(p0, p1, gl_TessCoord.y);\n\n\treturn p;\n}\n\nvoid main() {\n\t// Interpolate the attributes of the output vertex using the barycentric coordinates        \n\tfposition = (interpolate(teposition[0], teposition[1], teposition[2], teposition[3]));\n\tfnormal = normalize(interpolate(tenormal[0], tenormal[1], tenormal[2], tenormal[3]));\n\tfUV = interpolate(teUV[0], teUV[1], teUV[2], teUV[3]);\n\n\t//fposition += fnormal * length(gl_TessCoord.xy);\n\n\tgl_Position = projectionMatrix * viewMatrix * vec4(fposition, 1.0);\n}\n\n//------------------------------------------------------------------------------//\n\n[fragment]\n\nin vec3 fposition;\nin vec3 fnormal;\nin vec2 fUV;\n\nout vec4 outColor;\n\nvoid main() {\n\tfposition;\n\tfnormal;\n\tfUV;\n\n\tvec3 color = vec3(1);\n\toutColor = vec4(color, 1);\n}  "
  },
  {
    "path": "res/shaders/vector.shader",
    "content": "[common]\n\n#version 330 core\n\n//------------------------------------------------------------------------------//\n\n[vertex]\n\nlayout(location = 0) in vec3 vposition; \nlayout(location = 1) in vec3 vrotation;\nlayout(location = 2) in vec3 vcolor;\n\nout vec3 grotation;\nout vec3 gcolor;\n\nvoid main() { \n\tgcolor = vcolor;\n\tgrotation = vrotation;\n\tgl_Position = vec4(vposition, 1);\n}\n\n//------------------------------------------------------------------------------//\n[geometry]\n\nlayout(points) in;\nlayout(line_strip, max_vertices = 6) out;\n\nin vec3 grotation[];\nin vec3 gcolor[];\n\nout vec3 fcolor;\n\nuniform mat4 viewMatrix;\nuniform mat4 projectionMatrix;\nuniform vec3 viewPosition;\n\nvoid main() {\n\tfloat arrowLength = 0.1;\n\tfloat arrowWidth = 0.025;\n\tvec4 origin = gl_in[0].gl_Position;\n\tvec4 arrowTop = gl_in[0].gl_Position + vec4(grotation[0], 0);\n\tvec3 norm = normalize(cross(arrowTop.xyz - viewPosition, grotation[0]));\n\tvec3 unitRotation = normalize(grotation[0]);\n\tvec4 arrowLeft = arrowTop - vec4(arrowLength * unitRotation - arrowWidth * norm, 0);\n\tvec4 arrowRight = arrowTop - vec4(arrowLength * unitRotation + arrowWidth * norm, 0);\n\tvec4 arrowBase = arrowTop - arrowLength * vec4(unitRotation, 0);\n\n\tfcolor = gcolor[0];\n\n\tgl_Position = projectionMatrix * viewMatrix * origin;\n\tEmitVertex();\n\n\tgl_Position = projectionMatrix * viewMatrix * arrowBase;\n\tEmitVertex();\n\n\tgl_Position = projectionMatrix * viewMatrix * arrowLeft;\n\tEmitVertex();\n\n\tgl_Position = projectionMatrix * viewMatrix * arrowTop;\n\tEmitVertex();\n\n\tgl_Position = projectionMatrix * viewMatrix * arrowRight;\n\tEmitVertex();\n\n\tgl_Position = projectionMatrix * viewMatrix * arrowBase;\n\tEmitVertex();\n\n\tEndPrimitive();\n}\n\n//------------------------------------------------------------------------------//\n\n[fragment]\n\nlayout(location = 0) out vec4 outColor;\n\nin vec3 fcolor;\n\nvoid main() {\n\toutColor = vec4(fcolor, 1);\n}"
  },
  {
    "path": "tests/boundsTree2Tests.cpp",
    "content": "#include \"testsMain.h\"\n\n#include <Physics3D/boundstree/boundsTree.h>\n\n#include \"testsMain.h\"\n\n#include \"compare.h\"\n#include \"generators.h\"\n#include <Physics3D/misc/toString.h>\n#include <Physics3D/misc/validityHelper.h>\n\n#include <vector>\n#include <set>\n\nusing namespace P3D;\n\nstatic void shuffleTreeRecursive(TreeTrunk& curTrunk, int curTrunkSize) {\n\tfor(int iter = 0; iter < (curTrunkSize - 1) * curTrunkSize; iter++) {\n\t\tint index1 = generateInt(curTrunkSize);\n\t\tint index2;\n\t\tdo {\n\t\t\tindex2 = generateInt(curTrunkSize);\n\t\t} while(index1 == index2);\n\n\t\tBoundsTemplate<float> tmpBounds = curTrunk.getBoundsOfSubNode(index1);\n\t\tTreeNodeRef tmpNode = std::move(curTrunk.subNodes[index1]);\n\n\t\tcurTrunk.setSubNode(index1, std::move(curTrunk.subNodes[index2]), curTrunk.getBoundsOfSubNode(index2));\n\t\tcurTrunk.setSubNode(index2, std::move(tmpNode), tmpBounds);\n\t}\n\n\tfor(int i = 0; i < curTrunkSize; i++) {\n\t\tTreeNodeRef& subNode = curTrunk.subNodes[i];\n\t\tif(subNode.isTrunkNode()) {\n\t\t\tshuffleTreeRecursive(subNode.asTrunk(), subNode.getTrunkSize());\n\t\t}\n\t}\n}\nstatic void shuffleTree(BoundsTreePrototype& tree) {\n\tstd::pair<TreeTrunk&, int> baseTrunk = tree.getBaseTrunk();\n\tshuffleTreeRecursive(baseTrunk.first, baseTrunk.second);\n}\ntemplate<typename Boundable>\nstatic void shuffleTree(BoundsTree<Boundable>& tree) {\n\tshuffleTree(tree.getPrototype());\n}\n\nstatic BoundsTemplate<float> generateBoundsTreeBounds() {\n\tfloat x = generateFloat(-100.0f, 100.0f);\n\tfloat y = generateFloat(-100.0f, 100.0f);\n\tfloat z = generateFloat(-100.0f, 100.0f);\n\n\tfloat w = generateFloat(0.2f, 50.0f);\n\tfloat h = generateFloat(0.2f, 50.0f);\n\tfloat d = generateFloat(0.2f, 50.0f);\n\n\treturn BoundsTemplate<float>(PositionTemplate<float>(x - w, y - h, z - d), PositionTemplate<float>(x + w, y + h, z + d));\n}\n\nstatic std::vector<BasicBounded> generateBoundsTreeItems(int size) {\n\tstd::vector<BasicBounded> allItems;\n\n\tfor(int i = 0; i < size; i++) {\n\t\tallItems.push_back(BasicBounded{generateBoundsTreeBounds()});\n\t}\n\n\treturn allItems;\n}\n\nTEST_CASE(testAddRemoveToBoundsTree) {\n\tBoundsTree<BasicBounded> tree;\n\tASSERT_TRUE(isBoundsTreeValid(tree));\n\n\tconstexpr int itemCount = 1000;\n\n\tstd::vector<BasicBounded> itemsInTree = generateBoundsTreeItems(itemCount);\n\n\t// add all to tree\n\tfor(int i = 0; i < itemCount; i++) {\n\t\tBasicBounded& cur = itemsInTree[i];\n\t\tASSERT_FALSE(tree.contains(&cur));\n\t\ttree.add(&cur);\n\t\tASSERT_TRUE(tree.contains(&cur));\n\t}\n\tASSERT_TRUE(isBoundsTreeValid(tree));\n\t// assert all in tree\n\tfor(int i = 0; i < itemCount; i++) {\n\t\tBasicBounded& cur = itemsInTree[i];\n\t\tASSERT_TRUE(tree.contains(&cur));\n\t}\n\tASSERT_TRUE(isBoundsTreeValid(tree));\n\t// remove all from tree\n\tfor(int i = 0; i < itemCount; i++) {\n\t\tBasicBounded& cur = itemsInTree[i];\n\t\tASSERT_TRUE(tree.contains(&cur));\n\t\ttree.remove(&cur);\n\t\tASSERT_FALSE(tree.contains(&cur));\n\t}\n\tASSERT_TRUE(isBoundsTreeValid(tree));\n\t// assert all removed from tree\n\tfor(int i = 0; i < itemCount; i++) {\n\t\tBasicBounded& cur = itemsInTree[i];\n\t\tASSERT_FALSE(tree.contains(&cur));\n\t}\n\tASSERT_TRUE(isBoundsTreeValid(tree));\n}\n\n// check all groups are distinct, but internally the same\nstatic bool groupsMatchTree(const std::vector<std::vector<BasicBounded*>>& groups, const BoundsTree<BasicBounded>& tree) {\n\tfor(const std::vector<BasicBounded*>& groupA : groups) {\n\t\tfor(const std::vector<BasicBounded*>& groupB : groups) {\n\t\t\tbool isSameGroup = &groupA == &groupB;\n\t\t\tfor(const BasicBounded* objA : groupA) {\n\t\t\t\tfor(const BasicBounded* objB : groupB) {\n\t\t\t\t\tif(tree.groupContains(objA, objB) != isSameGroup) {\n\t\t\t\t\t\tstd::cout << (isSameGroup ? \"Objects should be in same group but aren't!\" : \"Objects shouldn't be in same group but are!\");\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t// verify that all groups in the tree match a group in the lists\n\tbool result = true;\n\ttree.forEach([&](const BasicBounded& obj) {\n\t\tsize_t groupSize = tree.groupSize(&obj);\n\n\t\tfor(const std::vector<BasicBounded*>& g : groups) {\n\t\t\tfor(BasicBounded* item : g) {\n\t\t\t\tif(&obj == item) {\n\t\t\t\t\tif(groupSize != g.size()) {\n\t\t\t\t\t\tstd::cout << \"Tree item's group not same size as in groups list!\\n\";\n\t\t\t\t\t\tresult = false;\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tstd::cout << \"Tree item's group not in groups list!\\n\";\n\t\tresult = false;\n\t});\n\treturn result;\n}\n\nstatic void mergeGroups(std::vector<std::vector<BasicBounded*>>& groups, BoundsTree<BasicBounded>& tree, int groupA, int groupB) {\n\tBasicBounded* objA = groups[groupA][0];\n\tBasicBounded* objB = groups[groupB][0];\n\ttree.mergeGroups(objA, objB);\n\tgroups[groupA].insert(groups[groupA].end(), groups[groupB].begin(), groups[groupB].end());\n\tgroups[groupB] = std::move(groups.back());\n\tgroups.pop_back();\n}\n\nTEST_CASE(testBoundsTreeGroupCreation) {\n\tBoundsTree<BasicBounded> tree;\n\tASSERT_TRUE(isBoundsTreeValid(tree));\n\n\tconstexpr int itemCount = 50;\n\t//constexpr int itemCount = 20;\n\n\tstd::vector<BasicBounded> allItems = generateBoundsTreeItems(itemCount);\n\n\tstd::vector<std::vector<BasicBounded*>> groups;\n\n\tASSERT_TRUE(isBoundsTreeValid(tree));\n\n\tfor(int i = 0; i < itemCount; i++) {\n\t\tBasicBounded* newObj = &allItems[i];\n\t\tint groupToAddTo = generateInt(groups.size() + 1) - 1;\n\t\tif(groupToAddTo == -1) {\n\t\t\tstd::vector<BasicBounded*> newGroup{newObj};\n\t\t\tgroups.push_back(std::move(newGroup));\n\t\t\ttree.add(newObj);\n\t\t} else {\n\t\t\tstd::vector<BasicBounded*>& grp = groups[groupToAddTo];\n\t\t\tgrp.push_back(newObj);\n\t\t\tBasicBounded* grpRep = grp[0];\n\t\t\ttree.addToGroup(newObj, grpRep);\n\t\t\tASSERT_TRUE(tree.groupContains(newObj, grpRep));\n\t\t}\n\t\tASSERT_TRUE(isBoundsTreeValid(tree));\n\t}\n\n\tASSERT_TRUE(groupsMatchTree(groups, tree));\n\tASSERT_TRUE(isBoundsTreeValid(tree));\n}\n\nstatic std::vector<std::vector<BasicBounded*>> createGroups(BoundsTree<BasicBounded>& tree, std::vector<BasicBounded>& allItems) {\n\tassert(tree.isEmpty());\n\n\tstd::vector<std::vector<BasicBounded*>> groups;\n\n\t// add to groups\n\tfor(int i = 0; i < allItems.size() / 2; i++) {\n\t\tBasicBounded* newObj = &allItems[i];\n\t\tint groupToAddTo = generateInt(groups.size() + 1) - 1;\n\t\tif(groupToAddTo == -1) {\n\t\t\tstd::vector<BasicBounded*> newGroup{newObj};\n\t\t\tgroups.push_back(std::move(newGroup));\n\t\t\ttree.add(newObj);\n\t\t} else {\n\t\t\tstd::vector<BasicBounded*>& grp = groups[groupToAddTo];\n\t\t\tgrp.push_back(newObj);\n\t\t\tBasicBounded* grpRep = grp[0];\n\t\t\ttree.addToGroup(newObj, grpRep);\n\t\t}\n\t}\n\n\t// also add some loose objects\n\tfor(int i = allItems.size() / 2; i < allItems.size(); i++) {\n\t\tBasicBounded* newObj = &allItems[i];\n\t\tstd::vector<BasicBounded*> newGroup{newObj};\n\t\tgroups.push_back(std::move(newGroup));\n\t\ttree.add(newObj);\n\t}\n\n\tshuffleTree(tree);\n\n\treturn groups;\n}\n\nTEST_CASE(testBoundsTreeGroupMerging) {\n\tBoundsTree<BasicBounded> tree;\n\tASSERT_TRUE(isBoundsTreeValid(tree));\n\n\tconstexpr int itemCount = 50;\n\t//constexpr int itemCount = 20;\n\n\tstd::vector<BasicBounded> allItems = generateBoundsTreeItems(itemCount);\n\n\tstd::vector<std::vector<BasicBounded*>> groups = createGroups(tree, allItems);\n\n\tASSERT_TRUE(groupsMatchTree(groups, tree));\n\tASSERT_TRUE(isBoundsTreeValid(tree));\n\n\twhile(groups.size() > 1) {\n\t\tint mergeIdxA = generateInt(groups.size());\n\t\tint mergeIdxB;\n\t\tdo {\n\t\t\tmergeIdxB = generateInt(groups.size());\n\t\t} while(mergeIdxA == mergeIdxB);\n\n\t\tmergeGroups(groups, tree, mergeIdxA, mergeIdxB);\n\t\tASSERT_TRUE(isBoundsTreeValid(tree));\n\t\tASSERT_TRUE(groupsMatchTree(groups, tree));\n\t}\n}\n\nTEST_CASE_SLOW(testBoundsTreeGroupMergingSplitting) {\n\tstd::vector<int> itemCounts{5, 15, 30, 50};\n\tfor(int& itemCount : itemCounts) {\n\t\t//printf(\"\\n\");\n\t\tBoundsTree<BasicBounded> tree;\n\t\tASSERT_TRUE(isBoundsTreeValid(tree));\n\n\t\tstd::vector<BasicBounded> allItems = generateBoundsTreeItems(itemCount);\n\n\t\tstd::vector<std::vector<BasicBounded*>> groups;\n\n\t\ttree.add(&allItems[0]);\n\t\tASSERT_TRUE(isBoundsTreeValid(tree));\n\t\tgroups.push_back(std::vector<BasicBounded*>{&allItems[0]});\n\t\tfor(int i = 1; i < itemCount; i++) {\n\t\t\tBasicBounded* newObj = &allItems[i];\n\t\t\tstd::vector<BasicBounded*>& grp = groups[0];\n\t\t\tgrp.push_back(newObj);\n\t\t\tBasicBounded* grpRep = grp[0];\n\t\t\ttree.addToGroup(newObj, grpRep);\n\t\t\tASSERT_TRUE(tree.groupContains(newObj, grpRep));\n\t\t\tASSERT_TRUE(isBoundsTreeValid(tree));\n\t\t}\n\n\t\t//printf(\"groups.size() = %d   groups[0].size() = %d\\n\", (int) groups.size(), (int) groups[0].size());\n\n\t\tASSERT_TRUE(groupsMatchTree(groups, tree));\n\n\t\t// do a whole bunch of splits and merges\n\t\tfor(int iter = 0; iter < 1000; iter++) {\n\t\t\tint group = generateInt(groups.size());\n\t\t\tbool split = generateBool() || groups.size() == 1;\n\n\t\t\tif(split) {\n\t\t\t\tstd::vector<BasicBounded*>& grp = groups[group];\n\t\t\t\tsize_t originalSize = grp.size();\n\t\t\t\tstd::vector<BasicBounded*> newGroup;\n\n\t\t\t\t// remove a subset of the elements from the group\n\t\t\t\tfor(size_t i = 0; i < grp.size(); ) {\n\t\t\t\t\tif(generateBool()) {\n\t\t\t\t\t\tnewGroup.push_back(grp[i]);\n\t\t\t\t\t\tgrp[i] = grp.back();\n\t\t\t\t\t\tgrp.pop_back();\n\t\t\t\t\t} else {\n\t\t\t\t\t\ti++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tint newGroupSize = newGroup.size();\n\t\t\t\tint leftoverSize = grp.size();\n\t\t\t\t//printf(\"Split group %d into size %d-%d/%d\\n\", group, newGroupSize, leftoverSize, (int) originalSize);\n\t\t\t\ttree.splitGroup(newGroup.begin(), newGroup.end());\n\t\t\t\tif(grp.size() == 0) {\n\t\t\t\t\tgrp = std::move(newGroup);\n\t\t\t\t} else {\n\t\t\t\t\tif(newGroupSize > 0) {\n\t\t\t\t\t\tgroups.push_back(std::move(newGroup));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else { // merge\n\t\t\t\tint group2;\n\t\t\t\tdo {\n\t\t\t\t\tgroup2 = generateInt(groups.size());\n\t\t\t\t} while(group == group2);\n\n\t\t\t\t//printf(\"Merged groups %d, %d\\n\", group, group2);\n\t\t\t\tmergeGroups(groups, tree, group, group2);\n\t\t\t}\n\n\t\t\tASSERT_TRUE(isBoundsTreeValid(tree));\n\t\t\tASSERT_TRUE(groupsMatchTree(groups, tree));\n\t\t}\n\t}\n}\n\nTEST_CASE(testForEachColission) {\n\tBoundsTree<BasicBounded> tree;\n\n\tconstexpr int itemCount = 100;\n\n\tstd::vector<BasicBounded> allItems = generateBoundsTreeItems(itemCount);\n\n\tstd::vector<std::vector<BasicBounded*>> groups = createGroups(tree, allItems);\n\n\tstd::set<std::pair<BasicBounded*, BasicBounded*>> foundColissions;\n\n\tASSERT_TRUE(isBoundsTreeValid(tree));\n\n\ttree.forEachColission([&](BasicBounded* a, BasicBounded* b) {\n\t\tASSERT_STRICT(a != b);\n\t\tif(b < a) std::swap(a, b);\n\t\tstd::pair<BasicBounded*, BasicBounded*> col(a, b);\n\t\tASSERT_FALSE(foundColissions.find(col) != foundColissions.end()); // no duplicate colissions\n\t\tfoundColissions.insert(col);\n\t});\n\n\tfor(size_t i = 0; i < groups.size(); i++) {\n\t\tstd::vector<BasicBounded*>& grp = groups[i];\n\n\t\tfor(size_t aIndex = 0; aIndex < grp.size(); aIndex++) {\n\t\t\tBasicBounded* a = grp[aIndex];\n\t\t\tfor(size_t bIndex = aIndex + 1; bIndex < grp.size(); bIndex++) {\n\t\t\t\tBasicBounded* b = grp[bIndex];\n\t\t\t\tif(a > b) std::swap(a, b);\n\t\t\t\tstd::pair<BasicBounded*, BasicBounded*> col(a, b);\n\n\t\t\t\tASSERT_FALSE(foundColissions.find(col) != foundColissions.end());\n\t\t\t}\n\t\t}\n\t}\n\n\tfor(size_t i = 0; i < groups.size(); i++) {\n\t\tstd::vector<BasicBounded*>& groupA = groups[i];\n\n\t\tfor(size_t j = i + 1; j < groups.size(); j++) {\n\t\t\tstd::vector<BasicBounded*>& groupB = groups[j];\n\n\t\t\tfor(int ai = 0; ai < groupA.size(); ai++) {\n\t\t\t\tfor(int bi = 0; bi < groupB.size(); bi++) {\n\t\t\t\t\tBasicBounded* a = groupA[ai];\n\t\t\t\t\tBasicBounded* b = groupB[bi];\n\t\t\t\t\tif(a > b) std::swap(a, b);\n\t\t\t\t\tstd::pair<BasicBounded*, BasicBounded*> col(a, b);\n\n\t\t\t\t\tbool wasFound = foundColissions.find(col) != foundColissions.end();\n\n\t\t\t\t\tbool shouldBeFound = intersects(a->bounds, b->bounds);\n\n\t\t\t\t\tASSERT_STRICT(wasFound == shouldBeFound);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nTEST_CASE(testForEachColissionBetween) {\n\tBoundsTree<BasicBounded> tree1;\n\tBoundsTree<BasicBounded> tree2;\n\n\tconstexpr int itemCount = 100;\n\n\tstd::vector<BasicBounded> allItems1 = generateBoundsTreeItems(itemCount);\n\tstd::vector<BasicBounded> allItems2 = generateBoundsTreeItems(itemCount);\n\n\tstd::vector<std::vector<BasicBounded*>> groups1 = createGroups(tree1, allItems1);\n\tstd::vector<std::vector<BasicBounded*>> groups2 = createGroups(tree2, allItems2);\n\n\tstd::set<std::pair<BasicBounded*, BasicBounded*>> foundColissions;\n\n\ttree1.forEachColissionWith(tree2, [&](BasicBounded* a, BasicBounded* b) {\n\t\tstd::pair<BasicBounded*, BasicBounded*> col(a, b);\n\t\tASSERT_FALSE(foundColissions.find(col) != foundColissions.end()); // no duplicate colissions\n\t\tfoundColissions.insert(col);\n\t});\n\n\tfor(size_t i = 0; i < groups1.size(); i++) {\n\t\tstd::vector<BasicBounded*>& groupA = groups1[i];\n\n\t\tfor(size_t j = i + 1; j < groups2.size(); j++) {\n\t\t\tstd::vector<BasicBounded*>& groupB = groups2[i];\n\n\t\t\tfor(BasicBounded* a : groupA) {\n\t\t\t\tfor(BasicBounded* b : groupB) {\n\t\t\t\t\tstd::pair<BasicBounded*, BasicBounded*> col(a, b);\n\n\t\t\t\t\tbool wasFound = foundColissions.find(col) != foundColissions.end();\n\n\t\t\t\t\tbool shouldBeFound = intersects(a->bounds, b->bounds);\n\n\t\t\t\t\tASSERT_STRICT(wasFound == shouldBeFound);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nTEST_CASE(testUpdatePartBounds) {\n\tBoundsTree<BasicBounded> tree;\n\n\tconstexpr int itemCount = 100;\n\n\tstd::vector<BasicBounded> allItems = generateBoundsTreeItems(itemCount);\n\n\tstd::vector<std::vector<BasicBounded*>> groups = createGroups(tree, allItems);\n\n\tASSERT_TRUE(isBoundsTreeValid(tree));\n\n\tfor(int iter = 0; iter < 500; iter++) {\n\t\tBasicBounded& selectedItem = allItems[generateSize_t(allItems.size())];\n\t\tBoundsTemplate<float> oldBounds = selectedItem.getBounds();\n\t\tselectedItem.bounds = generateBoundsTreeBounds();\n\n\t\ttree.updateObjectBounds(&selectedItem, oldBounds);\n\t\tASSERT_TRUE(tree.contains(&selectedItem));\n\t\tASSERT_TRUE(isBoundsTreeValid(tree));\n\t}\n}\n\nTEST_CASE(testUpdateGroupBounds) {\n\tBoundsTree<BasicBounded> tree;\n\n\tconstexpr int itemCount = 10;\n\n\tstd::vector<BasicBounded> allItems = generateBoundsTreeItems(itemCount);\n\n\tstd::vector<std::vector<BasicBounded*>> groups = createGroups(tree, allItems);\n\n\tASSERT_TRUE(isBoundsTreeValid(tree));\n\n\tfor(int iter = 0; iter < 500; iter++) {\n\t\tstd::vector<BasicBounded*>& selectedGroup = groups[generateSize_t(groups.size())];\n\t\tsize_t selectedGroupSize = selectedGroup.size();\n\t\tBasicBounded& selectedItem = *selectedGroup[generateSize_t(selectedGroupSize)];\n\t\tBoundsTemplate<float> oldBounds = selectedItem.getBounds();\n\t\tfor(BasicBounded* item : selectedGroup) {\n\t\t\titem->bounds = generateBoundsTreeBounds();\n\t\t}\n\n\t\ttree.updateObjectGroupBounds(&selectedItem, oldBounds);\n\t\tASSERT_TRUE(tree.contains(&selectedItem));\n\t\tASSERT_TRUE(isBoundsTreeValid(tree));\n\t}\n}\n\nTEST_CASE(testImproveStructureValidity) {\n\tBoundsTree<BasicBounded> tree;\n\n\tconstexpr int itemCount = 100;\n\n\tstd::vector<BasicBounded> allItems = generateBoundsTreeItems(itemCount);\n\n\tstd::vector<std::vector<BasicBounded*>> groups = createGroups(tree, allItems);\n\n\tASSERT_TRUE(groupsMatchTree(groups, tree));\n\tASSERT_TRUE(isBoundsTreeValid(tree));\n\n\tfor(int iter = 0; iter < 10; iter++) {\n\t\tfor(BasicBounded& bb : allItems) {\n\t\t\tbb.bounds = generateBoundsTreeBounds();\n\t\t}\n\t\ttree.recalculateBounds();\n\n\t\tASSERT_TRUE(groupsMatchTree(groups, tree));\n\t\tASSERT_TRUE(isBoundsTreeValid(tree));\n\n\t\tfor(int i = 0; i < 5; i++) {\n\t\t\ttree.improveStructure();\n\t\t\tASSERT_TRUE(groupsMatchTree(groups, tree));\n\t\t\tASSERT_TRUE(isBoundsTreeValid(tree));\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "tests/compare.h",
    "content": "#pragma once\n\n#include <Physics3D/math/linalg/vec.h>\n#include <Physics3D/math/linalg/largeMatrix.h>\n#include <Physics3D/math/linalg/mat.h>\n#include <Physics3D/math/linalg/eigen.h>\n#include <Physics3D/math/cframe.h>\n#include <Physics3D/math/position.h>\n#include <Physics3D/math/globalCFrame.h>\n#include <Physics3D/math/taylorExpansion.h>\n#include <Physics3D/math/boundingBox.h>\n\n#include <Physics3D/motion.h>\n#include <Physics3D/relativeMotion.h>\n\n#include <utility>\n#include <array>\n#include <vector>\n#include <type_traits>\n\n#define IS_SUBCLASS_OF(Child, BaseClass) typename std::enable_if<std::is_base_of<BaseClass, Child>::value>::type* = nullptr\n#define IS_ARITHMETIC(Type) typename std::enable_if<std::is_arithmetic<Type>::value>::type* = nullptr\n\ntemplate<typename Num1, typename Num2, typename Tol, IS_ARITHMETIC(Num1), IS_ARITHMETIC(Num2)>\nbool tolerantEquals(const Num1& first, const Num2& second, Tol tolerance) {\n\tauto diff = first - second;\n\treturn diff <= tolerance && -diff <= tolerance;\n}\n\ntemplate<typename Num1, typename Num2, typename Tol, IS_ARITHMETIC(Num1), IS_ARITHMETIC(Num2)>\nbool tolerantNotEquals(const Num1& first, const Num2& second, Tol tolerance) {\n\tauto diff = first - second;\n\treturn diff > tolerance && -diff > tolerance;\n}\n\ntemplate<typename Num1, typename Num2, typename Tol, IS_ARITHMETIC(Num1), IS_ARITHMETIC(Num2)>\nbool tolerantLessThan(const Num1& first, const Num2& second, Tol tolerance) {\n\treturn first < second + tolerance;\n}\n\ntemplate<typename Num1, typename Num2, typename Tol, IS_ARITHMETIC(Num1), IS_ARITHMETIC(Num2)>\nbool tolerantGreaterThan(const Num1& first, const Num2& second, Tol tolerance) {\n\treturn first + tolerance > second;\n}\n\ntemplate<typename Num1, typename Num2, typename Tol, IS_ARITHMETIC(Num1), IS_ARITHMETIC(Num2)>\nbool tolerantLessOrEqual(const Num1& first, const Num2& second, Tol tolerance) {\n\treturn first <= second + tolerance;\n}\n\ntemplate<typename Num1, typename Num2, typename Tol, IS_ARITHMETIC(Num1), IS_ARITHMETIC(Num2)>\nbool tolerantGreaterOrEqual(const Num1& first, const Num2& second, Tol tolerance) {\n\treturn first + tolerance >= second;\n}\n\ntemplate<typename Num1, typename Num2, typename Tol, size_t Size>\nbool tolerantEquals(const P3D::Vector<Num1, Size>& first, const P3D::Vector<Num2, Size>& second, Tol tolerance) {\n\tfor(size_t i = 0; i < Size; i++) {\n\t\tif(!tolerantEquals(first[i], second[i], tolerance)) return false;\n\t}\n\treturn true;\n}\ntemplate<typename Num1, typename Num2, typename Tol>\nbool tolerantEquals(const P3D::LargeVector<Num1>& first, const P3D::LargeVector<Num2>& second, Tol tolerance) {\n\tif(first.n != second.n) throw \"Dimensions must match!\";\n\tfor(size_t i = 0; i < first.n; i++) {\n\t\tif(!tolerantEquals(first[i], second[i], tolerance)) return false;\n\t}\n\treturn true;\n}\ntemplate<typename Num1, typename Num2, typename Tol, size_t Width, size_t Height>\nbool tolerantEquals(const P3D::Matrix<Num1, Height, Width>& first, const P3D::Matrix<Num2, Height, Width>& second, Tol tolerance) {\n\tfor(size_t row = 0; row < Height; row++)\n\t\tfor(size_t col = 0; col < Width; col++)\n\t\t\tif(!tolerantEquals(first(row, col), second(row, col), tolerance))\n\t\t\t\treturn false;\n\n\treturn true;\n}\n\ntemplate<typename Num1, typename Num2, typename Tol, size_t Size>\nbool tolerantEquals(const P3D::SymmetricMatrix<Num1, Size>& first, const P3D::SymmetricMatrix<Num2, Size>& second, Tol tolerance) {\n\tfor(size_t row = 0; row < Size; row++)\n\t\tfor(size_t col = 0; col < Size; col++)\n\t\t\tif(!tolerantEquals(first(row, col), second(row, col), tolerance))\n\t\t\t\treturn false;\n\n\treturn true;\n}\n\ntemplate<typename Num1, typename Num2, typename Tol, size_t Size>\nbool tolerantEquals(const P3D::DiagonalMatrix<Num1, Size>& first, const P3D::DiagonalMatrix<Num2, Size>& second, Tol tolerance) {\n\tfor(size_t i = 0; i < Size; i++)\n\t\tif(!tolerantEquals(first[i], second[i], tolerance))\n\t\t\treturn false;\n\n\treturn true;\n}\n\ntemplate<typename Num1, typename Num2, typename Tol>\nbool tolerantEquals(const P3D::LargeMatrix<Num1>& first, const P3D::LargeMatrix<Num2>& second, Tol tolerance) {\n\tif(first.w != second.w || first.h != second.h) throw \"Dimensions must match!\";\n\tfor(size_t row = 0; row < first.h; row++)\n\t\tfor(size_t col = 0; col < first.w; col++)\n\t\t\tif(!tolerantEquals(first.get(row, col), second.get(row, col), tolerance))\n\t\t\t\treturn false;\n\n\treturn true;\n}\n\ntemplate<typename Num1, typename Num2, typename Tol>\nbool tolerantEquals(const P3D::LargeSymmetricMatrix<Num1>& first, const P3D::LargeSymmetricMatrix<Num2>& second, Tol tolerance) {\n\tif(first.size != second.size) throw \"Dimensions must match!\";\n\tfor(size_t row = 0; row < first.size; row++)\n\t\tfor(size_t col = row; col < first.size; col++)\n\t\t\tif(!tolerantEquals(first.get(row, col), second.get(row, col), tolerance))\n\t\t\t\treturn false;\n\n\treturn true;\n}\n\ntemplate<typename Tol>\nbool tolerantEquals(const P3D::Position& a, const P3D::Position& b, Tol tolerance) {\n\tP3D::Vec3 delta = a - b;\n\treturn tolerantEquals(delta, P3D::Vec3(0, 0, 0), tolerance);\n}\n\ntemplate<typename T, typename Tol>\nbool tolerantEquals(const P3D::Quaternion<T>& a, const P3D::Quaternion<T>& b, Tol tolerance) {\n\treturn\n\t\ttolerantEquals(a.w, b.w, tolerance) &&\n\t\ttolerantEquals(a.i, b.i, tolerance) &&\n\t\ttolerantEquals(a.j, b.j, tolerance) &&\n\t\ttolerantEquals(a.k, b.k, tolerance);\n}\n\ntemplate<typename T, typename Tol>\nbool tolerantEquals(const P3D::MatrixRotationTemplate<T>& a, const P3D::MatrixRotationTemplate<T>& b, Tol tolerance) {\n\treturn tolerantEquals(a.asRotationMatrix(), b.asRotationMatrix(), tolerance);\n}\n\ntemplate<typename T, typename Tol>\nbool tolerantEquals(const P3D::QuaternionRotationTemplate<T>& a, const P3D::QuaternionRotationTemplate<T>& b, Tol tolerance) {\n\tP3D::Quaternion<T> aq = a.asRotationQuaternion();\n\tP3D::Quaternion<T> bq = b.asRotationQuaternion();\n\t// Quaternions double cover the plane of possible rotations, -q and q express the same rotation. \n\t// Therefore we must make sure we are comparing correctly\n\tif(dot(aq, bq) > 0) { // quaternions are aligned\n\t\treturn tolerantEquals(aq, bq, tolerance);\n\t} else { // quaternions are not aligned\n\t\treturn tolerantEquals(aq, -bq, tolerance);\n\t}\n}\n\ntemplate<typename Tol>\nbool tolerantEquals(const P3D::CFrame& first, const P3D::CFrame& second, Tol tolerance) {\n\treturn tolerantEquals(first.position, second.position, tolerance) &&\n\t\ttolerantEquals(first.rotation, second.rotation, tolerance);\n}\n\ntemplate<typename Tol>\nbool tolerantEquals(const P3D::GlobalCFrame& first, const P3D::GlobalCFrame& second, Tol tolerance) {\n\treturn tolerantEquals(first.position, second.position, tolerance) &&\n\t\ttolerantEquals(first.rotation, second.rotation, tolerance);\n}\n\ntemplate<typename Tol, typename N>\nbool tolerantEquals(const P3D::EigenValues<N, 3>& a, const P3D::EigenValues<N, 3>& b, Tol tolerance) {\n\treturn tolerantEquals(a[0], b[0], tolerance) && tolerantEquals(a[1], b[1], tolerance) && tolerantEquals(a[2], b[2], tolerance) ||\n\t\ttolerantEquals(a[0], b[0], tolerance) && tolerantEquals(a[1], b[2], tolerance) && tolerantEquals(a[2], b[1], tolerance) ||\n\t\ttolerantEquals(a[0], b[1], tolerance) && tolerantEquals(a[1], b[0], tolerance) && tolerantEquals(a[2], b[2], tolerance) ||\n\t\ttolerantEquals(a[0], b[1], tolerance) && tolerantEquals(a[1], b[2], tolerance) && tolerantEquals(a[2], b[0], tolerance) ||\n\t\ttolerantEquals(a[0], b[2], tolerance) && tolerantEquals(a[1], b[0], tolerance) && tolerantEquals(a[2], b[1], tolerance) ||\n\t\ttolerantEquals(a[0], b[2], tolerance) && tolerantEquals(a[1], b[1], tolerance) && tolerantEquals(a[2], b[0], tolerance);\n}\n\ntemplate<typename Tol, typename T, std::size_t DerivationCount>\nbool tolerantEquals(const P3D::Derivatives<T, DerivationCount>& first, const P3D::Derivatives<T, DerivationCount>& second, Tol tolerance) {\n\tfor(std::size_t i = 0; i < DerivationCount; i++) {\n\t\tif(!tolerantEquals(first[i], second[i], tolerance)) return false;\n\t}\n\treturn true;\n}\n\ntemplate<typename Tol, typename T, std::size_t DerivationCount>\nbool tolerantEquals(const P3D::TaylorExpansion<T, DerivationCount>& first, const P3D::TaylorExpansion<T, DerivationCount>& second, Tol tolerance) {\n\treturn tolerantEquals(first.derivs, second.derivs, tolerance);\n}\n\ntemplate<typename Tol, typename T, std::size_t DerivationCount>\nbool tolerantEquals(const P3D::FullTaylorExpansion<T, DerivationCount>& first, const P3D::FullTaylorExpansion<T, DerivationCount>& second, Tol tolerance) {\n\treturn tolerantEquals(first.derivs, second.derivs, tolerance);\n}\n\ntemplate<typename Tol>\nbool tolerantEquals(const P3D::TranslationalMotion& first, const P3D::TranslationalMotion& second, Tol tolerance) {\n\treturn tolerantEquals(first.translation, second.translation, tolerance);\n}\n\ntemplate<typename Tol>\nbool tolerantEquals(const P3D::RotationalMotion& first, const P3D::RotationalMotion& second, Tol tolerance) {\n\treturn tolerantEquals(first.rotation, second.rotation, tolerance);\n}\n\ntemplate<typename Tol>\nbool tolerantEquals(const P3D::Motion& first, const P3D::Motion& second, Tol tolerance) {\n\treturn tolerantEquals(first.translation, second.translation, tolerance)\n\t\t&& tolerantEquals(first.rotation, second.rotation, tolerance);\n}\n\ntemplate<typename Tol>\nbool tolerantEquals(const P3D::RelativeMotion& first, const P3D::RelativeMotion& second, Tol tolerance) {\n\treturn tolerantEquals(first.relativeMotion, second.relativeMotion, tolerance) &&\n\t\ttolerantEquals(first.locationOfRelativeMotion, second.locationOfRelativeMotion, tolerance);\n}\n\ntemplate<typename Tol>\nbool tolerantEquals(const P3D::BoundingBox& first, const P3D::BoundingBox& second, Tol tolerance) {\n\treturn tolerantEquals(first.min, second.min, tolerance) &&\n\t\ttolerantEquals(first.max, second.max, tolerance);\n}\n\ntemplate<typename T1, typename T2, typename Tol>\nbool tolerantEquals(const std::pair<T1, T2>& first, const std::pair<T1, T2>& second, Tol tolerance) {\n\treturn tolerantEquals(first.first, second.first, tolerance) &&\n\t\ttolerantEquals(first.second, second.second, tolerance);\n}\n\ntemplate<typename T, std::size_t Size, typename Tol>\nbool tolerantEquals(const std::array<T, Size>& first, const std::array<T, Size>& second, Tol tolerance) {\n\tfor(std::size_t i = 0; i < Size; i++) {\n\t\tif(!tolerantEquals(first[i], second[i], tolerance)) {\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\ntemplate<typename T, typename Tol>\nbool tolerantEquals(const std::vector<T>& first, const std::vector<T>& second, Tol tolerance) {\n\tif(first.size() != second.size()) throw std::logic_error(\"Incompatible vector sizes!\");\n\tfor(std::size_t i = 0; i < first.size(); i++) {\n\t\tif(!tolerantEquals(first[i], second[i], tolerance)) {\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\ntemplate<typename T, std::size_t Height, std::size_t Width, typename Tol>\nbool tolerantEquals(const P3D::Matrix<T, Height, Width>& first, const P3D::UnmanagedHorizontalFixedMatrix<T, Width>& second, Tol tolerance) {\n\tassert(first.height() == second.height());\n\tfor(size_t row = 0; row < Height; row++)\n\t\tfor(size_t col = 0; col < Width; col++)\n\t\t\tif(!tolerantEquals(first(row, col), second(row, col), tolerance))\n\t\t\t\treturn false;\n\n\treturn true;\n}\ntemplate<typename T, std::size_t Height, std::size_t Width, typename Tol>\nbool tolerantEquals(const P3D::UnmanagedHorizontalFixedMatrix<T, Width>& second, const P3D::Matrix<T, Height, Width>& first, Tol tolerance) {\n\treturn tolerantEquals(first, second, tolerance);\n}\ntemplate<typename T, std::size_t Height, std::size_t Width, typename Tol>\nbool tolerantEquals(const P3D::Matrix<T, Height, Width>& first, const P3D::UnmanagedVerticalFixedMatrix<T, Height>& second, Tol tolerance) {\n\tassert(first.width() == second.width());\n\tfor(size_t row = 0; row < Height; row++)\n\t\tfor(size_t col = 0; col < Width; col++)\n\t\t\tif(!tolerantEquals(first(row, col), second(row, col), tolerance))\n\t\t\t\treturn false;\n\n\treturn true;\n}\ntemplate<typename T, std::size_t Height, std::size_t Width, typename Tol>\nbool tolerantEquals(const P3D::UnmanagedVerticalFixedMatrix<T, Height>& second, const P3D::Matrix<T, Height, Width>& first, Tol tolerance) {\n\treturn tolerantEquals(first, second, tolerance);\n}\ntemplate<typename T, std::size_t Size, typename Tol>\nbool tolerantEquals(const P3D::UnmanagedVerticalFixedMatrix<T, Size>& first, const P3D::UnmanagedVerticalFixedMatrix<T, Size>& second, Tol tolerance) {\n\tassert(first.width() == second.width());\n\tfor(size_t row = 0; row < first.height(); row++)\n\t\tfor(size_t col = 0; col < first.width(); col++)\n\t\t\tif(!tolerantEquals(first(row, col), second(row, col), tolerance))\n\t\t\t\treturn false;\n\n\treturn true;\n}\ntemplate<typename T, std::size_t Size, typename Tol>\nbool tolerantEquals(const P3D::UnmanagedHorizontalFixedMatrix<T, Size>& first, const P3D::UnmanagedHorizontalFixedMatrix<T, Size>& second, Tol tolerance) {\n\tassert(first.width() == second.width());\n\tfor(size_t row = 0; row < first.height(); row++)\n\t\tfor(size_t col = 0; col < first.width(); col++)\n\t\t\tif(!tolerantEquals(first(row, col), second(row, col), tolerance))\n\t\t\t\treturn false;\n\n\treturn true;\n}\n"
  },
  {
    "path": "tests/constraintTests.cpp",
    "content": "#include \"testsMain.h\"\n\n#include \"compare.h\"\n#include \"generators.h\"\n#include \"estimateMotion.h\"\n#include <Physics3D/misc/toString.h>\n\n#include <Physics3D/geometry/shape.h>\n#include <Physics3D/geometry/shapeCreation.h>\n#include <Physics3D/part.h>\n#include <Physics3D/physical.h>\n#include <Physics3D/layer.h>\n#include <Physics3D/world.h>\n#include <Physics3D/hardconstraints/fixedConstraint.h>\n#include <Physics3D/hardconstraints/motorConstraint.h>\n#include <Physics3D/hardconstraints/sinusoidalPistonConstraint.h>\n#include <Physics3D/math/linalg/trigonometry.h>\n\n#include <functional>\n\nusing namespace P3D;\n#define ASSERT(cond) ASSERT_TOLERANT(cond, 0.05)\n\n#define DELTA_T 0.0001\n\nTEST_CASE(testMotionOfPhysicalSinglePart) {\n\tPart p1(sphereShape(1.0), GlobalCFrame(0.0, 0.0, 0.0), {1.0, 1.0, 1.0});\n\n\tPhysical* p1Phys = p1.ensureHasPhysical();\n\n\tMotion COMMotion(Vec3(1.0, 0.7, 1.3), Vec3(-0.3, 1.7, -1.1));\n\n\tp1Phys->mainPhysical->motionOfCenterOfMass = COMMotion;\n\n\tVec3 p1calculatedVelBefore = p1.getMotion().getVelocity();\n\n\tVec3 p1calculatedAccelBefore = p1.getMotion().getAcceleration();\n\n\tPosition p1PosBefore = p1.getCenterOfMass();\n\n\tp1Phys->mainPhysical->update(DELTA_T);\n\n\tPosition p1PosMid = p1.getCenterOfMass();\n\n\tp1Phys->mainPhysical->update(DELTA_T);\n\n\tPosition p1PosAfter = p1.getCenterOfMass();\n\n\tTranslationalMotion estimatedVelAccel1 = estimateMotion(p1PosBefore, p1PosMid, p1PosAfter, DELTA_T);\n\n\tASSERT(estimatedVelAccel1.getVelocity() == p1calculatedVelBefore);\n\tASSERT(estimatedVelAccel1.getAcceleration() == p1calculatedAccelBefore);\n}\n\nTEST_CASE(testMotionOfPhysicalPartsBasic) {\n\tPart p1(sphereShape(1.0), GlobalCFrame(0.0, 0.0, 0.0), {1.0, 1.0, 1.0});\n\tPart p2(sphereShape(1.0), GlobalCFrame(1.0, 0.0, 0.0), {3.0, 1.0, 1.0});\n\tp1.attach(&p2, CFrame(1.0, 0.0, 0.0));\n\n\tMotion COMMotion(Vec3(1.0, 0.7, 1.3), Vec3(0, 0, 0));\n\n\tPhysical* p1Phys = p1.getPhysical();\n\tp1.getMainPhysical()->motionOfCenterOfMass = COMMotion;\n\n\tVec3 p1calculatedVelBefore = p1.getMotion().getVelocity();\n\tVec3 p2calculatedVelBefore = p2.getMotion().getVelocity();\n\n\tVec3 p1calculatedAccelBefore = p1.getMotion().getAcceleration();\n\tVec3 p2calculatedAccelBefore = p2.getMotion().getAcceleration();\n\n\tPosition p1PosBefore = p1.getCenterOfMass();\n\tPosition p2PosBefore = p2.getCenterOfMass();\n\n\tp1.getMainPhysical()->update(DELTA_T);\n\n\tPosition p1PosMid = p1.getCenterOfMass();\n\tPosition p2PosMid = p2.getCenterOfMass();\n\n\tp1.getMainPhysical()->update(DELTA_T);\n\n\tPosition p1PosAfter = p1.getCenterOfMass();\n\tPosition p2PosAfter = p2.getCenterOfMass();\n\n\tTranslationalMotion estimatedVelAccel1 = estimateMotion(p1PosBefore, p1PosMid, p1PosAfter, DELTA_T);\n\tTranslationalMotion estimatedVelAccel2 = estimateMotion(p2PosBefore, p2PosMid, p2PosAfter, DELTA_T);\n\n\tASSERT(estimatedVelAccel1.getVelocity() == p1calculatedVelBefore);\n\tASSERT(estimatedVelAccel2.getVelocity() == p2calculatedVelBefore);\n\tASSERT(estimatedVelAccel1.getAcceleration() == p1calculatedAccelBefore);\n\tASSERT(estimatedVelAccel2.getAcceleration() == p2calculatedAccelBefore);\n}\n\nTEST_CASE(testMotionOfPhysicalPartsRotation) {\n\tPart p1(sphereShape(1.0), GlobalCFrame(0.0, 0.0, 0.0), {1.0, 1.0, 1.0});\n\tPart p2(sphereShape(1.0), GlobalCFrame(1.0, 0.0, 0.0), {3.0, 1.0, 1.0});\n\tp1.attach(&p2, CFrame(1.0, 0.0, 0.0));\n\n\tMotion COMMotion(Vec3(0, 0, 0), Vec3(-0.3, 1.7, -1.1));\n\n\tp1.getMainPhysical()->motionOfCenterOfMass = COMMotion;\n\n\tVec3 p1calculatedVelBefore = p1.getMotion().getVelocity();\n\tVec3 p2calculatedVelBefore = p2.getMotion().getVelocity();\n\n\tlogStream << p1.getPhysical()->getMotion() << \"\\n\";\n\tlogStream << p1.getMotion() << \"\\n\";\n\tlogStream << p2.getMotion() << \"\\n\";\n\n\tVec3 p1calculatedAccelBefore = p1.getMotion().getAcceleration();\n\tVec3 p2calculatedAccelBefore = p2.getMotion().getAcceleration();\n\n\tGlobalCFrame p1CFrameBefore = p1.getCFrame();\n\tGlobalCFrame p2CFrameBefore = p2.getCFrame();\n\n\tp1.getMainPhysical()->update(DELTA_T);\n\n\tGlobalCFrame p1CFrameMid = p1.getCFrame();\n\tGlobalCFrame p2CFrameMid = p2.getCFrame();\n\n\tp1.getMainPhysical()->update(DELTA_T);\n\n\tGlobalCFrame p1CFrameAfter = p1.getCFrame();\n\tGlobalCFrame p2CFrameAfter = p2.getCFrame();\n\n\tMotion estimatedMotion1 = estimateMotion(p1CFrameBefore, p1CFrameMid, p1CFrameAfter, DELTA_T);\n\tMotion estimatedMotion2 = estimateMotion(p2CFrameBefore, p2CFrameMid, p2CFrameAfter, DELTA_T);\n\n\tASSERT(estimatedMotion1.getVelocity() == p1calculatedVelBefore);\n\tASSERT(estimatedMotion2.getVelocity() == p2calculatedVelBefore);\n\t//ASSERT(estimatedMotion1.getAcceleration() == p1calculatedAccelBefore);\n\t//ASSERT(estimatedMotion2.getAcceleration() == p2calculatedAccelBefore);\n}\n\nTEST_CASE(testMotionOfPhysicalPartsBasicFixedConstraint) {\n\tPart p1(sphereShape(1.0), GlobalCFrame(0.0, 0.0, 0.0), {1.0, 1.0, 1.0});\n\tPart p2(sphereShape(1.0), GlobalCFrame(1.0, 0.0, 0.0), {3.0, 1.0, 1.0});\n\n\tp1.attach(&p2, new FixedConstraint(), CFrame(1.0, 0.0, 0.0), CFrame(0, 0, 0));\n\n\tMotion COMMotion(Vec3(1.0, 0.7, 1.3), Vec3(0, 0, 0));\n\n\tp1.getMainPhysical()->motionOfCenterOfMass = COMMotion;\n\n\tVec3 p1calculatedVelBefore = p1.getMotion().getVelocity();\n\tVec3 p2calculatedVelBefore = p2.getMotion().getVelocity();\n\n\tVec3 p1calculatedAccelBefore = p1.getMotion().getAcceleration();\n\tVec3 p2calculatedAccelBefore = p2.getMotion().getAcceleration();\n\n\tPosition p1PosBefore = p1.getCenterOfMass();\n\tPosition p2PosBefore = p2.getCenterOfMass();\n\n\tp1.getMainPhysical()->update(DELTA_T);\n\n\tPosition p1PosMid = p1.getCenterOfMass();\n\tPosition p2PosMid = p2.getCenterOfMass();\n\n\tp1.getMainPhysical()->update(DELTA_T);\n\n\tPosition p1PosAfter = p1.getCenterOfMass();\n\tPosition p2PosAfter = p2.getCenterOfMass();\n\n\tTranslationalMotion estimatedVelAccel1 = estimateMotion(p1PosBefore, p1PosMid, p1PosAfter, DELTA_T);\n\tTranslationalMotion estimatedVelAccel2 = estimateMotion(p2PosBefore, p2PosMid, p2PosAfter, DELTA_T);\n\n\tASSERT(estimatedVelAccel1.getVelocity() == p1calculatedVelBefore);\n\tASSERT(estimatedVelAccel2.getVelocity() == p2calculatedVelBefore);\n\tASSERT(estimatedVelAccel1.getAcceleration() == p1calculatedAccelBefore);\n\tASSERT(estimatedVelAccel2.getAcceleration() == p2calculatedAccelBefore);\n}\n\nTEST_CASE(testMotionOfPhysicalPartsRotationFixedConstraint) {\n\tPart p1(sphereShape(1.0), GlobalCFrame(0.0, 0.0, 0.0), {1.0, 1.0, 1.0});\n\tPart p2(sphereShape(1.0), GlobalCFrame(1.0, 0.0, 0.0), {3.0, 1.0, 1.0});\n\n\tp1.attach(&p2, new FixedConstraint(), CFrame(1.0, 0.0, 0.0), CFrame(0, 0, 0));\n\n\tMotion COMMotion(Vec3(0, 0, 0), Vec3(-0.3, 1.7, -1.1));\n\n\tp1.getMainPhysical()->motionOfCenterOfMass = COMMotion;\n\n\tVec3 p1calculatedVelBefore = p1.getMotion().getVelocity();\n\tVec3 p2calculatedVelBefore = p2.getMotion().getVelocity();\n\n\tlogStream << p1.getPhysical()->getMotion() << \"\\n\";\n\tlogStream << p1.getMotion() << \"\\n\";\n\tlogStream << p2.getMotion() << \"\\n\";\n\n\tVec3 p1calculatedAccelBefore = p1.getMotion().getAcceleration();\n\tVec3 p2calculatedAccelBefore = p2.getMotion().getAcceleration();\n\n\tPosition p1PosBefore = p1.getCenterOfMass();\n\tPosition p2PosBefore = p2.getCenterOfMass();\n\n\tp1.getMainPhysical()->update(DELTA_T);\n\n\tPosition p1PosMid = p1.getCenterOfMass();\n\tPosition p2PosMid = p2.getCenterOfMass();\n\n\tp1.getMainPhysical()->update(DELTA_T);\n\n\tPosition p1PosAfter = p1.getCenterOfMass();\n\tPosition p2PosAfter = p2.getCenterOfMass();\n\n\tTranslationalMotion estimatedVelAccel1 = estimateMotion(p1PosBefore, p1PosMid, p1PosAfter, DELTA_T);\n\tTranslationalMotion estimatedVelAccel2 = estimateMotion(p2PosBefore, p2PosMid, p2PosAfter, DELTA_T);\n\n\tASSERT(estimatedVelAccel2.getVelocity() == p2calculatedVelBefore);\n\tASSERT(estimatedVelAccel1.getVelocity() == p1calculatedVelBefore);\n\t//ASSERT(estimatedVelAccel2.getAcceleration() == p2calculatedAccelBefore);\n\t//ASSERT(estimatedVelAccel1.getAcceleration() == p1calculatedAccelBefore);\n}\n\nTEST_CASE(testMotionOfPhysicalParts) {\n\tPart p1(sphereShape(1.0), GlobalCFrame(0.0, 0.0, 0.0), {1.0, 1.0, 1.0});\n\tPart p2(sphereShape(1.0), GlobalCFrame(1.0, 0.0, 0.0), {3.0, 1.0, 1.0});\n\tp1.attach(&p2, CFrame(1.0, 0.0, 0.0));\n\n\tMotion COMMotion(Vec3(1.0, 0.7, 1.3), Vec3(-0.3, 1.7, -1.1));\n\n\tp1.getMainPhysical()->motionOfCenterOfMass = COMMotion;\n\n\tVec3 p1calculatedVelBefore = p1.getMotion().getVelocity();\n\tVec3 p2calculatedVelBefore = p2.getMotion().getVelocity();\n\n\tVec3 p1calculatedAccelBefore = p1.getMotion().getAcceleration();\n\tVec3 p2calculatedAccelBefore = p2.getMotion().getAcceleration();\n\n\tPosition p1PosBefore = p1.getCenterOfMass();\n\tPosition p2PosBefore = p2.getCenterOfMass();\n\n\tp1.getMainPhysical()->update(DELTA_T);\n\n\tPosition p1PosMid = p1.getCenterOfMass();\n\tPosition p2PosMid = p2.getCenterOfMass();\n\n\tp1.getMainPhysical()->update(DELTA_T);\n\n\tPosition p1PosAfter = p1.getCenterOfMass();\n\tPosition p2PosAfter = p2.getCenterOfMass();\n\n\tTranslationalMotion estimatedVelAccel1 = estimateMotion(p1PosBefore, p1PosMid, p1PosAfter, DELTA_T);\n\tTranslationalMotion estimatedVelAccel2 = estimateMotion(p2PosBefore, p2PosMid, p2PosAfter, DELTA_T);\n\n\tASSERT(estimatedVelAccel1.getVelocity() == p1calculatedVelBefore);\n\tASSERT(estimatedVelAccel2.getVelocity() == p2calculatedVelBefore);\n\t//ASSERT(estimatedVelAccel1.getAcceleration() == p1calculatedAccelBefore);\n\t//ASSERT(estimatedVelAccel2.getAcceleration() == p2calculatedAccelBefore);\n}\n\nTEST_CASE(testMotionOfPhysicalJointsBasic) {\n\tPart p1(sphereShape(1.0), GlobalCFrame(0.0, 0.0, 0.0), {1.0, 1.0, 1.0});\n\tPart p2(sphereShape(1.0), GlobalCFrame(1.0, 0.0, 0.0), {3.0, 1.0, 1.0});\n\tp1.attach(&p2, CFrame(1.0, 0.0, 0.0));\n\n\tPart p1e(sphereShape(1.0), GlobalCFrame(0.0, 0.0, 0.0), {1.0, 1.0, 1.0});\n\tPart p2e(sphereShape(1.0), GlobalCFrame(1.0, 0.0, 0.0), {3.0, 1.0, 1.0});\n\n\tp1e.attach(&p2e, new FixedConstraint(), CFrame(1.0, 0.0, 0.0), CFrame(0, 0, 0));\n\n\tMotion COMMotion(Vec3(1.0, 0.7, 1.3), Vec3(0, 0, 0));\n\n\tp1.getMainPhysical()->motionOfCenterOfMass = COMMotion;\n\tp1e.getMainPhysical()->motionOfCenterOfMass = COMMotion;\n\n\tASSERT(p1.getMotion() == p1e.getMotion());\n\tASSERT(p2.getMotion() == p2e.getMotion());\n}\n\nTEST_CASE(testMotionOfPhysicalJointsRotation) {\n\tPart p1(sphereShape(1.0), GlobalCFrame(0.0, 0.0, 0.0), {1.0, 1.0, 1.0});\n\tPart p2(sphereShape(1.0), GlobalCFrame(1.0, 0.0, 0.0), {3.0, 1.0, 1.0});\n\tp1.attach(&p2, CFrame(1.0, 0.0, 0.0));\n\n\tPart p1e(sphereShape(1.0), GlobalCFrame(0.0, 0.0, 0.0), {1.0, 1.0, 1.0});\n\tPart p2e(sphereShape(1.0), GlobalCFrame(1.0, 0.0, 0.0), {3.0, 1.0, 1.0});\n\n\tp1e.attach(&p2e, new FixedConstraint(), CFrame(1.0, 0.0, 0.0), CFrame(0.0, 0.0, 0.0));\n\n\tMotion COMMotion(Vec3(0, 0, 0), Vec3(-0.3, 1.7, -1.1));\n\n\tp1.getMainPhysical()->motionOfCenterOfMass = COMMotion;\n\tp1e.getMainPhysical()->motionOfCenterOfMass = COMMotion;\n\n\tlogStream << p1.getPhysical()->getMotion() << \"\\n\";\n\tlogStream << p1.getMotion() << \"\\n\";\n\tlogStream << p2.getMotion() << \"\\n\";\n\tlogStream << p1e.getPhysical()->getMotion() << \"\\n\";\n\tlogStream << p1e.getMotion() << \"\\n\";\n\tlogStream << p2e.getMotion() << \"\\n\";\n\n\tASSERT(p1.getMotion() == p1e.getMotion());\n\tASSERT(p2.getMotion() == p2e.getMotion());\n}\n\nTEST_CASE(testMotionOfPhysicalJoints) {\n\tPart p1(sphereShape(1.0), GlobalCFrame(0.0, 0.0, 0.0), {1.0, 1.0, 1.0});\n\tPart p2(sphereShape(1.0), GlobalCFrame(1.0, 0.0, 0.0), {3.0, 1.0, 1.0});\n\tp1.attach(&p2, CFrame(1.0, 0.0, 0.0));\n\n\tPart p1e(sphereShape(1.0), GlobalCFrame(0.0, 0.0, 0.0), {1.0, 1.0, 1.0});\n\tPart p2e(sphereShape(1.0), GlobalCFrame(1.0, 0.0, 0.0), {3.0, 1.0, 1.0});\n\n\tp1e.attach(&p2e, new FixedConstraint(), CFrame(1.0, 0.0, 0.0), CFrame(0, 0, 0));\n\n\tMotion COMMotion(Vec3(1.0, 0.7, 1.3), Vec3(-0.3, 1.7, -1.1));\n\n\tp1.getMainPhysical()->motionOfCenterOfMass = COMMotion;\n\tp1e.getMainPhysical()->motionOfCenterOfMass = COMMotion;\n\n\tlogStream << p1.getPhysical()->getMotion() << \"\\n\";\n\tlogStream << p1.getMotion() << \"\\n\";\n\tlogStream << p2.getMotion() << \"\\n\";\n\tlogStream << p1e.getPhysical()->getMotion() << \"\\n\";\n\tlogStream << p1e.getMotion() << \"\\n\";\n\tlogStream << p2e.getMotion() << \"\\n\";\n\n\tASSERT(p1.getMotion() == p1e.getMotion());\n\tASSERT(p2.getMotion() == p2e.getMotion());\n}\n\nTEST_CASE(testFixedConstraintProperties) {\n\tPart p1(sphereShape(1.0), GlobalCFrame(0.0, 0.0, 0.0), {1.0, 1.0, 1.0});\n\tPart p2(sphereShape(1.0), GlobalCFrame(), {3.0, 1.0, 1.0});\n\tp1.attach(&p2, CFrame(1.0, 0.0, 0.0));\n\n\tPart p1e(sphereShape(1.0), GlobalCFrame(0.0, 0.0, 0.0), {1.0, 1.0, 1.0});\n\tPart p2e(sphereShape(1.0), GlobalCFrame(), {3.0, 1.0, 1.0});\n\n\tp1e.attach(&p2e, new FixedConstraint(), CFrame(0.3, -0.8, 0.0), CFrame(-0.7, -0.8, 0));\n\n\tMotorizedPhysical* phys1 = p1.getMainPhysical();\n\tMotorizedPhysical* phys1e = p1e.getMainPhysical();\n\n\tASSERT(p1.getCFrame() == GlobalCFrame(0.0, 0.0, 0.0));\n\tASSERT(p2.getCFrame() == GlobalCFrame(1.0, 0.0, 0.0));\n\tASSERT(p1e.getCFrame() == GlobalCFrame(0.0, 0.0, 0.0));\n\tASSERT(p2e.getCFrame() == GlobalCFrame(1.0, 0.0, 0.0));\n\tASSERT(phys1->totalMass == phys1e->totalMass);\n\tASSERT(phys1->getCenterOfMass() == phys1e->getCenterOfMass());\n\tASSERT(phys1->forceResponse == phys1e->forceResponse);\n\tASSERT(phys1->momentResponse == phys1e->momentResponse);\n\n}\n\nTEST_CASE(testApplyForceToFixedConstraint) {\n\tCFrame attach(Vec3(1.3, 0.7, 0.9), Rotation::fromEulerAngles(0.3, -0.7, 0.9));\n\n\tPart p1(boxShape(1.0, 2.0, 3.0), GlobalCFrame(), {1.0, 1.0, 1.0});\n\tPart p2(boxShape(1.5, 2.3, 1.2), GlobalCFrame(), {1.0, 1.0, 1.0});\n\n\tp1.attach(&p2, attach);\n\n\n\tPart p1e(boxShape(1.0, 2.0, 3.0), GlobalCFrame(), {1.0, 1.0, 1.0});\n\tPart p2e(boxShape(1.5, 2.3, 1.2), GlobalCFrame(), {1.0, 1.0, 1.0});\n\n\tp1e.attach(&p2e, new FixedConstraint(), attach, CFrame());\n\n\tMotorizedPhysical* phys1 = p1.getMainPhysical();\n\tMotorizedPhysical* phys1e = p1e.getMainPhysical();\n\n\tphys1->applyForceAtCenterOfMass(Vec3(2.7, 3.9, -2.3));\n\tphys1e->applyForceAtCenterOfMass(Vec3(2.7, 3.9, -2.3));\n\n\tphys1->update(DELTA_T);\n\tphys1e->update(DELTA_T);\n\n\tASSERT(phys1->getMotion() == phys1e->getMotion());\n\n\tASSERT(p1.getCFrame() == p1e.getCFrame());\n\tASSERT(p2.getCFrame() == p2e.getCFrame());\n\n\tASSERT(phys1->forceResponse == phys1e->forceResponse);\n\tASSERT(phys1->momentResponse == phys1e->momentResponse);\n\n\tphys1->applyImpulseAtCenterOfMass(Vec3(2.7, 3.9, -2.3));\n\tphys1e->applyImpulseAtCenterOfMass(Vec3(2.7, 3.9, -2.3));\n\n\tphys1->update(DELTA_T);\n\tphys1e->update(DELTA_T);\n\n\tASSERT(phys1->getMotion() == phys1e->getMotion());\n\n\tASSERT(p1.getCFrame() == p1e.getCFrame());\n\tASSERT(p2.getCFrame() == p2e.getCFrame());\n\n\tASSERT(phys1->forceResponse == phys1e->forceResponse);\n\tASSERT(phys1->momentResponse == phys1e->momentResponse);\n}\n\nTEST_CASE(testPlainAttachAndFixedConstraintIndistinguishable) {\n\tPart firstPart(boxShape(1.0, 1.0, 1.0), GlobalCFrame(0.0, 0.0, 0.0), {1.0, 1.0, 1.0});\n\tPart secondPart(boxShape(0.5, 0.5, 0.5), GlobalCFrame(1.0, 0.0, 0.0), {1.0, 1.0, 1.0});\n\n\tfirstPart.attach(&secondPart, CFrame(1.0, 0.0, 0.0));\n\n\tPart firstPart2(boxShape(1.0, 1.0, 1.0), GlobalCFrame(0.0, 0.0, 0.0), {1.0, 1.0, 1.0});\n\tPart secondPart2(boxShape(0.5, 0.5, 0.5), GlobalCFrame(1.0, 0.0, 0.0), {1.0, 1.0, 1.0});\n\n\tfirstPart2.attach(&secondPart2, new FixedConstraint(), CFrame(0.5, 0.0, 0.0), CFrame(-0.5, 0.0, 0.0));\n\n\tVec3 impulse(1.3, 4.7, 0.2);\n\tVec3 impulsePos(2.6, 1.7, 2.8);\n\n\tMotorizedPhysical* main1 = firstPart.getMainPhysical();\n\tMotorizedPhysical* main2 = firstPart2.getMainPhysical();\n\n\tmain1->applyImpulse(impulsePos, impulse);\n\tmain2->applyImpulse(impulsePos, impulse);\n\n\tmain1->update(0.5);\n\tmain2->update(0.5);\n\n\tASSERT(main1->getMotionOfCenterOfMass() == main2->getMotionOfCenterOfMass());\n\tASSERT(main1->getCFrame() == main2->getCFrame());\n}\n\nTEST_CASE(testInternalMotionOfCenterOfMass) {\n\tPart firstPart(boxShape(1.0, 1.0, 1.0), GlobalCFrame(0.0, 0.0, 0.0), {1.0, 1.0, 1.0});\n\tPart secondPart(boxShape(0.5, 0.5, 0.5), GlobalCFrame(1.0, 0.0, 0.0), {1.0, 1.0, 1.0});\n\n\tSinusoidalPistonConstraint* piston = new SinusoidalPistonConstraint(0.3, 1.0, 1.0);\n\n\tpiston->currentStepInPeriod = 0.7;\n\n\tfirstPart.attach(&secondPart, piston, CFrame(0.0, 0.0, 1.0), CFrame(0.0, 0.0, -1.0));\n\n\tMotorizedPhysical* phys = firstPart.getMainPhysical();\n\n\tVec3 original = phys->totalCenterOfMass;\n\n\tALLOCA_InternalMotionTree(cache, phys, size);\n\n\tTranslationalMotion motionOfCom = std::get<2>(cache.getInternalMotionOfCenterOfMass());\n\n\tphys->update(DELTA_T);\n\tVec3 v2 = phys->totalCenterOfMass;\n\n\tphys->update(DELTA_T);\n\tVec3 v3 = phys->totalCenterOfMass;\n\n\tTranslationalMotion estimatedMotion = estimateMotion(original, v2, v3, DELTA_T);\n\n\tASSERT(motionOfCom == estimatedMotion);\n}\n\nstatic bool haveSameMotorPhys(const Part& first, const Part& second) {\n\treturn first.getPhysical() != nullptr && second.getPhysical() != nullptr && first.getMainPhysical() == second.getMainPhysical();\n}\n\nTEST_CASE(attachPhysicalsNoLayers) {\n\tfor(int iter = 0; iter < 100; iter++) {\n\t\tstd::vector<Part> firstPhysParts = generateMotorizedPhysicalParts();\n\t\tstd::vector<Part> secondPhysParts = generateMotorizedPhysicalParts();\n\n\t\tASSERT_FALSE(haveSameMotorPhys(firstPhysParts[0], secondPhysParts[0]));\n\n\t\tgenerateAttachment(oneOf(firstPhysParts), oneOf(secondPhysParts));\n\n\t\tASSERT_TRUE(haveSameMotorPhys(firstPhysParts[0], secondPhysParts[0]));\n\t}\n}\n\nbool areInSameGroup(const Part& a, const Part& b) {\n\treturn a.layer->tree.groupContains(&a, &b);\n}\n\nstatic bool pairwiseCorrectlyGrouped(const std::vector<Part>& la, const std::vector<Part>& lb, bool expectedAreInSameGroup) {\n\tfor(const Part& a : la) {\n\t\tfor(const Part& b : lb) {\n\t\t\tif(a.layer == b.layer) {\n\t\t\t\tif(areInSameGroup(a, b) != expectedAreInSameGroup) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn true;\n}\n\nTEST_CASE(attachPhysicalsWithLayers) {\n\tfor(int iter = 0; iter < 100; iter++) {\n\t\tWorldPrototype testWorld(0.005);\n\t\ttestWorld.createLayer(true, true);\n\t\ttestWorld.createLayer(false, false);\n\t\tstd::vector<Part> firstPhysParts = generateMotorizedPhysicalParts();\n\t\tstd::vector<Part> secondPhysParts = generateMotorizedPhysicalParts();\n\t\tgenerateLayerAssignment(firstPhysParts, testWorld);\n\t\tgenerateLayerAssignment(secondPhysParts, testWorld);\n\n\t\tASSERT_FALSE(haveSameMotorPhys(firstPhysParts[0], secondPhysParts[0]));\n\n\t\tASSERT_TRUE(pairwiseCorrectlyGrouped(firstPhysParts, firstPhysParts, true));\n\t\tASSERT_TRUE(pairwiseCorrectlyGrouped(secondPhysParts, secondPhysParts, true));\n\t\tASSERT_TRUE(pairwiseCorrectlyGrouped(firstPhysParts, secondPhysParts, false));\n\n\t\tPart& attachedPart1 = oneOf(firstPhysParts);\n\t\tPart& attachedPart2 = oneOf(secondPhysParts);\n\n\t\tgenerateAttachment(attachedPart1, attachedPart2);\n\n\t\tASSERT_TRUE(haveSameMotorPhys(firstPhysParts[0], secondPhysParts[0]));\n\n\t\tASSERT_TRUE(pairwiseCorrectlyGrouped(firstPhysParts, firstPhysParts, true));\n\t\tASSERT_TRUE(pairwiseCorrectlyGrouped(secondPhysParts, secondPhysParts, true));\n\t\tASSERT_TRUE(pairwiseCorrectlyGrouped(firstPhysParts, secondPhysParts, true));\n\t}\n}\n\n"
  },
  {
    "path": "tests/ecsTests.cpp",
    "content": "#include \"testsMain.h\"\n\n#include <Physics3D/datastructures/smartPointers.h>\n#include \"../engine/ecs/registry.h\"\n#include \"../application/ecs/components.h\"\n\nnamespace P3D {\nTEST_CASE(idGeneration) {\n\tusing namespace P3D::Engine;\n\tRegistry16 registry;\n\tauto id1 = registry.create();\n\tauto id2 = registry.create();\n\tregistry.destroy(id1);\n\tauto id3 = registry.create();\n\n\tASSERT_TRUE(id3 == id1);\n}\n\nTEST_CASE(componentGeneration) {\n\tusing namespace P3D::Engine;\n\tRegistry16 registry;\n\tauto id = registry.create();\n\n\tstruct A : public RC {};\n\tstruct B : public RC {};\n\n\tregistry.add<A>(id);\n\tregistry.add<B>(id);\n\tregistry.remove<A>(id);\n\n\tASSERT_FALSE(registry.has<A>(id));\n\tASSERT_TRUE(registry.has<B>(id));\n}\n\nTEST_CASE(componentAccess) {\n\tusing namespace P3D::Engine;\n\tRegistry16 registry;\n\tauto id = registry.create();\n\n\tstruct A : public RC {\n\t\tint a;\n\t\tfloat b;\n\n\t\tA(int a, float b) : a(a), b(b) {}\n\t};\n\n\tregistry.add<A>(id, 1, 1.2);\n\tASSERT_TRUE(registry.get<A>(id)->a == 1);\n\tASSERT_TOLERANT(registry.get<A>(id)->b == 1.2, 0.000001);\n}\n\n\nTEST_CASE(viewTest) {\n\tstruct A : public RC {};\n\tstruct B : public RC {};\n\tstruct C : public RC {};\n\n\tusing namespace P3D::Engine;\n\tRegistry16 registry;\n\tauto id1 = registry.create();\n\tauto id2 = registry.create();\n\tauto id3 = registry.create();\n\tauto id4 = registry.create();\n\tauto id5 = registry.create();\n\n\tregistry.add<A>(id1);\n\tregistry.add<A>(id2);\n\tregistry.add<A>(id3);\n\tregistry.add<A>(id4);\n\n\tregistry.add<B>(id1);\n\tregistry.add<B>(id3);\n\tregistry.add<B>(id5);\n\n\tregistry.add<C>(id1);\n\tregistry.add<C>(id2);\n\tregistry.add<C>(id3);\n\tregistry.add<C>(id4);\n\tregistry.add<C>(id5);\n\n\tstd::size_t count = 0;\n\tfor(auto _ : registry.view<A, B, C>()) {\n\t\tcount++;\n\t}\n\n\tASSERT_TRUE(count == 2);\n}\n\nTEST_CASE(entityParent) {\n\tusing namespace P3D::Engine;\n\tRegistry16 registry;\n\tauto id1 = registry.create();\n\tauto parent = registry.create();\n\n\tASSERT_TRUE(registry.getParent(id1) == registry.null_entity);\n\n\tid1 = registry.setParent(id1, parent);\n\n\tASSERT_FALSE(registry.getParent(id1) == registry.null_entity);\n}\n\nTEST_CASE(getChildren) {\n\tusing namespace P3D::Engine;\n\tRegistry16 registry;\n\tauto id1 = registry.create();\n\tauto id2 = registry.create();\n\tauto parent = registry.create();\n\n\tid1 = registry.setParent(id1, parent);\n\tid2 = registry.setParent(id2, parent);\n\n\tstd::size_t count = 0;\n\tfor(auto _ : registry.getChildren(parent)) {\n\t\tcount++;\n\t}\n\n\tASSERT_TRUE(count == 2);\n}\n\nTEST_CASE(getFromView) {\n\tusing namespace P3D::Engine;\n\tRegistry16 registry;\n\tauto id = registry.create();\n\n\tstruct A : public RC {\n\t\tint idx = 0;\n\t\tA(int idx) : idx(idx) {}\n\t};\n\n\tregistry.add<A>(id, 1);\n\tregistry.add<A>(id, 2);\n\tregistry.add<A>(id, 3);\n\n\tauto view = registry.view<A>();\n\tfor(auto entity : view) {\n\t\tintrusive_ptr<A> component = view.get<A>(entity);\n\t\tASSERT_TRUE(component->idx > 0 && component->idx < 4);\n\t}\n}\n};\n"
  },
  {
    "path": "tests/estimateMotion.cpp",
    "content": "#include \"estimateMotion.h\"\n\n#include <Physics3D/math/linalg/mat.h>\n#include <Physics3D/math/linalg/trigonometry.h>\n\nnamespace P3D {\nVec3 getVelocityBySimulation(const Motion& m, const Vec3& point, double deltaT) {\n\tRotation rotation = Rotation::fromRotationVector(m.getAngularVelocity() * deltaT);\n\tVec3 delta = m.getVelocity() * deltaT + (rotation * point - point);\n\treturn delta / deltaT;\n}\n\nMotion getMotionBySimulation(const Motion& m, const Vec3& point, double deltaT) {\n\tVec3 mainVel1 = m.getVelocity();\n\tVec3 mainVel2 = mainVel1 + m.getAcceleration() * deltaT;\n\n\tVec3 angularVel2 = m.getAngularVelocity() + m.getAngularAcceleration() * deltaT;\n\tVec3 rotVec1 = m.getAngularVelocity() * deltaT;\n\tVec3 rotVec2 = angularVel2 * deltaT;\n\tRotation rotation1 = Rotation::fromRotationVector(rotVec1);\n\tRotation rotation2 = Rotation::fromRotationVector(rotVec2);\n\n\tVec3 pos0 = point;\n\tVec3 pos1 = mainVel1 * deltaT + rotation1 * pos0;\n\tVec3 pos2 = mainVel2 * deltaT + rotation2 * pos1;\n\n\tVec3 delta1 = pos1 - pos0;\n\tVec3 delta2 = pos2 - pos1;\n\tVec3 vel1 = delta1 / deltaT;\n\tVec3 vel2 = delta2 / deltaT;\n\n\tTranslationalMotion tResult(vel1, (vel2 - vel1) / deltaT);\n\tRotationalMotion rResult(m.getAngularVelocity(), m.getAngularAcceleration());\n\n\treturn Motion(tResult, rResult);\n}\nTranslationalMotion estimateMotion(const Vec3& startPos, const Vec3& midPos, const Vec3& endPos, double stepT) {\n\tVec3 distance1 = midPos - startPos;\n\tVec3 distance2 = endPos - midPos;\n\n\tVec3 velocity1 = distance1 / stepT;\n\tVec3 velocity2 = distance2 / stepT;\n\n\tVec3 acceleration = (velocity2 - velocity1) / stepT;\n\n\treturn TranslationalMotion(velocity1, acceleration);\n}\nTranslationalMotion estimateMotion(const Position& startPos, const Position& midPos, const Position& endPos, double stepT) {\n\tVec3 distance1 = midPos - startPos;\n\tVec3 distance2 = endPos - midPos;\n\n\tVec3 velocity1 = distance1 / stepT;\n\tVec3 velocity2 = distance2 / stepT;\n\n\tVec3 acceleration = (velocity2 - velocity1) / stepT;\n\n\treturn TranslationalMotion(velocity1, acceleration);\n}\n\n// secondRot = delta * firstRot\n// delta = secondRot * ~firstRot\n\nstatic Vec3 getRotationVecFor(const Rotation& firstRot, const Rotation& secondRot) {\n\tRotation delta = secondRot * ~firstRot;\n\n\treturn delta.asRotationVector();\n}\n\nVec3 getRotationVelFor(const Rotation& before, const Rotation& after, double deltaT) {\n\tVec3 rotationVec = getRotationVecFor(before, after);\n\n\treturn rotationVec / deltaT;\n}\n\nMotion estimateMotion(const CFrame& step1, const CFrame& step2, const CFrame& step3, double stepT) {\n\tVec3 vel1 = Vec3(step2.getPosition() - step1.getPosition()) / stepT;\n\tVec3 vel2 = Vec3(step3.getPosition() - step2.getPosition()) / stepT;\n\n\tVec3 rotVel1 = getRotationVelFor(step1.getRotation(), step2.getRotation(), stepT);\n\tVec3 rotVel2 = getRotationVelFor(step2.getRotation(), step3.getRotation(), stepT);\n\n\tVec3 accel = (vel2 - vel1) / stepT;\n\tVec3 rotAccel = (rotVel2 - rotVel1) / stepT;\n\n\treturn Motion(vel1, rotVel1, accel, rotAccel);\n}\n\nMotion estimateMotion(const GlobalCFrame& step1, const GlobalCFrame& step2, const GlobalCFrame& step3, double stepT) {\n\tVec3 vel1 = Vec3(step2.getPosition() - step1.getPosition()) / stepT;\n\tVec3 vel2 = Vec3(step3.getPosition() - step2.getPosition()) / stepT;\n\n\tVec3 rotVel1 = getRotationVelFor(step1.getRotation(), step2.getRotation(), stepT);\n\tVec3 rotVel2 = getRotationVelFor(step2.getRotation(), step3.getRotation(), stepT);\n\n\tVec3 accel = (vel2 - vel1) / stepT;\n\tVec3 rotAccel = (rotVel2 - rotVel1) / stepT;\n\n\treturn Motion(vel1, rotVel1, accel, rotAccel);\n}\n\n\nCFrame simulateForTime(const Motion& motion, const CFrame& startingCFrame, double deltaT) {\n\tMovement mov = motion.getMovementAfterDeltaT(deltaT);\n\n\treturn CFrame(startingCFrame.getPosition() + mov.translation, Rotation::fromRotationVector(mov.rotation) * startingCFrame.getRotation());\n}\n};\n"
  },
  {
    "path": "tests/estimateMotion.h",
    "content": "#pragma once\n\n#include <Physics3D/motion.h>\n#include <Physics3D/math/linalg/vec.h>\n#include <Physics3D/math/position.h>\n#include <Physics3D/math/globalCFrame.h>\n\n#include <utility>\n\nnamespace P3D {\nVec3 getVelocityBySimulation(const Motion& m, const Vec3& point, double deltaT);\nMotion getMotionBySimulation(const Motion& m, const Vec3& point, double deltaT);\nTranslationalMotion estimateMotion(const Vec3& startPos, const Vec3& midPos, const Vec3& endPos, double stepT);\nTranslationalMotion estimateMotion(const Position& startPos, const Position& midPos, const Position& endPos, double stepT);\nVec3 getRotationVelFor(const Rotation& before, const Rotation& after, double deltaT);\nMotion estimateMotion(const CFrame& step1, const CFrame& step2, const CFrame& step3, double stepT);\nMotion estimateMotion(const GlobalCFrame& step1, const GlobalCFrame& step2, const GlobalCFrame& step3, double stepT);\n\nCFrame simulateForTime(const Motion& motion, const CFrame& startingCFrame, double deltaT);\n};\n\n"
  },
  {
    "path": "tests/estimationTests.cpp",
    "content": "#include \"testsMain.h\"\n\n#include \"compare.h\"\n#include <Physics3D/misc/toString.h>\n\n#include <Physics3D/geometry/shape.h>\n#include <Physics3D/geometry/shapeLibrary.h>\n\nusing namespace P3D;\nTEST_CASE_SLOW(volumeApproximation) {\n\tPolyhedron s = ShapeLibrary::house;\n\n\tBoundingBox b = s.getBounds();\n\n\tint sampleCount = 100;\n\n\tdouble dx = (b.max.x - b.min.x) / sampleCount;\n\tdouble dy = (b.max.y - b.min.y) / sampleCount;\n\tdouble dz = (b.max.z - b.min.z) / sampleCount;\n\n\tdouble sampleVolume = dx * dy * dz;\n\n\tlong totalContainedCubes = 0;\n\n\tfor(int xi = 0; xi < sampleCount; xi++) {\n\t\tfor(int yi = 0; yi < sampleCount; yi++) {\n\t\t\tfor(int zi = 0; zi < sampleCount; zi++) {\n\t\t\t\tdouble x = b.min.x + dx * xi + dx / 2;\n\t\t\t\tdouble y = b.min.y + dy * yi + dy / 2;\n\t\t\t\tdouble z = b.min.z + dz * zi + dz / 2;\n\n\t\t\t\tif(s.containsPoint(Vec3(x, y, z))) totalContainedCubes++;\n\t\t\t}\n\t\t}\n\t}\n\n\tdouble estimatedVolume = totalContainedCubes * sampleVolume;\n\n\tASSERT_TOLERANT(estimatedVolume == s.getVolume(), s.getVolume() * 0.001);\n}\n\nTEST_CASE_SLOW(centerOfMassApproximation) {\n\tPolyhedron s = ShapeLibrary::house;\n\n\tBoundingBox b = s.getBounds();\n\n\tint sampleCount = 100;\n\n\tdouble dx = (b.max.x - b.min.x) / sampleCount;\n\tdouble dy = (b.max.y - b.min.y) / sampleCount;\n\tdouble dz = (b.max.z - b.min.z) / sampleCount;\n\n\tdouble sampleVolume = dx * dy * dz;\n\n\tVec3 total = Vec3(0, 0, 0);\n\n\tfor(int xi = 0; xi < sampleCount; xi++) {\n\t\tfor(int yi = 0; yi < sampleCount; yi++) {\n\t\t\tfor(int zi = 0; zi < sampleCount; zi++) {\n\t\t\t\tdouble x = b.min.x + dx * xi + dx / 2;\n\t\t\t\tdouble y = b.min.y + dy * yi + dy / 2;\n\t\t\t\tdouble z = b.min.z + dz * zi + dz / 2;\n\n\t\t\t\tif(s.containsPoint(Vec3(x, y, z))) {\n\t\t\t\t\ttotal += Vec3(x, y, z) * sampleVolume;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tVec3 estimatedCOM = total / s.getVolume();\n\n\tASSERT_TOLERANT(estimatedCOM == s.getCenterOfMass(), (dx + dy + dz) / 3 * 0.01);\n}\n\nTEST_CASE_SLOW(inertiaApproximation) {\n\n\tPolyhedron s = ShapeLibrary::house;\n\n\tBoundingBox b = s.getBounds();\n\n\tint sampleCount = 100;\n\n\tdouble dx = (b.max.x - b.min.x) / sampleCount;\n\tdouble dy = (b.max.y - b.min.y) / sampleCount;\n\tdouble dz = (b.max.z - b.min.z) / sampleCount;\n\n\tdouble sampleVolume = dx * dy * dz;\n\n\tSymmetricMat3 totalInertia = SymmetricMat3::ZEROS();\n\n\tfor(int xi = 0; xi < sampleCount; xi++) {\n\t\tfor(int yi = 0; yi < sampleCount; yi++) {\n\t\t\tfor(int zi = 0; zi < sampleCount; zi++) {\n\t\t\t\tdouble x = b.min.x + dx * xi + dx / 2;\n\t\t\t\tdouble y = b.min.y + dy * yi + dy / 2;\n\t\t\t\tdouble z = b.min.z + dz * zi + dz / 2;\n\n\t\t\t\tif(s.containsPoint(Vec3(x, y, z))) {\n\t\t\t\t\tSymmetricMat3 inertiaOfPoint{\n\t\t\t\t\t\ty * y + z * z,\n\t\t\t\t\t\t-x * y,    x * x + z * z,\n\t\t\t\t\t\t-x * z,     -y * z,   x * x + y * y\n\t\t\t\t\t};\n\t\t\t\t\ttotalInertia += inertiaOfPoint * sampleVolume;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tdouble v = s.getVolume();\n\tASSERT_TOLERANT(totalInertia == s.getInertia(CFrame()), v * v * 0.001);\n}\n"
  },
  {
    "path": "tests/generators.cpp",
    "content": "#include \"generators.h\"\n\n#include <vector>\n\n#include <Physics3D/hardconstraints/motorConstraint.h>\n#include <Physics3D/hardconstraints/sinusoidalPistonConstraint.h>\n\n#include <Physics3D/geometry/convexShapeBuilder.h>\n#include <Physics3D/misc/toString.h>\n\nnamespace P3D {\nstatic std::default_random_engine generator;\n\nint generateInt(int max) {\n\treturn std::uniform_int_distribution<int>(0, max - 1)(generator);\n}\nsize_t generateSize_t(size_t max) {\n\treturn std::uniform_int_distribution<size_t>(0, max - 1)(generator);\n}\ndouble generateDouble() {\n\treturn std::uniform_real_distribution<double>(0.0, 2.0)(generator);\n}\nfloat generateFloat() {\n\treturn std::uniform_real_distribution<float>(0.0f, 2.0f)(generator);\n}\ndouble generateDouble(double min, double max) {\n\treturn std::uniform_real_distribution<double>(min, max)(generator);\n}\nfloat generateFloat(float min, float max) {\n\treturn std::uniform_real_distribution<float>(min, max)(generator);\n}\n\nbool generateBool() {\n\treturn std::uniform_int_distribution<int>(0, 1)(generator) == 1;\n}\n\nShape generateShape() {\n\treturn boxShape(generateDouble(), generateDouble(), generateDouble());\n}\n\nPolyhedron generateConvexPolyhedron() {\n\tconstexpr size_t MAX_POINT_COINT = 50;\n\tVec3f vecBuf[MAX_POINT_COINT * 10]{generateVec3f(), generateVec3f(), generateVec3f(), generateVec3f()};\n\tif((vecBuf[1] - vecBuf[0]) % (vecBuf[2] - vecBuf[0]) * vecBuf[3] > 0) {\n\t\tfor(int i = 0; i < 4; i++) {\n\t\t\tvecBuf[i].z = -vecBuf[i].z;\n\t\t}\n\t}\n\tTriangle triangleBuf[MAX_POINT_COINT * 2 * 10]{{0,1,2}, {0,2,3}, {0,3,1}, {3,2,1}};\n\tTriangleNeighbors neighborBuf[MAX_POINT_COINT * 2 * 10];\n\tint removalBuf[MAX_POINT_COINT * 2 * 10];\n\tEdgePiece edgeBuf[MAX_POINT_COINT * 4 * 10];\n\n\tConvexShapeBuilder builder(vecBuf, triangleBuf, 4, 4, neighborBuf, removalBuf, edgeBuf);\n\n\tint numExtraPoints = generateInt(MAX_POINT_COINT - 4);\n\tfor(int i = 0; i < numExtraPoints; i++) {\n\t\tbuilder.addPoint(generateVec3f());\n\t}\n\n\treturn builder.toPolyhedron();\n}\n\nstatic Triangle finishTriangle(int maxIndex, int firstIndex) {\n\tint secondIndex, thirdIndex;\n\n\tdo {\n\t\tsecondIndex = generateInt(maxIndex);\n\t} while(secondIndex == firstIndex);\n\n\tdo {\n\t\tthirdIndex = generateInt(maxIndex);\n\t} while(thirdIndex == firstIndex || thirdIndex == secondIndex);\n\n\treturn Triangle{firstIndex, secondIndex, thirdIndex};\n}\n\nTriangle generateTriangle(int maxIndex) {\n\tint firstIndex = generateInt(maxIndex);\n\n\treturn finishTriangle(maxIndex, firstIndex);\n}\n\nTriangleMesh generateTriangleMesh() {\n\tint numVertices = generateInt(46) + 4;\n\tint numTriangles = generateInt(100) + numVertices;\n\tEditableMesh mesh(numVertices, numTriangles);\n\n\tfor(int i = 0; i < numVertices; i++) {\n\t\tmesh.setVertex(i, generateVec3f());\n\t}\n\n\tfor(int i = 0; i < numVertices; i++) {\n\t\tmesh.setTriangle(i, finishTriangle(numVertices, i)); // ensure one triangle per vertex\n\t}\n\n\tfor(int i = numVertices; i < numTriangles; i++) {\n\t\tmesh.setTriangle(i, generateTriangle(numVertices)); // extra triangles\n\t}\n\n\treturn TriangleMesh(std::move(mesh));\n}\n\nPositionTemplate<float> generatePositionf() {\n\treturn PositionTemplate<float>(generateFloat(), generateFloat(), generateFloat());\n}\n\nPosition generatePosition() {\n\treturn Position(generateDouble(), generateDouble(), generateDouble());\n}\n\nBoundsTemplate<float> generateBoundsf() {\n\tPositionTemplate<float> a = generatePositionf();\n\tPositionTemplate<float> b = generatePositionf();\n\n\treturn BoundsTemplate<float>(PositionTemplate<float>(std::min(a.x, b.x), std::min(a.y, b.y), std::min(a.z, b.z)), PositionTemplate<float>(std::max(a.x, b.x), std::max(a.y, b.y), std::max(a.z, b.z)));\n}\n\nBounds generateBounds() {\n\tPosition a = generatePosition();\n\tPosition b = generatePosition();\n\n\treturn Bounds(Position(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z)), Position(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z)));\n}\n\nDiagonalMat3 generateDiagonalMatrix() {\n\treturn DiagonalMat3();\n}\n\nRotation generateRotation() {\n\treturn Rotation::fromEulerAngles(generateDouble() * 1.507075, generateDouble() * 1.507075, generateDouble() * 1.507075);\n}\n\nCFrame generateCFrame() {\n\treturn CFrame(generateVec3(), generateRotation());\n}\n\nGlobalCFrame generateGlobalCFrame() {\n\treturn GlobalCFrame(generatePosition(), generateRotation());\n}\n\n\nTranslationalMotion generateTranslationalMotion() {\n\treturn TranslationalMotion(generateTaylor<2>(generateVec3));\n}\nRotationalMotion generateRotationalMotion() {\n\treturn RotationalMotion(generateTaylor<2>(generateVec3));\n}\nMotion generateMotion() {\n\treturn Motion(generateTranslationalMotion(), generateRotationalMotion());\n}\nRelativeMotion generateRelativeMotion() {\n\treturn RelativeMotion(generateMotion(), generateCFrame());\n}\n\n\nPartProperties generatePartProperties() {\n\treturn PartProperties{generateDouble(),generateDouble(),generateDouble()};\n}\nPart generatePart() {\n\treturn Part(generateShape(), generateGlobalCFrame(), generatePartProperties());\n}\n\nPart generatePart(Part& attachTo) {\n\treturn Part(generateShape(), attachTo, generateCFrame(), generatePartProperties());\n}\n\nPart generatePart(Part& attachTo, HardConstraint* constraint) {\n\treturn Part(generateShape(), attachTo, constraint, generateCFrame(), generateCFrame(), generatePartProperties());\n}\n\nHardConstraint* generateHardConstraint() {\n\treturn new MotorConstraintTemplate<ConstantMotorTurner>(generateDouble());\n}\n\nvoid generateAttachment(Part& first, Part& second) {\n\tif(generateBool()) {\n\t\tfirst.attach(&second, generateCFrame());\n\t} else {\n\t\tfirst.attach(&second, generateHardConstraint(), generateCFrame(), generateCFrame());\n\t}\n}\n\nstd::vector<Part> generateMotorizedPhysicalParts() {\n\t//int size = int(std::sqrt(rand() % 1000)) + 1;\n\n\tint size = rand() % 5 + 1;\n\tstd::vector<Part> parts(size);\n\tparts[0] = generatePart();\n\tif(generateBool()) parts[0].ensureHasPhysical();\n\n\tfor(int i = 1; i < size; i++) {\n\t\tparts[i] = generatePart();\n\t\tgenerateAttachment(parts[i], parts[rand() % i]);\n\t}\n\n\treturn parts;\n}\n\nvoid generateLayerAssignment(std::vector<Part>& parts, WorldPrototype& world) {\n\tstd::vector<Part*> layerParts(world.layers.size(), nullptr);\n\n\tint selectedSubLayer = rand() % ColissionLayer::NUMBER_OF_SUBLAYERS;\n\tfor(Part& curPart : parts) {\n\t\tint selectedLayer = rand() % world.layers.size();\n\t\tWorldLayer& addTo = world.layers[selectedLayer].subLayers[selectedSubLayer];\n\t\tif(layerParts[selectedLayer] == nullptr) {\n\t\t\taddTo.tree.add(&curPart);\n\t\t\tlayerParts[selectedLayer] = &curPart;\n\t\t} else {\n\t\t\taddTo.tree.addToGroup(&curPart, layerParts[selectedLayer]);\n\t\t}\n\t\tcurPart.layer = &addTo;\n\t}\n}\n\n};"
  },
  {
    "path": "tests/generators.h",
    "content": "#pragma once\n\n#include <random>\n#include <utility>\n#include <cstdint>\n\n#include <Physics3D/math/linalg/vec.h>\n#include <Physics3D/math/linalg/mat.h>\n#include <Physics3D/math/rotation.h>\n#include <Physics3D/math/cframe.h>\n#include <Physics3D/math/globalCFrame.h>\n#include <Physics3D/math/position.h>\n#include <Physics3D/math/bounds.h>\n#include <Physics3D/math/fix.h>\n#include <Physics3D/math/taylorExpansion.h>\n#include <Physics3D/geometry/shape.h>\n#include <Physics3D/geometry/shapeCreation.h>\n#include <Physics3D/geometry/polyhedron.h>\n#include <Physics3D/motion.h>\n#include <Physics3D/relativeMotion.h>\n\n#include <Physics3D/part.h>\n#include <Physics3D/physical.h>\n#include <Physics3D/hardconstraints/hardConstraint.h>\n#include <Physics3D/layer.h>\n#include <Physics3D/world.h>\n\n#include <Physics3D/boundstree/boundsTree.h>\n\nnamespace P3D {\ntemplate<typename T>\nT generate() {\n\tthrow \"Unsupported generate type!\";\n}\n\n// generates between -2.0 and 2.0\ntemplate<>\ninline double generate() {\n\treturn rand() * 4.0 / RAND_MAX - 2.0;\n}\n// generates between -2.0 and 2.0\ntemplate<>\ninline float generate() {\n\treturn rand() * 4.0f / RAND_MAX - 2.0f;\n}\ntemplate<>\ninline int8_t generate() {\n\treturn (rand() % 200) - 100;\n}\ntemplate<>\ninline uint8_t generate() {\n\treturn uint8_t(rand()) & 0xFF;\n}\ntemplate<>\ninline int16_t generate() {\n\treturn (rand() % 200) - 100;\n}\ntemplate<>\ninline uint16_t generate() {\n\treturn rand() % 100;\n}\ntemplate<>\ninline int32_t generate() {\n\treturn (rand() % 200) - 100;\n}\ntemplate<>\ninline uint32_t generate() {\n\treturn rand() % 100;\n}\ntemplate<>\ninline int64_t generate() {\n\treturn (rand() % 200) - 100;\n}\ntemplate<>\ninline uint64_t generate() {\n\treturn rand() % 100;\n}\n\nint generateInt(int max);\nsize_t generateSize_t(size_t max);\ndouble generateDouble();\nfloat generateFloat();\ndouble generateDouble(double min, double max);\nfloat generateFloat(float min, float max);\nbool generateBool();\nShape generateShape();\nPolyhedron generateConvexPolyhedron();\nTriangleMesh generateTriangleMesh();\ntemplate<typename T, std::size_t Size>\nVector<T, Size> generateVector() {\n\tVector<T, Size> result;\n\n\tfor(std::size_t i = 0; i < Size; i++) {\n\t\tresult[i] = generate<T>();\n\t}\n\n\treturn result;\n}\ntemplate<typename T, std::size_t Height, std::size_t Width>\nMatrix<T, Height, Width> generateMatrix() {\n\tMatrix<T, Height, Width> result;\n\n\tfor(std::size_t i = 0; i < Height; i++) {\n\t\tfor(std::size_t j = 0; j < Width; j++) {\n\t\t\tresult(i, j) = generate<T>();\n\t\t}\n\t}\n\n\treturn result;\n}\ninline Vec3 generateVec3() { return generateVector<double, 3>(); }\ninline Vec3f generateVec3f() { return generateVector<float, 3>(); }\nTriangle generateTriangle(int maxIndex);\nPosition generatePosition();\nBounds generateBounds();\nBoundsTemplate<float> generateBoundsf();\nPositionTemplate<float> generatePositionf();\nRotation generateRotation();\nCFrame generateCFrame();\nGlobalCFrame generateGlobalCFrame();\ntemplate<int Derivatives, typename ItemGenerator>\nauto generateTaylor(ItemGenerator itemGenerator) -> TaylorExpansion<decltype(itemGenerator()), Derivatives> {\n\tTaylorExpansion<decltype(itemGenerator()), Derivatives> result;\n\n\tfor(auto& item : result) {\n\t\titem = itemGenerator();\n\t}\n\n\treturn result;\n}\ntemplate<int Derivatives, typename ItemGenerator>\nauto generateFullTaylor(ItemGenerator itemGenerator) -> FullTaylorExpansion<decltype(itemGenerator()), Derivatives> {\n\tFullTaylorExpansion<decltype(itemGenerator()), Derivatives> result;\n\n\tfor(auto& item : result) {\n\t\titem = itemGenerator();\n\t}\n\n\treturn result;\n}\nTranslationalMotion generateTranslationalMotion();\nRotationalMotion generateRotationalMotion();\nMotion generateMotion();\nRelativeMotion generateRelativeMotion();\nPartProperties generatePartProperties();\nPart generatePart();\nPart generatePart(Part& attachTo);\nPart generatePart(Part& attachTo, HardConstraint* constraint);\nHardConstraint* generateHardConstraint();\nvoid generateAttachment(Part& first, Part& second);\nstd::vector<Part> generateMotorizedPhysicalParts();\nvoid generateLayerAssignment(std::vector<Part>& parts, WorldPrototype& world);\ntemplate<typename Collection>\nauto oneOf(const Collection& collection) -> decltype(collection[0]) {\n\treturn collection[generateSize_t(collection.size())];\n}\ntemplate<typename Collection>\nauto oneOf(Collection& collection) -> decltype(collection[0]) {\n\treturn collection[generateSize_t(collection.size())];\n}\ntemplate<typename T, size_t size>\nDiagonalMatrix<T, size> generateDiagonalMatrix() {\n\tT buf[size];\n\tfor(size_t i = 0; i < size; i++) {\n\t\tbuf[i] = generate<T>();\n\t}\n\treturn DiagonalMatrix<T, size>(buf);\n}\n};\n"
  },
  {
    "path": "tests/geometryTests.cpp",
    "content": "#include \"testsMain.h\"\n\n#include \"compare.h\"\n#include <Physics3D/misc/toString.h>\n\n#include <Physics3D/math/linalg/vec.h>\n#include <Physics3D/math/linalg/mat.h>\n#include <Physics3D/math/linalg/trigonometry.h>\n#include <Physics3D/math/linalg/eigen.h>\n#include <Physics3D/math/utils.h>\n#include <Physics3D/math/boundingBox.h>\n\n#include <Physics3D/geometry/shape.h>\n\n#include <Physics3D/geometry/shapeLibrary.h>\n\n#include \"testValues.h\"\n#include \"generators.h\"\n\n#include <Physics3D/misc/cpuid.h>\n#include <Physics3D/geometry/builtinShapeClasses.h>\n\nusing namespace P3D;\n#define ASSERT(condition) ASSERT_TOLERANT(condition, 0.00001)\n\ntemplate<typename T, typename Tol, size_t Size>\nbool isDiagonalTolerant(const Matrix<T, Size, Size>& m, Tol tolerance) {\n\tfor(size_t row = 0; row < Size; row++) {\n\t\tfor(size_t col = 0; col < Size; col++) {\n\t\t\tif(row == col) continue;\n\t\t\tif(!tolerantEquals<T>(m[row][col], 0, tolerance)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n\treturn true;\n}\ntemplate<typename T, typename Tol, size_t Size>\nbool isDiagonalTolerant(const SymmetricMatrix<T, Size>& m, Tol tolerance) {\n\tfor(size_t row = 0; row < Size - 1; row++) {\n\t\tfor(size_t col = row + 1; col < Size; col++) {\n\t\t\tif(!tolerantEquals<T>(m[row][col], 0, tolerance)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n\treturn true;\n}\n\ntemplate<typename T, typename Tol, size_t Size>\nbool isSymmetricTolerant(const Matrix<T, Size, Size>& m, Tol tolerance) {\n\tfor(size_t row = 0; row < Size - 1; row++) {\n\t\tfor(size_t col = row + 1; col < Size; col++) {\n\t\t\tif(!tolerantEquals<T>(m[row][col], m[col][row], tolerance)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n\treturn true;\n}\n\n#define ASSERT_DIAGONAL_TOLERANT(matrix, tolerance) if(!isDiagonalTolerant(matrix, tolerance)) throw AssertionError(__LINE__, errMsg(matrix))\n#define ASSERT_DIAGONAL(matrix) ASSERT_DIAGONAL_TOLERANT(matrix, 0.00000001)\n\nTEST_CASE(shapeVolume) {\n\tPolyhedron boxShape = ShapeLibrary::createBox(2, 2, 2);\n\n\tCFramef transform(Vec3f(0.3f, 0.7f, -3.5f), Rotationf::fromEulerAngles(0.7f, 0.2f, 0.3f));\n\n\tPolyhedron transformedShape = boxShape.localToGlobal(transform);\n\n\tASSERT(boxShape.getVolume() == transformedShape.getVolume());\n\tASSERT(boxShape.getVolume() == 8.0);\n}\n\nTEST_CASE(shapeCenterOfMass) {\n\tPolyhedron boxShape = ShapeLibrary::createBox(2.0, 2.0, 2.0);\n\n\tCFramef transform(Vec3f(0.3f, 0.7f, -3.5f), Rotationf::fromEulerAngles(0.7f, 0.2f, 0.3f));\n\n\tPolyhedron transformedShape = boxShape.localToGlobal(transform);\n\n\tASSERT(transform.localToGlobal(boxShape.getCenterOfMass()) == transformedShape.getCenterOfMass());\n}\n\n/*TEST_CASE(shapeInertiaMatrix) {\n\tPolyhedron boxShape = ShapeLibrary::createBox(2.0, 2.0, 2.0);\n\n\tCFramef transform(Vec3f(0,0,0), rotationMatrixfromEulerAngles(0.7f, 0.2f, 0.3f));\n\tPolyhedron transformedShape = boxShape.localToGlobal(transform);\n\n\tlogf(\"Inertia of boxShape: %s\", str(boxShape.getInertiaAroundCenterOfMass()).c_str());\n\n\tlogf(\"Inertia of transformed boxShape: %s\", str(transformedShape.getInertiaAroundCenterOfMass()).c_str());\n\n\tPolyhedron h = ShapeLibrary::house;\n\tPolyhedron newHouse = ShapeLibrary::house.translated(-Vec3f(ShapeLibrary::house.getCenterOfMass()));\n\tPolyhedron rotatedHouse = newHouse.rotated(rotationMatrixfromEulerAngles(0.0, 0.3, 0.0));\n\tlogf(\"Inertia of House: %s\", str(newHouse.getInertiaAroundCenterOfMass()).c_str());\n\tlogf(\"Inertia of Rotated House: %s\", str(rotatedHouse.getInertiaAroundCenterOfMass()).c_str());\n}*/\n\nTEST_CASE(shapeInertiaRotationInvariance) {\n\tPolyhedron testShape = ShapeLibrary::house.translated(-Vec3f(ShapeLibrary::house.getCenterOfMass()));\n\n\tVec3 testMoment = Vec3(0.7, -3.2, 4.8);\n\tVec3 momentResult = ~testShape.getInertiaAroundCenterOfMass() * testMoment;\n\n\tlogStream << \"Center Of Mass: \" << testShape.getCenterOfMass() << '\\n';\n\n\tlogStream << \"reference inertia: \" << testShape.getInertiaAroundCenterOfMass() << \"\\n\";\n\n\tlogStream << \"Inertial eigenValues: \" << getEigenDecomposition(testShape.getInertiaAroundCenterOfMass()).eigenValues.asDiagonalMatrix() << \"\\n\";\n\n\tfor(const Rotation& testRotation : rotations) {\n\n\n\t\tPolyhedron rotatedShape = testShape.rotated(static_cast<Rotationf>(testRotation));\n\n\t\tVec3 rotatedTestMoment = testRotation * testMoment;\n\n\t\tSymmetricMat3 inertia = rotatedShape.getInertiaAroundCenterOfMass();\n\n\t\tVec3 rotatedMomentResult = ~inertia * rotatedTestMoment;\n\n\n\t\tlogStream << \"testRotation: \" << testRotation << \"\\ninertia: \" << inertia << \"\\n\";\n\n\t\tlogStream << \"Inertial eigenValues: \" << getEigenDecomposition(inertia).eigenValues.asDiagonalMatrix() << \"\\n\";\n\n\t\tASSERT(rotatedMomentResult == testRotation * momentResult);\n\t}\n}\n\nTEST_CASE(shapeInertiaEigenValueInvariance) {\n\tPolyhedron testShape = ShapeLibrary::house.translated(-Vec3f(ShapeLibrary::house.getCenterOfMass()));\n\n\tEigenValues<double, 3> initialEigenValues = getEigenDecomposition(testShape.getInertiaAroundCenterOfMass()).eigenValues;\n\n\tfor(Rotation testRotation : rotations) {\n\t\tlogStream << testRotation << '\\n';\n\n\t\tPolyhedron rotatedShape = testShape.rotated(static_cast<Rotationf>(testRotation));\n\n\t\tEigenValues<double, 3> newEigenValues = getEigenDecomposition(rotatedShape.getInertiaAroundCenterOfMass()).eigenValues;\n\n\t\tASSERT(initialEigenValues == newEigenValues);\n\t}\n}\n\nTEST_CASE(testRayIntersection) {\n\tASSERT_TRUE(rayTriangleIntersection(Vec3(-1.0, 0.3, 0.3), Vec3(1.0, 0.0, 0.0), Vec3(), Vec3(0.0, 0.0, 1.0), Vec3(0.0, 1.0, 0.0)).rayIntersectsTriangle());\n\tASSERT_FALSE(rayTriangleIntersection(Vec3(-1.0, -0.3, 0.3), Vec3(1.0, 0.0, 0.0), Vec3(), Vec3(0.0, 0.0, 1.0), Vec3(0.0, 1.0, 0.0)).rayIntersectsTriangle());\n\tASSERT_FALSE(rayTriangleIntersection(Vec3(-1.0, 0.3, -0.3), Vec3(1.0, 0.0, 0.0), Vec3(), Vec3(0.0, 0.0, 1.0), Vec3(0.0, 1.0, 0.0)).rayIntersectsTriangle());\n\tASSERT_FALSE(rayTriangleIntersection(Vec3(-1.0, -0.3, -0.3), Vec3(1.0, 0.0, 0.0), Vec3(), Vec3(0.0, 0.0, 1.0), Vec3(0.0, 1.0, 0.0)).rayIntersectsTriangle());\n}\n\nTEST_CASE(testGetFurthestPointInDirection) {\n\tfor(Vec3f vertex : ShapeLibrary::icosahedron.iterVertices()) {\n\t\tASSERT(ShapeLibrary::icosahedron.furthestInDirection(vertex) == vertex);\n\t}\n}\n\nTEST_CASE(testCornerShape) {\n\tfor(int i = 0; i < 10000; i++) {\n\t\tVec3 direction = generateVec3();\n\t\tVec3 point = generateVec3();\n\t\tVec3 origin = generateVec3();\n\t\tRotation rotation = generateRotation();\n\t\tDiagonalMat3 scale = generateDiagonalMatrix<double, 3>();\n\n\t\tASSERT(CornerClass::instance.asPolyhedron().furthestInDirectionFallback(direction) == CornerClass::instance.furthestInDirection(direction));\n\t\tASSERT(CornerClass::instance.asPolyhedron().getScaledMaxRadiusSq(scale) == CornerClass::instance.getScaledMaxRadiusSq(scale));\n\t\tASSERT(CornerClass::instance.asPolyhedron().containsPoint(point) == CornerClass::instance.containsPoint(point));\n\t\tASSERT(CornerClass::instance.asPolyhedron().getIntersectionDistance(origin, direction) == CornerClass::instance.getIntersectionDistance(origin, direction));\n\t\tASSERT(CornerClass::instance.asPolyhedron().getBounds(Mat3f(rotation.asRotationMatrix() * scale)) == CornerClass::instance.getBounds(rotation, scale));\n\t}\n}\n\nTEST_CASE(testWedgeShape) {\n\tfor(int i = 0; i < 10000; i++) {\n\t\tVec3 direction = generateVec3();\n\t\tVec3 point = generateVec3();\n\t\tVec3 origin = generateVec3();\n\t\tRotation rotation = generateRotation();\n\t\tDiagonalMat3 scale = generateDiagonalMatrix<double, 3>();\n\t\t\n\t\tASSERT(WedgeClass::instance.asPolyhedron().furthestInDirectionFallback(direction) == WedgeClass::instance.furthestInDirection(direction));\n\t\tASSERT(WedgeClass::instance.asPolyhedron().getBounds(Mat3f(rotation.asRotationMatrix() * scale)) == WedgeClass::instance.getBounds(rotation, scale));\n\t\tASSERT(WedgeClass::instance.asPolyhedron().getScaledMaxRadiusSq(scale) == WedgeClass::instance.getScaledMaxRadiusSq(scale));\n\t\tASSERT(WedgeClass::instance.asPolyhedron().containsPoint(point) == WedgeClass::instance.containsPoint(point));\n\t\tASSERT(WedgeClass::instance.asPolyhedron().getIntersectionDistance(origin, direction) == WedgeClass::instance.getIntersectionDistance(origin, direction));\n\t}\n}\n\nTEST_CASE(testTriangleMeshOptimizedGetBounds) {\n\tfor(int iter = 0; iter < 1000; iter++) {\n\t\tTriangleMesh mesh = generateTriangleMesh();\n\t\tlogStream << \"NewPoly: \" << mesh.vertexCount << \" vertices, \" << mesh.triangleCount << \" triangles\\n\";\n\t\tfor(int i = 0; i < mesh.vertexCount; i++) {\n\t\t\tlogStream << mesh.getVertex(i) << \"\\n\";\n\t\t}\n\t\tBoundingBox reference = mesh.getBoundsFallback();\n\n\t\tif(CPUIDCheck::hasTechnology(CPUIDCheck::SSE | CPUIDCheck::SSE2)) {\n\t\t\tASSERT(reference == mesh.getBoundsSSE());\n\t\t}\n\n\t\tif(CPUIDCheck::hasTechnology(CPUIDCheck::AVX | CPUIDCheck::AVX2 | CPUIDCheck::FMA)) {\n\t\t\tASSERT(reference == mesh.getBoundsAVX());\n\t\t}\n\t}\n}\n\nTEST_CASE(testTriangleMeshOptimizedGetBoundsRotated) {\n\tfor(int iter = 0; iter < 1000; iter++) {\n\t\tTriangleMesh mesh = generateTriangleMesh();\n\t\tlogStream << \"NewPoly: \" << mesh.vertexCount << \" vertices, \" << mesh.triangleCount << \" triangles\\n\";\n\t\tfor(int i = 0; i < mesh.vertexCount; i++) {\n\t\t\tlogStream << mesh.getVertex(i) << \"\\n\";\n\t\t}\n\t\tMat3f rot = generateMatrix<float, 3, 3>();\n\t\tBoundingBox reference = mesh.getBoundsFallback(rot);\n\n\t\tif(CPUIDCheck::hasTechnology(CPUIDCheck::SSE | CPUIDCheck::SSE2)) {\n\t\t\tASSERT(reference == mesh.getBoundsSSE(rot));\n\t\t}\n\n\t\tif(CPUIDCheck::hasTechnology(CPUIDCheck::AVX | CPUIDCheck::AVX2 | CPUIDCheck::FMA)) {\n\t\t\tASSERT(reference == mesh.getBoundsAVX(rot));\n\t\t}\n\t}\n}\n\nTEST_CASE(testTriangleMeshOptimizedFurthestIndexInDirection) {\n\tfor(int iter = 0; iter < 1000; iter++) {\n\t\tTriangleMesh mesh = generateTriangleMesh();\n\t\tlogStream << \"NewPoly: \" << mesh.vertexCount << \" vertices, \" << mesh.triangleCount << \" triangles\\n\";\n\t\tfor(int i = 0; i < mesh.vertexCount; i++) {\n\t\t\tlogStream << mesh.getVertex(i) << \"\\n\";\n\t\t}\n\t\tVec3 dir = generateVec3();\n\t\tint reference = mesh.furthestIndexInDirectionFallback(dir);\n\t\tlogStream << \"reference: \" << reference << \"\\n\";\n\n\t\tif(CPUIDCheck::hasTechnology(CPUIDCheck::SSE | CPUIDCheck::SSE2)) {\n\t\t\tint sseVertex = mesh.furthestIndexInDirectionSSE(dir);\n\t\t\tlogStream << \"sseVertex: \" << sseVertex << \"\\n\";\n\t\t\tASSERT(mesh.getVertex(reference) * dir == mesh.getVertex(sseVertex) * dir);\n\t\t}\n\n\t\tif(CPUIDCheck::hasTechnology(CPUIDCheck::SSE | CPUIDCheck::SSE2 | CPUIDCheck::SSE4_1)) {\n\t\t\tint sse4Vertex = mesh.furthestIndexInDirectionSSE4(dir);\n\t\t\tlogStream << \"sse4Vertex: \" << sse4Vertex << \"\\n\";\n\t\t\tASSERT(mesh.getVertex(reference) * dir == mesh.getVertex(sse4Vertex) * dir);\n\t\t}\n\n\t\tif(CPUIDCheck::hasTechnology(CPUIDCheck::AVX | CPUIDCheck::AVX2 | CPUIDCheck::FMA)) {\n\t\t\tint avxVertex = mesh.furthestIndexInDirectionAVX(dir);\n\t\t\tlogStream << \"avxVertex: \" << avxVertex << \"\\n\";\n\t\t\tASSERT(mesh.getVertex(reference) * dir == mesh.getVertex(avxVertex) * dir);\n\t\t}\n\t}\n}\nTEST_CASE(testTriangleMeshOptimizedFurthestInDirection) {\n\tfor(int iter = 0; iter < 1000; iter++) {\n\t\tTriangleMesh mesh = generateTriangleMesh();\n\t\tlogStream << \"NewPoly: \" << mesh.vertexCount << \" vertices, \" << mesh.triangleCount << \" triangles\\n\";\n\t\tfor(int i = 0; i < mesh.vertexCount; i++) {\n\t\t\tlogStream << mesh.getVertex(i) << \"\\n\";\n\t\t}\n\t\tVec3 dir = generateVec3();\n\t\tVec3 reference = mesh.furthestInDirectionFallback(dir);\n\t\tlogStream << \"reference: \" << reference << \"\\n\";\n\n\t\tif(CPUIDCheck::hasTechnology(CPUIDCheck::SSE | CPUIDCheck::SSE2)) {\n\t\t\tVec3f sseVertex = mesh.furthestInDirectionSSE(dir);\n\t\t\tlogStream << \"sseVertex: \" << sseVertex << \"\\n\";\n\t\t\tASSERT(reference * dir == sseVertex * dir); // dot with dir as we don't really care for the exact vertex in a tie\n\t\t}\n\n\t\tif(CPUIDCheck::hasTechnology(CPUIDCheck::SSE | CPUIDCheck::SSE2 | CPUIDCheck::SSE4_1)) {\n\t\t\tVec3f sse4Vertex = mesh.furthestInDirectionSSE4(dir);\n\t\t\tlogStream << \"sse4Vertex: \" << sse4Vertex << \"\\n\";\n\t\t\tASSERT(reference * dir == sse4Vertex * dir); // dot with dir as we don't really care for the exact vertex in a tie\n\t\t}\n\n\t\tif(CPUIDCheck::hasTechnology(CPUIDCheck::AVX | CPUIDCheck::AVX2 | CPUIDCheck::FMA)) {\n\t\t\tVec3f avxVertex = mesh.furthestInDirectionAVX(dir);\n\t\t\tlogStream << \"avxVertex: \" << avxVertex << \"\\n\";\n\t\t\tASSERT(reference * dir == avxVertex * dir); // dot with dir as we don't really care for the exact vertex in a tie\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "tests/guiTests.cpp",
    "content": "#include \"testsMain.h\"\n\n#include \"compare.h\"\n#include <Physics3D/misc/toString.h>\n\n#include <Physics3D/math/linalg/mat.h>\n#include <Physics3D/math/linalg/vec.h>\n\n#include <Physics3D/math/mathUtil.h>\n#include <Physics3D/math/linalg/trigonometry.h>\n\n#include <string>\n#include <vector>\n\nusing namespace P3D;\nTEST_CASE(transformationTest) {\n\tMat4f viewMatrix = Mat4f::IDENTITY();\n\tMat4f projectionMatrix = perspective(1, 2, 0.1f, 100);\n\n\tMat4f inverseViewMatrix = ~viewMatrix;\n\tMat4f inverseProjectionMatrix = ~projectionMatrix;\n\n\tVec4f point = Vec4f(1.0, 2.0, 3.0, 1.0);\n\tVec4f transformedPoint = projectionMatrix * viewMatrix * point;\n\tVec4f transformedBack = inverseViewMatrix * inverseProjectionMatrix * transformedPoint;\n\n\tASSERT_TOLERANT(point == transformedBack, 0.000001);\n}\n"
  },
  {
    "path": "tests/indexedShapeTests.cpp",
    "content": "#include \"testsMain.h\"\n\n#include \"compare.h\"\n#include <Physics3D/misc/toString.h>\n\n#include <Physics3D/geometry/indexedShape.h>\n#include <Physics3D/geometry/shapeBuilder.h>\n#include <Physics3D/geometry/convexShapeBuilder.h>\n#include <Physics3D/geometry/shapeLibrary.h>\n#include <Physics3D/misc/validityHelper.h>\n\nusing namespace P3D;\nTEST_CASE(testIndexedShape) {\n\tVec3f verts[]{Vec3f(0.0, 0.0, 0.0), Vec3f(1.0, 0.0, 0.0), Vec3f(0.0, 0.0, 1.0), Vec3f(0.0, 1.0, 0.0)};\n\tTriangle triangles[]{{0,1,2},{0,3,1},{0,2,3},{1,3,2}};\n\n\tTriangleNeighbors neighBuf[4];\n\n\tfillNeighborBuf(triangles, 4, neighBuf);\n\n\tIndexedShape s(verts, triangles, 4, 4, neighBuf);\n\n\tASSERT_TRUE(isValid(s));\n}\n\nTEST_CASE(buildShape) {\n\tVec3f verts[10]{Vec3f(0.0, 0.0, 0.0), Vec3f(1.0, 0.0, 0.0), Vec3f(0.0, 0.0, 1.0), Vec3f(0.0, 1.0, 0.0)};\n\tTriangle triangles[20]{{0,1,2},{0,3,1},{0,2,3},{1,3,2}};\n\tTriangleNeighbors neighBuf[20];\n\n\tShapeBuilder b(verts, triangles, 4, 4, neighBuf);\n\n\tb.addPoint(Vec3f(1, 1, 1), 3);\n\n\tIndexedShape result = b.toIndexedShape();\n\n\tASSERT_TRUE(isValid(result));\n}\n\nTEST_CASE(buildConvexShape) {\n\tint builderRemovalBuffer[1000];\n\tEdgePiece builderAddingBuffer[1000];\n\n\tVec3f verts[10]{Vec3f(0.0, 0.0, 0.0), Vec3f(1.0, 0.0, 0.0), Vec3f(0.0, 0.0, 1.0), Vec3f(0.0, 1.0, 0.0)};\n\tTriangle triangles[20]{{0,1,2},{0,3,1},{0,2,3},{1,3,2}};\n\tTriangleNeighbors neighBuf[20];\n\n\tPolyhedron simpleTetrahedron(verts, triangles, 4, 4);\n\n\tASSERT_TRUE(isValid(simpleTetrahedron));\n\n\tConvexShapeBuilder builder(verts, triangles, 4, 4, neighBuf, builderRemovalBuffer, builderAddingBuffer);\n\n\tbuilder.addPoint(Vec3f(-1, 10, -1), 3);\n\n\tASSERT_TRUE(isValid(builder.toIndexedShape()));\n\n\tVec3f verts2[10]{Vec3f(0.0, 0.0, 0.0), Vec3f(1.0, 0.0, 0.0), Vec3f(0.0, 0.0, 1.0), Vec3f(0.0, 1.0, 0.0)};\n\tTriangle triangles2[20]{{0,1,2},{0,3,1},{0,2,3},{1,3,2}};\n\tTriangleNeighbors neighBuf2[20];\n\n\tPolyhedron simpleTetrahedron2(verts2, triangles2, 4, 4);\n\n\tASSERT_TRUE(isValid(simpleTetrahedron2));\n\n\tConvexShapeBuilder builder2(verts2, triangles2, 4, 4, neighBuf2, builderRemovalBuffer, builderAddingBuffer);\n\n\tbuilder2.addPoint(Vec3f(0.4f, 0.4f, 0.4f), 3);\n\n\tASSERT_TRUE(isValid(builder2.toIndexedShape()));\n\n\tbuilder2.addPoint(Vec3f(-0.5f, 50.0f, -0.5f), 3);\n\n\tASSERT_TRUE(isValid(builder2.toIndexedShape()));\n\n\tVec3f newIcosaVerts[30];\n\tTriangle newIcosaTriangles[40];\n\tTriangleNeighbors icosaNeighBuf[40];\n\n\tConvexShapeBuilder icosaBuilder(ShapeLibrary::icosahedron, newIcosaVerts, newIcosaTriangles, icosaNeighBuf, builderRemovalBuffer, builderAddingBuffer);\n\n\tASSERT_TRUE(isValid(icosaBuilder.toIndexedShape()));\n\n\ticosaBuilder.addPoint(Vec3f(0, 1.1f, 0));\n\ticosaBuilder.addPoint(Vec3f(0, -1.1f, 0));\n\ticosaBuilder.addPoint(Vec3f(1.1f, 0, 0));\n\ticosaBuilder.addPoint(Vec3f(-1.1f, 0, 0));\n\ticosaBuilder.addPoint(Vec3f(0, 0, 1.1f));\n\ticosaBuilder.addPoint(Vec3f(0, 0, -1.1f));\n\n\tASSERT_TRUE(isValid(icosaBuilder.toIndexedShape()));\n}\n"
  },
  {
    "path": "tests/inertiaTests.cpp",
    "content": "#include \"testsMain.h\"\n#include \"compare.h\"\n#include <Physics3D/misc/toString.h>\n\n#include <Physics3D/inertia.h>\n#include <Physics3D/geometry/shapeLibrary.h>\n\n#include \"simulation.h\"\n\n#include \"randomValues.h\"\n\nusing namespace P3D;\n#define REMAINS_CONSTANT(v) REMAINS_CONSTANT_TOLERANT(v, 0.0001)\n#define ASSERT(v) ASSERT_TOLERANT(v, 0.0001)\n\n#define DELTA_T 0.0001\n\nTEST_CASE(movedInertialMatrixForBox) {\n\tPolyhedron originalShape = ShapeLibrary::createBox(1.0, 2.0, 3.0);\n\tVec3 translation(3.1, -2.7, 7.9);\n\tPolyhedron translatedTriangle = originalShape.translated(translation);\n\tSymmetricMat3 triangleInertia = originalShape.getInertia(CFrame());\n\tSymmetricMat3 translatedTriangleInertia = translatedTriangle.getInertia(CFrame());\n\n\tASSERT(getTranslatedInertia(triangleInertia, originalShape.getVolume(), translation, originalShape.getCenterOfMass()) == translatedTriangleInertia);\n}\n\nTEST_CASE(movedInertialMatrixForDifficuiltPart) {\n\tPolyhedron originalShape = ShapeLibrary::trianglePyramid;\n\tVec3 translation(3.1, -2.7, 7.9);\n\tPolyhedron translatedTriangle = originalShape.translated(translation);\n\tSymmetricMat3 triangleInertia = originalShape.getInertia(CFrame());\n\tSymmetricMat3 translatedTriangleInertia = translatedTriangle.getInertia(CFrame());\n\n\tASSERT(getTranslatedInertia(triangleInertia, originalShape.getVolume(), translation, originalShape.getCenterOfMass()) == translatedTriangleInertia);\n}\n\nTEST_CASE(inertiaTranslationDerivatives) {\n\tSymmetricMat3 inert = ShapeLibrary::trianglePyramid.getInertia(CFrame());\n\tdouble mass = ShapeLibrary::trianglePyramid.getVolume();\n\n\tVec3 start(0.8, 0.4, 0.2);\n\tTranslationalMotion motion(Vec3(0.3, 0.4, 0.5), Vec3(-0.8, 0.5, -0.3));\n\n\tstd::array<Vec3, 3> points = computeTranslationOverTime(start, motion, DELTA_T);\n\tstd::array<SymmetricMat3, 3> inertias;\n\tfor(int i = 0; i < 3; i++) {\n\t\tinertias[i] = getTranslatedInertiaAroundCenterOfMass(inert, mass, points[i]);\n\t}\n\tFullTaylor<SymmetricMat3> estimatedTaylor = estimateDerivatives(inertias, DELTA_T);\n\tFullTaylor<SymmetricMat3> inertialTaylor = getTranslatedInertiaDerivativesAroundCenterOfMass(inert, mass, start, motion);\n\n\tASSERT(estimatedTaylor == inertialTaylor);\n}\n\nTEST_CASE(inertiaRotationDerivatives) {\n\tSymmetricMat3 inert = ShapeLibrary::trianglePyramid.getInertia(CFrame());\n\n\tRotation start = Rotation::fromEulerAngles(0.8, 0.4, 0.2);\n\tRotationalMotion motion(Vec3(0.3, 0.4, 0.5), Vec3(-0.8, 0.5, -0.3));\n\n\tstd::array<Rotation, 3> rotations = computeRotationOverTime(start, motion, DELTA_T);\n\tstd::array<SymmetricMat3, 3> inertias;\n\tfor(int i = 0; i < 3; i++) {\n\t\tinertias[i] = getRotatedInertia(inert, rotations[i]);\n\t}\n\tFullTaylor<SymmetricMat3> estimatedTaylor = estimateDerivatives(inertias, DELTA_T);\n\tFullTaylor<SymmetricMat3> inertialTaylor = getRotatedInertiaTaylor(inert, start, motion);\n\n\tASSERT(estimatedTaylor == inertialTaylor);\n}\n\nTEST_CASE(inertiaTransformationDerivatives) {\n\tPolyhedron centeredTrianglePyramid = ShapeLibrary::trianglePyramid.translated(-ShapeLibrary::trianglePyramid.getCenterOfMass());\n\n\tSymmetricMat3 inert = centeredTrianglePyramid.getInertia(CFrame());\n\tdouble mass = centeredTrianglePyramid.getVolume();\n\n\tRotationalMotion rotation(Vec3(0.3, 0.4, 0.5), Vec3(-0.8, 0.5, -0.3));\n\tTranslationalMotion translation(Vec3(-0.23, 0.25, -0.7), Vec3(-0.2, -0.7, 0.333));\n\tMotion motion(translation, rotation);\n\n\tVec3 startingTranslation(1.2, -0.7, 2.1);\n\tRotation startingRotation = Rotation::fromEulerAngles(0.5, -0.6, 0.7);\n\tCFrame start(startingTranslation, startingRotation);\n\n\tstd::array<CFrame, 3> cframes = computeCFrameOverTime(start, motion, DELTA_T);\n\tstd::array<SymmetricMat3, 3> inertias;\n\tfor(int i = 0; i < 3; i++) {\n\t\tinertias[i] = getTransformedInertiaAroundCenterOfMass(inert, mass, cframes[i]);\n\t}\n\tFullTaylor<SymmetricMat3> estimatedTaylor = estimateDerivatives(inertias, DELTA_T);\n\tFullTaylor<SymmetricMat3> inertialTaylor = getTransformedInertiaDerivativesAroundCenterOfMass(inert, mass, start, motion);\n\n\tASSERT(estimatedTaylor == inertialTaylor);\n}\nTEST_CASE(inertiaTransformationDerivativesForOffsetCenterOfMass) {\n\tVec3 com = ShapeLibrary::trianglePyramid.getCenterOfMass();\n\n\tSymmetricMat3 inert = ShapeLibrary::trianglePyramid.getInertia(CFrame());\n\tdouble mass = ShapeLibrary::trianglePyramid.getVolume();\n\n\tRotationalMotion rotation(Vec3(0.3, 0.4, 0.5), Vec3(-0.8, 0.5, -0.3));\n\tTranslationalMotion translation(Vec3(-0.23, 0.25, -0.7), Vec3(-0.2, -0.7, 0.333));\n\tMotion motion(translation, rotation);\n\n\tVec3 startingTranslation(1.2, -0.7, 2.1);\n\tRotation startingRotation = Rotation::fromEulerAngles(0.5, -0.6, 0.7);\n\tCFrame start(startingTranslation, startingRotation);\n\n\tstd::array<CFrame, 3> cframes = computeCFrameOverTime(start, motion, DELTA_T);\n\tstd::array<SymmetricMat3, 3> inertias;\n\tfor(int i = 0; i < 3; i++) {\n\t\tinertias[i] = getTransformedInertiaAroundCenterOfMass(inert, mass, com, cframes[i]);\n\t}\n\tFullTaylor<SymmetricMat3> estimatedTaylor = estimateDerivatives(inertias, DELTA_T);\n\tFullTaylor<SymmetricMat3> inertialTaylor = getTransformedInertiaDerivativesAroundCenterOfMass(inert, mass, com, start, motion);\n\n\tASSERT(estimatedTaylor == inertialTaylor);\n}\n\n// test getting angular momentum for 2x2x2 box rotating at omega_x rad/s around the x axis\n// moving at (0, vy, vz), at (0, 0, cz), relative to (0,0,0)\n// answer computed by manually running through the angular momentum integral\n// integrate(dz=1..2, dy=-1..1, dx=-1..1){offset % (angVel % offset + velocity)}\nTEST_CASE(premadeAngularMomentum) {\n\tdouble omega_x = -2.1;\n\tdouble vy = 1.3;\n\tdouble vz = 2.9;\n\tdouble cz = 3.7;\n\n\t// 2x2x2 box\n\tdouble boxInertiaXX = 16.0 / 3.0;\n\tdouble boxVolume = 8.0;\n\tdouble selfBoxAngularMomentum = boxInertiaXX * omega_x;\n\tdouble velocityAngularMomentum = -boxVolume * cz * vy;\n\tdouble totalTrueAngularMomentum = selfBoxAngularMomentum + velocityAngularMomentum;\n\n\tSymmetricMat3 inertia{\n\t\tboxInertiaXX,\n\t\t0, boxInertiaXX,\n\t\t0, 0, boxInertiaXX\n\t};\n\tVec3 angularVel(omega_x, 0, 0);\n\tVec3 vel(0, vy, vz);\n\tVec3 offset(0, 0, cz);\n\n\tVec3 boxNotRotatingAngMom = getAngularMomentumFromOffsetOnlyVelocity(offset, vel, boxVolume);\n\tVec3 boxNotRotatingAngMom2 = getAngularMomentumFromOffset(offset, vel, Vec3(0, 0, 0), inertia, boxVolume);\n\tASSERT(boxNotRotatingAngMom == Vec3(velocityAngularMomentum, 0, 0));\n\tASSERT(boxNotRotatingAngMom == boxNotRotatingAngMom2);\n\n\tVec3 boxAlsoRotatingAngMom = getAngularMomentumFromOffset(offset, vel, angularVel, inertia, boxVolume);\n\tASSERT(boxAlsoRotatingAngMom == Vec3(totalTrueAngularMomentum, 0, 0));\n}\n\nTEST_CASE(translatedAngularMomentum) {\n\tPolyhedron simpleBox = ShapeLibrary::createCube(1.0f);\n\n\tSymmetricMat3 inertia = simpleBox.getInertiaAroundCenterOfMass();\n\tdouble mass = simpleBox.getVolume();\n\n\tVec3 offset(1.3, 0.7, -2.1);\n\tVec3 angularVel(3.2, 1.3, -2.1);\n\n\tSymmetricMat3 offsetInertia = getTranslatedInertiaAroundCenterOfMass(inertia, mass, offset);\n\n\tVec3 angularMomentumTarget = offsetInertia * angularVel;\n\tVec3 rotationAngularMomentum = inertia * angularVel;\n\tVec3 velocity = angularVel % offset;\n\tVec3 angularMomentumFromVelocity = offset % velocity * mass;\n\tVec3 angularMomentumTest = rotationAngularMomentum + angularMomentumFromVelocity;\n\n\tVec3 computedAngularMomentumFromVelocity = getAngularMomentumFromOffsetOnlyVelocity(offset, velocity, mass);\n\tVec3 computedAngularMomentumFromVelocityAndAngular = getAngularMomentumFromOffset(offset, velocity, angularVel, inertia, mass);\n\n\tASSERT(angularMomentumTarget == angularMomentumTest);\n\tASSERT(angularMomentumFromVelocity == computedAngularMomentumFromVelocity);\n\tASSERT(angularMomentumTarget == computedAngularMomentumFromVelocityAndAngular);\n}\n"
  },
  {
    "path": "tests/jointTests.cpp",
    "content": "#include \"testsMain.h\"\n\n#include \"compare.h\"\n#include \"generators.h\"\n#include \"estimateMotion.h\"\n#include <Physics3D/misc/toString.h>\n\n#include <Physics3D/geometry/shape.h>\n#include <Physics3D/geometry/shapeCreation.h>\n#include <Physics3D/part.h>\n#include <Physics3D/physical.h>\n#include <Physics3D/layer.h>\n#include <Physics3D/world.h>\n\n#include <Physics3D/constraints/constraint.h>\n#include <Physics3D/constraints/constraintGroup.h>\n#include <Physics3D/constraints/ballConstraint.h>\n#include <Physics3D/constraints/constraintImpl.h>\n\nusing namespace P3D;\n#define ASSERT(cond) ASSERT_TOLERANT(cond, 0.05)\n\n#define DELTA_T 0.0001\n\nTEST_CASE(testConstraintMatrixPack) {\n\tMatrix<double, 6, 4> paramToMotionA = generateMatrix<double, 6, 4>();\n\tMatrix<double, 6, 4> paramToMotionB = generateMatrix<double, 6, 4>();\n\tMatrix<double, 4, 6> motionToEqA = generateMatrix<double, 4, 6>();\n\tMatrix<double, 4, 6> motionToEqB = generateMatrix<double, 4, 6>();\n\tMatrix<double, 4, NUMBER_OF_ERROR_DERIVATIVES> errorMat = generateMatrix<double, 4, NUMBER_OF_ERROR_DERIVATIVES>();\n\n\tdouble matrixBuf[6 * 4 * 4];\n\tdouble errorBuf[6 * NUMBER_OF_ERROR_DERIVATIVES];\n\n\tConstraintMatrixPack cmp(matrixBuf, errorBuf, paramToMotionA, paramToMotionB, motionToEqA, motionToEqB, errorMat);\n\n\tASSERT(cmp.getParameterToMotionMatrixA() == paramToMotionA);\n\tASSERT(cmp.getParameterToMotionMatrixB() == paramToMotionB);\n\tASSERT(cmp.getMotionToEquationMatrixA() == motionToEqA);\n\tASSERT(cmp.getMotionToEquationMatrixB() == motionToEqB);\n\tASSERT(cmp.getErrorMatrix() == errorMat);\n}\n\nTEST_CASE(testBallConstraintMatrices) {\n\tPart firstPart(boxShape(1.0, 2.0, 3.0), GlobalCFrame(Position(0.0, 0.0, 0.0)), {0.3, 0.7, 0.9});\n\tPart secondPart(sphereShape(1.5), GlobalCFrame(Position(1.0, 0.0, 0.0)), {0.1, 0.6, 0.6});\n\n\tVec3 attach1(0.0, 0.0, 0.0);\n\tVec3 attach2(-1.0, 0.0, 0.0);\n\n\tBallConstraint bc(attach1, attach2);\n\n\tPhysicalConstraint pc(firstPart.ensureHasPhysical(), secondPart.ensureHasPhysical(), &bc);\n\n\tdouble matrixBuf[6 * 3 * 4 + 100];\n\tdouble errorBuf[NUMBER_OF_ERROR_DERIVATIVES * 3 + 100];\n\n\n\tConstraintMatrixPack matrices = pc.getMatrices(matrixBuf, errorBuf);\n\n\tVec3 param = generateVec3();\n\tLargeVector<double> paramBig(3);\n\tparamBig.setSubVector(param, 0);\n\tVec6 motionA = matrices.getParameterToMotionMatrixA() * paramBig;\n\n\tfirstPart.getPhysical()->applyImpulseToPhysical(attach1, param);\n\tASSERT(firstPart.getMotion().getDerivAsVec6(0) == motionA);\n\n\tVec6 motionB = -(matrices.getParameterToMotionMatrixB() * paramBig);\n\n\tsecondPart.getPhysical()->applyImpulseToPhysical(attach2, -param);\n\tASSERT(secondPart.getMotion().getDerivAsVec6(0) == motionB);\n}\n\nTEST_CASE(testBallConstraintSymmetric) {\n\tPart firstPart(generateShape(), generateGlobalCFrame(), {0.3, 0.7, 0.9});\n\tPart secondPart(generateShape(), generateGlobalCFrame(), {0.1, 0.6, 0.6});\n\n\tfirstPart.ensureHasPhysical();\n\tsecondPart.ensureHasPhysical();\n\n\tVec3 attach1 = generateVec3();\n\tVec3 attach2 = generateVec3();\n\n\tBallConstraint bcA(attach1, attach2);\n\tPhysicalConstraint pcA(firstPart.getPhysical(), secondPart.getPhysical(), &bcA);\n\n\tBallConstraint bcB(attach2, attach1);\n\tPhysicalConstraint pcB(secondPart.getPhysical(), firstPart.getPhysical(), &bcB);\n\n\tdouble matrixBufA[6 * 3 * 4 + 100];\n\tdouble errorBufA[NUMBER_OF_ERROR_DERIVATIVES * 3 + 100];\n\tdouble matrixBufB[6 * 3 * 4 + 100];\n\tdouble errorBufB[NUMBER_OF_ERROR_DERIVATIVES * 3 + 100];\n\n\n\tConstraintMatrixPack matricesA = pcA.getMatrices(matrixBufA, errorBufA);\n\tConstraintMatrixPack matricesB = pcB.getMatrices(matrixBufB, errorBufB);\n\tASSERT(matricesA.getParameterToMotionMatrixA() == matricesB.getParameterToMotionMatrixB());\n\tASSERT(matricesA.getParameterToMotionMatrixB() == matricesB.getParameterToMotionMatrixA());\n\tASSERT(matricesA.getMotionToEquationMatrixA() == matricesB.getMotionToEquationMatrixB());\n\tASSERT(matricesA.getMotionToEquationMatrixB() == matricesB.getMotionToEquationMatrixA());\n\tauto errB = matricesB.getErrorMatrix();\n\tinMemoryMatrixNegate(errB);\n\tASSERT(matricesA.getErrorMatrix() == errB);\n}\n\n\n/*TEST_CASE(testBallConstraint) {\n\tPart part1(boxShape(2.0, 2.0, 2.0), GlobalCFrame(0.0, 0.0, 0.0), {1.0, 1.0, 1.0});\n\tpart1.ensureHasParent();\n\tPart part2(boxShape(2.0, 2.0, 2.0), GlobalCFrame(6.0, 0.0, 0.0), {1.0, 1.0, 1.0});\n\tpart2.ensureHasParent();\n\tConstraintGroup group;\n\tgroup.ballConstraints.push_back(BallConstraint{Vec3(3.0, 0.0, 0.0), part1.parent->mainPhysical, Vec3(-3.0, 0.0, 0.0), part2.parent->mainPhysical});\n\n\tpart1.parent->mainPhysical->applyForceAtCenterOfMass(Vec3(2, 0, 0));\n\n\tgroup.apply();\n\n\tASSERT(part1.getMotion().getAcceleration() == Vec3(0.125, 0.0, 0.0));\n\tASSERT(part2.getMotion().getAcceleration() == Vec3(0.125, 0.0, 0.0));\n}*/\n"
  },
  {
    "path": "tests/lexerTests.cpp",
    "content": "#include \"testsMain.h\"\n\n#include \"../graphics/shader/lexer.h\"\n#include \"../graphics/shader/parser.h\"\n#include \"../util/log.h\"\n\nusing namespace P3D;\nstatic const char* code = R\"(\nstruct Light {\n\tvec3 position;\n\tvec3 color;\n\tfloat intensity;\n\tAttenuation attenuation;\n};\n\n#define maxLights 10\nuniform Light lights[maxLights];\n\t)\";\n\nstatic const char* names[] = {\n\t\t\"Error\",\n\t\t\"Comma\",\n\t\t\"Semicolon\",\n\t\t\"LeftParenthesis\",\n\t\t\"RightParenthesis\",\n\t\t\"Equals\",\n\t\t\"Dot\",\n\t\t\"InOut\",\n\t\t\"Layout\",\n\t\t\"Uniform\",\n\t\t\"Qualifier\",\n\t\t\"Struct\",\n\t\t\"Version\",\n\t\t\"Preprocessor\",\n\t\t\"Datatype\",\n\t\t\"Identifier\",\n\t\t\"LeftCurl\",\n\t\t\"RightCurl\",\n\t\t\"LeftBracket\",\n\t\t\"RightBracket\",\n\t\t\"Number\",\n\t\t\"Operator\",\n\t\t\"SingleQuote\",\n\t\t\"DoubleQuote\",\n\t\t\"String\",\n\t\t\"Comment\",\n\t\t\"End\"\n};\n\nTEST_CASE(lexVersionPreprocessor) {\n\tusing namespace P3D::Graphics;\n\n\tconst char* code = R\"(\n\t\t#version 123;\n\t\t#version #ifdef 2 #else 4\n\t)\";\n\n\tLexer lexer(code);\n\n\tauto current = lexer.next();\n\twhile(current.type != Lexer::Token::End) {\n\t\tLog::debug(\"%s[%s]\", names[current.type], current.string(code).c_str());\n\t\tcurrent = lexer.next();\n\t}\n}\n\nTEST_CASE(lexShader) {\n\tusing namespace P3D::Graphics;\n\n\tLexer lexer(code);\n\n\tauto current = lexer.next();\n\twhile(current.type != Lexer::Token::End) {\n\t\tLog::debug(\"%s[%s]\", names[current.type], current.string(code).c_str());\n\t\tcurrent = lexer.next();\n\t}\n}\n\nTEST_CASE(parseShader) {\n\tusing namespace Graphics;\n\n\tParser::Parse result = Parser::parse(code);\n}\n"
  },
  {
    "path": "tests/mathTests.cpp",
    "content": "#include \"testsMain.h\"\n\n#include \"compare.h\"\n#include \"testValues.h\"\n#include \"randomValues.h\"\n#include \"simulation.h\"\n#include <Physics3D/misc/toString.h>\n#include <Physics3D/math/linalg/vec.h>\n#include <Physics3D/math/linalg/quat.h>\n#include <Physics3D/math/linalg/mat.h>\n#include <Physics3D/math/linalg/trigonometry.h>\n#include <Physics3D/math/linalg/largeMatrix.h>\n#include <Physics3D/math/linalg/largeMatrixAlgorithms.h>\n#include <Physics3D/math/linalg/eigen.h>\n#include <Physics3D/math/mathUtil.h>\n#include <Physics3D/math/taylorExpansion.h>\n#include <Physics3D/math/predefinedTaylorExpansions.h>\n#include <Physics3D/math/linalg/commonMatrices.h>\n\n#include <algorithm>\n\nusing namespace P3D;\n#define ASSERT(condition) ASSERT_TOLERANT(condition, 0.00000001)\n\n#define DELTA_T 0.00001\n\nTEST_CASE(subMatrixOperations) {\n\tMatrix<int, 5, 3> mat{\n\t\t5,7,9,\n\t\t6,9,2,\n\t\t3,9,5,\n\t\t3,8,4,\n\t\t3,8,1\n\t};\n\n\tASSERT((mat.getSubMatrix<3, 2>(1, 0)) == (Matrix<int, 3, 2>{\n\t\t6, 9,\n\t\t\t3, 9,\n\t\t\t3, 8\n\t}));\n\n\tASSERT((mat.withoutRow(2)) == (Matrix<int, 4, 3>{\n\t\t5, 7, 9,\n\t\t\t6, 9, 2,\n\t\t\t3, 8, 4,\n\t\t\t3, 8, 1\n\t}));\n\n\tASSERT((mat.withoutCol(1)) == (Matrix<int, 5, 2>{\n\t\t5, 9,\n\t\t\t6, 2,\n\t\t\t3, 5,\n\t\t\t3, 4,\n\t\t\t3, 1\n\t}));\n}\n\nTEST_CASE(determinant) {\n\tMatrix<double, 3, 3> m3{\n\t\t1, 7, 21,\n\t\t7, 6, 9,\n\t\t1, 3, 8\n\t};\n\n\tlogf(\"m=%s\\nm.det()=%f\", str(m3).c_str(), det(m3));\n\n\tASSERT(det(m3) == 7);\n\n\n\tMat4 m4{\n\t\t1, 7, 21, 6,\n\t\t7, 6, 9, 8,\n\t\t1, 3, 8, 4,\n\t\t2, 9, 7, 3\n\t};\n\n\tlogf(\"m=%s\\nm.det()=%f\", str(m4).c_str(), det(m4));\n\tASSERT(det(m4) == -983);\n}\n\n\nTEST_CASE(matrixInverse2) {\n\tMat2 m{4,7,9,3};\n\n\tlogf(\"m=%s\\n~m=%s\\nm.inverse()=%s\\nm.det()=%f\", str(m).c_str(), str(~m).c_str(), str(~m).c_str(), det(m));\n\n\tASSERT(det(m) * det(~m) == 1.0);\n\tASSERT(m * ~m == Mat2::IDENTITY());\n\tASSERT(~m * m == Mat2::IDENTITY());\n}\n\nTEST_CASE(matrixInverse3) {\n\tMat3 m{1,3,4,7,6,9,5,3,2};\n\tSymmetricMat3 s{1, 4, 7, 6, 9, 8};\n\tDiagonalMat3 d{7, 5, 3};\n\n\tlogf(\"m=%s\\n~m=%s\\nm.det()=%f\", str(m).c_str(), str(~m).c_str(), det(m));\n\n\tASSERT(m * ~m == Mat3::IDENTITY());\n\tASSERT(~m * m == Mat3::IDENTITY());\n\tASSERT(s * ~s == SymmetricMat3::IDENTITY());\n\tASSERT(~s * s == SymmetricMat3::IDENTITY());\n\tASSERT(d * ~d == DiagonalMat3::IDENTITY());\n\tASSERT(~d * d == DiagonalMat3::IDENTITY());\n}\n\nTEST_CASE(matrixInverse4) {\n\tMat4 m{\n\t\t1, 3, 4, 7,\n\t\t7, 9, 3, 5,\n\t\t4, 9, 1, 2,\n\t\t6, 7, 6, 9};\n\n\tlogf(\"m=%s\\n~m=%s\\nm.inverse()=%s\\nm.det()=%f\", str(m).c_str(), str(~m).c_str(), str(~m).c_str(), det(m));\n\n\tASSERT(det(m) * det(~m) == 1.0);\n\n\tASSERT(m * ~m == Mat4::IDENTITY());\n\tASSERT(~m * m == Mat4::IDENTITY());\n}\n\nTEST_CASE(cframeInverse) {\n\tCFrame A(Vec3(1.0, 0.8, 0.9), Rotation::fromEulerAngles(0.3, 0.7, 0.9));\n\tCFrame B(Vec3(8.2, -0.8, 3.4), Rotation::fromEulerAngles(0.4, 0.4, 0.3));\n\n\tASSERT(A.localToGlobal(A.globalToLocal(B)) == B);\n\tASSERT(A.globalToLocal(A.localToGlobal(B)) == B);\n\tASSERT(A.globalToLocal(A) == CFrame());\n\tASSERT(A.localToGlobal(~A) == CFrame());\n\tASSERT((~A).localToGlobal(A) == CFrame());\n\n\tASSERT(A.localToRelative(B) + A.position == A.localToGlobal(B));\n}\n\nTEST_CASE(matrixAssociativity) {\n\n\tMat3 A3{1, 2, 3, 4, 5, 6, 7, 8, 9};\n\tMat3 B3{11, 13, 17, 19, 23, 29, 31, 37, 41};\n\tMat3 C3{0.1, 0.2, 0.7, 0.9, -0.3, -0.5, 0.9, 0.1, -0.3};\n\n\tASSERT((A3 * B3) * C3 == A3 * (B3 * C3));\n\n\tVec3 v3(17, -0.7, 9.4);\n\n\tASSERT((A3 * B3) * v3 == (A3 * (B3 * v3)));\n\n\n\tMat4 A4{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};\n\tMat4 B4{11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 57, 61, 67, 71};\n\tMat4 C4{0.1, 0.2, 0.7, 0.9, -0.3, -0.5, 0.9, 0.1, -0.3, -0.8, 1.6, 0.4, 0.7, 0.3, 0.1, 0.1};\n\n\tASSERT((A4 * B4) * C4 == A4 * (B4 * C4));\n\n\tVec4 v4(17, -0.7, 9.4, 0.888);\n\n\tASSERT((A4 * B4) * v4 == (A4 * (B4 * v4)));\n}\n\nTEST_CASE(cframeAssociativity) {\n\n\tCFrame A(Vec3(0.7, 1.02, 0.9), Rotation::fromEulerAngles(0.7, 0.9, 0.3));\n\tCFrame B(Vec3(-0.2, 10.02, 0.3), Rotation::fromEulerAngles(0.2, 0.2, 0.1));\n\tCFrame C(Vec3(-0.2343657, 17.02, -9.3), Rotation::fromEulerAngles(0.9, 0.4, 0.9));\n\n\tVec3 v(17, -0.7, 9.4);\n\n\tASSERT(A.localToGlobal(B).localToGlobal(C) == A.localToGlobal(B.localToGlobal(C)));\n\tASSERT(A.localToGlobal(B).localToGlobal(v) == A.localToGlobal(B).localToGlobal(v));\n}\n\nTEST_CASE(fromEuler) {\n\tASSERT(rotMatZ(0.5) * rotMatX(0.3) * rotMatY(0.7) == rotationMatrixfromEulerAngles(0.3, 0.7, 0.5));\n}\n\nTEST_CASE(crossProduct) {\n\tVec3 x(1.0, 0.0, 0.0);\n\tVec3 y(0.0, 1.0, 0.0);\n\tVec3 z(0.0, 0.0, 1.0);\n\tVec3 v(1.3, 9.2, -3.7);\n\tVec3 u(-7.3, 1.8, 0.5);\n\n\tASSERT(v % u == -(u % v));\n\tASSERT((2.0 * v) % (3.0 * u) == 6.0 * (v % u));\n\n\tASSERT(x % y == z);\n\tASSERT(y % x == -z);\n\tASSERT(y % z == x);\n\tASSERT(z % y == -x);\n\tASSERT(z % x == y);\n\tASSERT(x % z == -y);\n}\n\nTEST_CASE(eigenDecomposition) {\n\tfor(double x = -1.25; x < 1.5; x += 0.1) {\n\t\tfor(double y = -1.35; y < 1.5; y += 0.1) {\n\t\t\tfor(double z = -1.55; z < 1.5; z += 0.1) {\n\t\t\t\tMat3 orthoPart = rotationMatrixfromEulerAngles(0.21, 0.31, 0.41);\n\t\t\t\tDiagonalMat3 eigenMat{x,y,z};\n\n\t\t\t\tSymmetricMat3 testMat = mulSymmetricLeftRightTranspose(SymmetricMat3(eigenMat), orthoPart);\n\n\t\t\t\tEigenSet<double, 3> v = getEigenDecomposition(testMat);\n\n\t\t\t\tEigenValues<double, 3> realValues{x,y,z};\n\n\t\t\t\tASSERT(realValues == v.eigenValues);\n\t\t\t\tASSERT(transformBasis(v.eigenValues.asDiagonalMatrix(), v.eigenVectors) == testMat);\n\t\t\t}\n\t\t}\n\t}\n}\n\nTEST_CASE(largeMatrixVectorSolve) {\n\tLargeMatrix<double> mat(5, 5);\n\tLargeVector<double> vec(5);\n\n\tfor(int i = 0; i < 5; i++) {\n\t\tvec[i] = fRand(-1.0, 1.0);\n\t}\n\n\tfor(int i = 0; i < 5; i++) {\n\t\tfor(int j = 0; j < 5; j++) {\n\t\t\tmat(i, j) = fRand(-1.0, 1.0);\n\t\t}\n\t}\n\n\tmat(0, 0) = 0;\n\n\tLargeVector<double> newVector = mat * vec;\n\n\tLargeVector<double> solutionVector = newVector;\n\n\tdestructiveSolve(mat, solutionVector);\n\n\tASSERT(solutionVector == vec);\n}\n\nTEST_CASE(testTaylorExpansion) {\n\tFullTaylorExpansion<double, 5> testTaylor{2.0, 5.0, 2.0, 3.0, -0.7};\n\n\tdouble x = 0.47;\n\n\tdouble correctResult =\n\t\ttestTaylor.getConstantValue() +\n\t\ttestTaylor.getDerivative(0) * x +\n\t\ttestTaylor.getDerivative(1) * x * x / 2 +\n\t\ttestTaylor.getDerivative(2) * x * x * x / 6 +\n\t\ttestTaylor.getDerivative(3) * x * x * x * x / 24;\n\n\tASSERT(correctResult == testTaylor(x));\n}\n\nTEST_CASE(testSinTaylorExpansion) {\n\tdouble curAngle = 0.93;\n\tdouble multiplier = 13.97;\n\t// Taylor expansion for sin(x * multiplier) at x=curAngle\n\tFullTaylorExpansion<double, 5> testTaylor = generateFullTaylorForSinWave<double, 5>(curAngle, multiplier);\n\n\tdouble constTerm = sin(curAngle * multiplier);\n\tdouble firstDerivative = multiplier * cos(curAngle * multiplier);\n\tdouble secondDerivative = multiplier * multiplier * (-sin(curAngle * multiplier));\n\tdouble thirdDerivative = multiplier * multiplier * multiplier * (-cos(curAngle * multiplier));\n\tdouble fourthDerivative = multiplier * multiplier * multiplier * multiplier * sin(curAngle * multiplier);\n\n\tASSERT(testTaylor.getConstantValue() == constTerm);\n\tASSERT(testTaylor.getDerivative(0) == firstDerivative);\n\tASSERT(testTaylor.getDerivative(1) == secondDerivative);\n\tASSERT(testTaylor.getDerivative(2) == thirdDerivative);\n\tASSERT(testTaylor.getDerivative(3) == fourthDerivative);\n}\n\nTEST_CASE(testMultiplicationDerivatives) {\n\tconstexpr int COUNT = 4;\n\tFullTaylorExpansion<Mat3, COUNT> mats = createRandomFullTaylorExpansion<Mat3, COUNT, createRandomMatrixTemplate<double, 3, 3>>();\n\tFullTaylorExpansion<Vec3, COUNT> vecs = createRandomFullTaylorExpansion<Vec3, COUNT, createRandomVecTemplate<double, 3>>();\n\n\tFullTaylorExpansion<Vec3, COUNT> resultToTest = derivsOfMultiplication(mats, vecs);\n\n\tstd::array<Mat3, COUNT> matVals = computeOverTime(mats, DELTA_T);\n\tstd::array<Vec3, COUNT> vecVals = computeOverTime(vecs, DELTA_T);\n\n\tstd::array<Vec3, COUNT> targetResults;\n\tfor(int i = 0; i < COUNT; i++) targetResults[i] = matVals[i] * vecVals[i];\n\n\tFullTaylorExpansion<Vec3, COUNT> estimatedRealDerivatives = estimateDerivatives(targetResults, DELTA_T);\n\n\tlogStream << \"resultToTest: \" << resultToTest << \"\\n\";\n\tlogStream << \"estimatedRealDerivatives: \" << estimatedRealDerivatives << \"\\n\";\n\n\tfor(int i = 0; i < COUNT; i++) {\n\t\tdouble tolerance = 0.0000001 * std::exp(10.0 * i);\n\t\tlogStream << \"tolerance: \" << tolerance << \"\\n\";\n\t\tASSERT_TOLERANT(resultToTest.derivs[i] == estimatedRealDerivatives.derivs[i], tolerance);\n\t}\n}\n\nTEST_CASE(testCrossProductEquivalent) {\n\tVec3 v(1.3, -0.5, 0.7);\n\tVec3 x(0.6, 0.5, -1.2);\n\n\tASSERT(v % x == createCrossProductEquivalent(v) * x);\n}\n\nTEST_CASE(testSkewSymmetricValid) {\n\tVec3 v(1.3, -0.5, 0.7);\n\tVec3 x(0.6, 0.5, -1.2);\n\n\tASSERT((v % (v % x)) == skewSymmetricSquared(v) * x);\n\tMat3 sv = createCrossProductEquivalent(v);\n\tASSERT(sv * sv == Mat3(skewSymmetricSquared(v)));\n}\n\nTEST_CASE(testSkewSymmetricDerivatives) {\n\tVec3 start(1.3, 1.7, -0.5);\n\tVec3 deriv1(-0.2, 0.4, -0.5);\n\tVec3 deriv2(-0.3, 0.2, -0.1);\n\n\tFullTaylor<Vec3> vecInput{start, deriv1, deriv2};\n\n\tFullTaylor<SymmetricMat3> skewSymOut = generateFullTaylorForSkewSymmetricSquared<double, 3>(vecInput);\n\n\tSymmetricMat3 s0 = skewSymmetricSquared(vecInput(0.0));\n\tSymmetricMat3 s1 = skewSymmetricSquared(vecInput(DELTA_T));\n\tSymmetricMat3 s2 = skewSymmetricSquared(vecInput(DELTA_T * 2.0));\n\n\tASSERT_TOLERANT(s0 == skewSymOut.getConstantValue(), 0.000000001);\n\tASSERT_TOLERANT((s1 - s0) / DELTA_T == skewSymOut.getDerivative(0), 0.00005);\n\tASSERT_TOLERANT((s2 + s0 - 2.0 * s1) / (DELTA_T * DELTA_T) == skewSymOut.getDerivative(1), 0.00005);\n}\n\nTEST_CASE(testSimulation) {\n\tFullTaylorExpansion<Vec3, 3> realDerivs{Vec3(0.4, -0.6, 0.7), Vec3(-0.2, 0.4, -0.8), Vec3(0.5, -0.35, 0.7)};\n\n\tdouble deltaT = 0.000001;\n\n\tstd::array<Vec3, 3> computedPoints = computeTranslationOverTime(realDerivs.getConstantValue(), realDerivs.getDerivatives(), deltaT);\n\n\tFullTaylorExpansion<Vec3, 3> computedDerivs = estimateDerivatives(computedPoints, deltaT);\n\n\tASSERT_TOLERANT(realDerivs == computedDerivs, 0.0005);\n}\n\nTEST_CASE(testRotationDerivs) {\n\tMat3 rot0 = rotationMatrixfromEulerAngles(0.3, -0.5, 0.7);\n\tfor(Vec3 angularVel : vectors) {\n\t\tfor(Vec3 angularAccel : vectors) {\n\t\t\tlogStream << \"angularVel: \" << angularVel << \" accel: \" << angularAccel << \"\\n\";\n\t\t\tTaylorExpansion<Vec3, 2> rotVecTaylor{angularVel, angularAccel};\n\t\t\tFullTaylorExpansion<Mat3, 3> rotTaylor = FullTaylorExpansion<Mat3, 3>::fromConstantAndDerivatives(rot0, generateTaylorForRotationMatrix<double, 2>(rotVecTaylor, rot0));\n\n\t\t\tVec3 rotVec1 = rotVecTaylor(DELTA_T);\n\t\t\tVec3 rotVec2 = rotVecTaylor(DELTA_T * 2);\n\t\t\tMat3 deltaRot1 = rotationMatrixFromRotationVec(rotVec1);\n\t\t\tMat3 deltaRot2 = rotationMatrixFromRotationVec(rotVec2);\n\t\t\tMat3 rot1 = deltaRot1 * rot0;\n\t\t\tMat3 rot2 = deltaRot2 * rot0;\n\n\t\t\tASSERT_TOLERANT((rot1 - rot0) / DELTA_T == rotTaylor.getDerivative(0), 0.0005 * lengthSquared(angularVel) + lengthSquared(angularAccel));\n\t\t\tASSERT_TOLERANT((rot2 + rot0 - 2.0 * rot1) / (DELTA_T * DELTA_T) == rotTaylor.getDerivative(1), 0.05 * (lengthSquared(angularVel) + lengthSquared(angularAccel)));\n\t\t}\n\t}\n}\n\nTEST_CASE(testFromRotationVec) {\n\tdouble deltaT = 0.0001;\n\n\tVec3 rotations[]{Vec3(1,0,0), Vec3(0,1,0), Vec3(0,0,1), Vec3(-5.0, 3.0, 9.0), Vec3(3.8, -0.5, 0.4)};\n\tfor(Vec3 rotVec : rotations) {\n\t\tVec3 rotationVec = rotVec * deltaT;\n\t\tVec3 pointToRotate = Vec3(1.0, 0.0, 0.0);\n\n\t\tMat3 rot = rotationMatrixFromRotationVec(rotationVec);\n\n\t\tVec3 rotateByRotVec = pointToRotate;\n\t\tVec3 rotateByRotMat = pointToRotate;\n\n\t\tfor(int i = 0; i < 500; i++) {\n\t\t\trotateByRotVec = rotateByRotVec + rotationVec % rotateByRotVec;\n\t\t\trotateByRotMat = rot * rotateByRotMat;\n\t\t}\n\n\t\tlogStream << \"rotVec: \" << rotationVec << \", rot: \" << rot << '\\n';\n\t\tlogStream << \"newPointRotVec: \" << rotateByRotVec << \"\\nnewPointRotMat: \" << rotateByRotMat << '\\n';\n\n\t\tASSERT_TOLERANT(rotateByRotVec == rotateByRotMat, 0.01);\n\t}\n}\n\n// Everything Quaternions\nTEST_CASE(quaternionBasicRotation) {\n\tVec3 v = Vec3(0.0, 1.0, 0.0);\n\tQuat4 q = QROT_X_180(double);\n\n\tQuat4 r = q * v * conj(q);\n\n\tASSERT(r.w == 0.0);\n\tASSERT(r.v == Vec3(0.0, -1.0, 0.0));\n}\n\nTEST_CASE(quaternionRotationShorthand) {\n\tVec3 v = Vec3(0.7, 1.0, 0.3);\n\tQuat4 q = normalize(Quat4(0.8, 0.4, 0.3, -0.4));\n\n\tASSERT(Quat4(0.0, mulQuaternionLeftRightConj(q, v)) == q * v * conj(q));\n\tASSERT(Quat4(0.0, mulQuaternionLeftConjRight(q, v)) == conj(q) * v * q);\n}\n\nTEST_CASE(quaternionFromRotationVecToRotationMatrix) {\n\tfor(double x = -1.25; x < 1.5; x += 0.1) {\n\t\tfor(double y = -1.35; y < 1.5; y += 0.1) {\n\t\t\tfor(double z = -1.55; z < 1.5; z += 0.1) {\n\t\t\t\tVec3 rotVec(x, y, z);\n\t\t\t\tASSERT(rotationMatrixFromQuaternion(rotationQuaternionFromRotationVec(rotVec)) == rotationMatrixFromRotationVec(rotVec));\n\t\t\t}\n\t\t}\n\t}\n}\n\nTEST_CASE(interchanceQuaternionAndMatrix) {\n\tfor(double x = -1.25; x < 1.5; x += 0.1) {\n\t\tfor(double y = -1.35; y < 1.5; y += 0.1) {\n\t\t\tfor(double z = -1.55; z < 1.5; z += 0.1) {\n\t\t\t\tMat3 rotMat = rotationMatrixfromEulerAngles(x, y, z);\n\t\t\t\tQuat4 rotQuat = rotationQuaternionFromRotationMatrix(rotMat);\n\t\t\t\tMat3 resultMat = rotationMatrixFromQuaternion(rotQuat);\n\n\t\t\t\tASSERT(rotMat == resultMat);\n\t\t\t}\n\t\t}\n\t}\n}\n\nTEST_CASE(testFixCastToInt) {\n\tfor(int i = 0; i < 10000; i++) {\n\t\tint64_t a = rand() - RAND_MAX / 2;\n\t\tFix<32> f(a);\n\t\tlogStream << a << '\\n';\n\t\tASSERT_STRICT(static_cast<int64_t>(f) == a);\n\t}\n\tfor(int i = 0; i < 10000; i++) {\n\t\tdouble d = double(rand()) / RAND_MAX * 100000.0;\n\t\tFix<32> f(d);\n\t\tlogStream << d << '\\n';\n\n\t\tASSERT_STRICT(static_cast<int64_t>(f) == static_cast<int64_t>(d));\n\t}\n}\n"
  },
  {
    "path": "tests/motionTests.cpp",
    "content": "#include \"testsMain.h\"\n\n#include \"compare.h\"\n#include \"randomValues.h\"\n#include <Physics3D/misc/toString.h>\n#include \"estimateMotion.h\"\n\n#include <Physics3D/motion.h>\n#include <Physics3D/relativeMotion.h>\n\n#include <Physics3D/hardconstraints/hardPhysicalConnection.h>\n#include <Physics3D/hardconstraints/motorConstraint.h>\n#include <Physics3D/hardconstraints/sinusoidalPistonConstraint.h>\n\nusing namespace P3D;\n#define REMAINS_CONSTANT(v) REMAINS_CONSTANT_TOLERANT(v, 0.005)\n#define ASSERT(v) ASSERT_TOLERANT(v, 0.005)\n\n#define DELTA_T 0.0001\n\n\n\nTEST_CASE(testBasicMotion) {\n\tVec3 vel(1.3, 0.7, 0.9);\n\tVec3 angularVel(1.7, 0.9, 1.2);\n\tVec3 point(1.2, -0.5, 0.7);\n\n\tMotion m(vel, angularVel);\n\n\tASSERT_TOLERANT(m.getVelocityOfPoint(point) == getVelocityBySimulation(m, point, DELTA_T), 0.05);\n}\n\nTEST_CASE(testAdvancedMotion) {\n\tVec3 vel(1.3, 0.7, 0.9);\n\tVec3 angularVel(1.7, 0.9, 1.2);\n\tVec3 accel(7.1, 0.9, -3.8);\n\tVec3 angularAccel(1.8, 0.67, -4.1);\n\tVec3 point(1.2, -0.5, 0.7);\n\n\tMotion m(vel, angularVel, accel, angularAccel);\n\n\tASSERT_TOLERANT(m.getMotionOfPoint(point) == getMotionBySimulation(m, point, DELTA_T), 0.05);\n}\n\nTEST_CASE(testMotionOfMotorConstraintCorrect) {\n\tHardPhysicalConnection connection(std::unique_ptr<HardConstraint>(new ConstantSpeedMotorConstraint(createRandomDouble())), createRandomCFrame(), createRandomCFrame());\n\n\tconnection.update(1.23456789);\n\n\tRelativeMotion calculatedMotion = connection.getRelativeMotion();\n\n\tCFrame cf1 = connection.getRelativeCFrameToParent();\n\tconnection.update(DELTA_T);\n\tCFrame cf2 = connection.getRelativeCFrameToParent();\n\tconnection.update(DELTA_T);\n\tCFrame cf3 = connection.getRelativeCFrameToParent();\n\n\tASSERT(calculatedMotion.relativeMotion == estimateMotion(cf1, cf2, cf3, DELTA_T));\n}\n\nTEST_CASE(testMotionOfPistonConstraintCorrect) {\n\tHardPhysicalConnection connection(std::unique_ptr<HardConstraint>(new SinusoidalPistonConstraint(1.0, 5.0, 1.0)), createRandomCFrame(), createRandomCFrame());\n\n\tconnection.update(1.23456789);\n\n\tRelativeMotion calculatedMotion = connection.getRelativeMotion();\n\n\tCFrame cf1 = connection.getRelativeCFrameToParent();\n\tconnection.update(DELTA_T);\n\tCFrame cf2 = connection.getRelativeCFrameToParent();\n\tconnection.update(DELTA_T);\n\tCFrame cf3 = connection.getRelativeCFrameToParent();\n\n\tASSERT(calculatedMotion.relativeMotion == estimateMotion(cf1, cf2, cf3, DELTA_T));\n}\n\nTEST_CASE(testPistonConstraint) {\n\tSinusoidalPistonConstraint constraint(1.0, 2.5, 0.7);\n\n\tconstraint.update(1.23456789);\n\n\tCFrame cf1 = constraint.getRelativeCFrame();\n\n\tRelativeMotion relMotion = constraint.getRelativeMotion();\n\n\tconstraint.update(DELTA_T);\n\n\tCFrame cf2 = constraint.getRelativeCFrame();\n\n\tASSERT((cf2.getPosition() - cf1.getPosition()) == relMotion.relativeMotion.getVelocity() * DELTA_T);\n}\n\nTEST_CASE(testExtendBegin) {\n\tRelativeMotion relMotion = createRandomRelativeMotion();\n\tVec3 offsetFromBegin = createRandomNonzeroVec3();\n\n\tRelativeMotion resultingMotion1 = relMotion.extendBegin(offsetFromBegin);\n\tRelativeMotion resultingMotion2 = RelativeMotion(Motion(), CFrame(offsetFromBegin)) + relMotion;\n\n\tASSERT(resultingMotion1 == resultingMotion2);\n}\n\nTEST_CASE(testExtendEnd) {\n\tRelativeMotion relMotion = createRandomRelativeMotion();\n\tVec3 offsetFromEnd = createRandomNonzeroVec3();\n\n\tRelativeMotion resultingMotion1 = relMotion.extendEnd(offsetFromEnd);\n\tRelativeMotion resultingMotion2 = relMotion + RelativeMotion(Motion(), CFrame(offsetFromEnd));\n\n\tASSERT(resultingMotion1 == resultingMotion2);\n}\n\nTEST_CASE(testExtendingRelativeMotionCVecCommutes) {\n\tRelativeMotion relMotion = createRandomRelativeMotion();\n\tVec3 offsetFromBegin = createRandomNonzeroVec3();\n\tVec3 offsetFromEnd = createRandomNonzeroVec3();\n\n\tRelativeMotion resultingMotion1 = relMotion.extendBegin(offsetFromBegin).extendEnd(offsetFromEnd);\n\tRelativeMotion resultingMotion2 = relMotion.extendEnd(offsetFromEnd).extendBegin(offsetFromBegin);\n\n\tASSERT(resultingMotion1 == resultingMotion2);\n}\nTEST_CASE(testExtendingRelativeMotionCFrameCommutes) {\n\tRelativeMotion relMotion = createRandomRelativeMotion();\n\tCFrame offsetFromBegin = createRandomCFrame();\n\tCFrame offsetFromEnd = createRandomCFrame();\n\n\tRelativeMotion resultingMotion1 = relMotion.extendBegin(offsetFromBegin).extendEnd(offsetFromEnd);\n\tRelativeMotion resultingMotion2 = relMotion.extendEnd(offsetFromEnd).extendBegin(offsetFromBegin);\n\n\tASSERT(resultingMotion1 == resultingMotion2);\n}\nTEST_CASE(testExtendingRelativeMotionVecCorrect) {\n\tRelativeMotion relMotion = createRandomRelativeMotion();\n\tMotion motionOfOrigin = createRandomMotion();\n\tVec3 offsetFromBegin = createRandomNonzeroVec3();\n\tVec3 offsetFromEnd = createRandomNonzeroVec3();\n\n\t// manually compute resulting motion\n\tMotion motionOfStartPoint = motionOfOrigin.getMotionOfPoint(offsetFromBegin);\n\tMotion motionOfEnd = motionOfStartPoint.getMotionOfPoint(relMotion.locationOfRelativeMotion.getPosition()).addRelativeMotion(relMotion.relativeMotion);\n\n\tRelativeMotion relMotionOfBeginIncluded = relMotion.extendBegin(offsetFromBegin);\n\tASSERT(motionOfEnd == relMotionOfBeginIncluded.applyTo(motionOfOrigin));\n}\n\nTEST_CASE(testExtendingRelativeMotionCFrameCorrect) {\n\tRelativeMotion relMotion = createRandomRelativeMotion();\n\tMotion motionOfOrigin = createRandomMotion();\n\tCFrame offsetFromBegin = createRandomCFrame();\n\tCFrame offsetFromEnd = createRandomCFrame();\n\n\t// manually compute resulting motion\n\tMotion motionOfStartPoint = motionOfOrigin.getMotionOfPoint(offsetFromBegin.getPosition());\n\tMotion rotatedRelativeMotion = localToGlobal(offsetFromBegin.getRotation(), relMotion.relativeMotion);\n\tCFrame rotatedOffset = offsetFromBegin.localToRelative(relMotion.locationOfRelativeMotion);\n\tMotion motionOfEnd = motionOfStartPoint.getMotionOfPoint(rotatedOffset.getPosition()).addRelativeMotion(rotatedRelativeMotion);\n\n\tRelativeMotion relMotionOfBeginIncluded = relMotion.extendBegin(offsetFromBegin);\n\tASSERT(motionOfEnd == relMotionOfBeginIncluded.applyTo(motionOfOrigin));\n}\n\nTEST_CASE(testJoiningRelativeMotionCorrect) {\n\tRelativeMotion r1 = createRandomRelativeMotion();\n\tRelativeMotion r2 = createRandomRelativeMotion();\n\n\tMotion motionOfEndPoint = r1.relativeMotion;\n\tCFrame offsetForSecondEndPoint = r1.locationOfRelativeMotion.localToRelative(r2.locationOfRelativeMotion);\n\n\tMotion secondMotionInNewSpace = localToGlobal(r1.locationOfRelativeMotion.getRotation(), r2.relativeMotion);\n\n\tMotion motionOfSecondEndPoint =\n\t\tmotionOfEndPoint.getMotionOfPoint(offsetForSecondEndPoint.getPosition())\n\t\t.addRelativeMotion(secondMotionInNewSpace);\n\n\tASSERT((r1 + r2).locationOfRelativeMotion == offsetForSecondEndPoint + r1.locationOfRelativeMotion.getPosition());\n\tASSERT((r1 + r2).relativeMotion == motionOfSecondEndPoint);\n}\n\nTEST_CASE(testComplexRelativeMotionAssociative) {\n\tMotion m0 = createRandomMotion();\n\tRelativeMotion r1 = createRandomRelativeMotion();\n\tRelativeMotion r2 = createRandomRelativeMotion();\n\tRelativeMotion r3 = createRandomRelativeMotion();\n\n\tASSERT((r1 + r2) + r3 == r1 + (r2 + r3));\n}\n\nTEST_CASE(testReducedRelativeMotionAssociative) {\n\tVec3 piston1Direction = createRandomNonzeroVec3();\n\tVec3 piston2Direction = createRandomNonzeroVec3();\n\tVec3 motor1Direction = createRandomNonzeroVec3();\n\tVec3 motor2Direction = createRandomNonzeroVec3();\n\n\tRelativeMotion p1(Motion(createRandomNonzeroDouble() * piston1Direction, Vec3(), createRandomNonzeroDouble() * piston1Direction, Vec3()), CFrame(createRandomNonzeroDouble() * piston1Direction));\n\tRelativeMotion p2(Motion(createRandomNonzeroDouble() * piston2Direction, Vec3(), createRandomNonzeroDouble() * piston2Direction, Vec3()), CFrame(createRandomNonzeroDouble() * piston2Direction));\n\tRelativeMotion m1(Motion(Vec3(), createRandomNonzeroDouble() * motor1Direction, Vec3(), createRandomNonzeroDouble() * motor1Direction), CFrame(createRandomNonzeroDouble() * motor1Direction));\n\tRelativeMotion m2(Motion(Vec3(), createRandomNonzeroDouble() * motor2Direction, Vec3(), createRandomNonzeroDouble() * motor2Direction), CFrame(createRandomNonzeroDouble() * motor2Direction));\n\n\tASSERT(p1 + p2 == p2 + p1); // pistons are commutative\n\tASSERT((p1 + p2) + m1 == p1 + (p2 + m1));\n\tASSERT((m1 + m2) + p1 == m1 + (m2 + p1));\n\tASSERT(((m1 + p1) + m2) + p2 == m1 + (p1 + (m2 + p2)));\n}\n\nTEST_CASE(testSimulateRelativeMotion) {\n\tMotion motionOfOrigin = createRandomMotion();\n\tRelativeMotion relMotion = createRandomRelativeMotion();\n\n\t/*motionOfOrigin.acceleration = Vec3(0, 0, 0);\n\trelMotion.relativeMotion.acceleration = Vec3(0, 0, 0);\n\tmotionOfOrigin.angularAcceleration = Vec3(0, 0, 0);\n\trelMotion.relativeMotion.angularAcceleration = Vec3(0, 0, 0);\n\trelMotion.relativeMotion.angularVelocity = Vec3(0, 0, 0);*/\n\t//relMotion.relativeMotion.velocity = Vec3(0, 0, 0); Coriolis effect!\n\n\tCFrame origin1 = CFrame();\n\tCFrame origin2 = simulateForTime(motionOfOrigin, CFrame(), DELTA_T);\n\tCFrame origin3 = simulateForTime(motionOfOrigin, CFrame(), 2 * DELTA_T);\n\n\tCFrame relative1 = relMotion.locationOfRelativeMotion;\n\tCFrame relative2 = simulateForTime(relMotion.relativeMotion, relMotion.locationOfRelativeMotion, DELTA_T);\n\tCFrame relative3 = simulateForTime(relMotion.relativeMotion, relMotion.locationOfRelativeMotion, 2 * DELTA_T);\n\n\tCFrame p1 = origin1.localToGlobal(relative1);\n\tCFrame p2 = origin2.localToGlobal(relative2);\n\tCFrame p3 = origin3.localToGlobal(relative3);\n\n\tMotion estimatedMotion = estimateMotion(p1, p2, p3, DELTA_T);\n\n\tMotion calculatedMotion = relMotion.applyTo(motionOfOrigin);\n\n\tASSERT(estimatedMotion == calculatedMotion);\n}\n\nTEST_CASE(testSimulateRelativeToRelativeMotion) {\n\tRelativeMotion motionOfOrigin = createRandomRelativeMotion();\n\tRelativeMotion relMotion = createRandomRelativeMotion();\n\n\t/*motionOfOrigin.acceleration = Vec3(0, 0, 0);\n\trelMotion.relativeMotion.acceleration = Vec3(0, 0, 0);\n\tmotionOfOrigin.angularAcceleration = Vec3(0, 0, 0);\n\trelMotion.relativeMotion.angularAcceleration = Vec3(0, 0, 0);\n\trelMotion.relativeMotion.angularVelocity = Vec3(0, 0, 0);*/\n\t//relMotion.relativeMotion.velocity = Vec3(0, 0, 0); Coriolis effect!\n\n\tCFrame origin1 = motionOfOrigin.locationOfRelativeMotion;\n\tCFrame origin2 = simulateForTime(motionOfOrigin.relativeMotion, motionOfOrigin.locationOfRelativeMotion, DELTA_T);\n\tCFrame origin3 = simulateForTime(motionOfOrigin.relativeMotion, motionOfOrigin.locationOfRelativeMotion, 2 * DELTA_T);\n\n\tCFrame relative1 = relMotion.locationOfRelativeMotion;\n\tCFrame relative2 = simulateForTime(relMotion.relativeMotion, relMotion.locationOfRelativeMotion, DELTA_T);\n\tCFrame relative3 = simulateForTime(relMotion.relativeMotion, relMotion.locationOfRelativeMotion, 2 * DELTA_T);\n\n\tCFrame p1 = origin1.localToGlobal(relative1);\n\tCFrame p2 = origin2.localToGlobal(relative2);\n\tCFrame p3 = origin3.localToGlobal(relative3);\n\n\tMotion estimatedMotion = estimateMotion(p1, p2, p3, DELTA_T);\n\n\tRelativeMotion calculatedMotion = motionOfOrigin + relMotion;\n\n\n\tASSERT(estimatedMotion == calculatedMotion.relativeMotion);\n\tASSERT(p1 == calculatedMotion.locationOfRelativeMotion);\n}\n"
  },
  {
    "path": "tests/physicalStructureTests.cpp",
    "content": "#include \"testsMain.h\"\n\n#include \"compare.h\"\n#include <Physics3D/misc/toString.h>\n\n#include \"randomValues.h\"\n#include \"estimateMotion.h\"\n\n#include <Physics3D/geometry/shape.h>\n#include <Physics3D/geometry/shapeCreation.h>\n#include <Physics3D/part.h>\n#include <Physics3D/physical.h>\n#include <Physics3D/hardconstraints/fixedConstraint.h>\n\nusing namespace P3D;\n#define ASSERT(x) ASSERT_STRICT(x)\n\nstatic CFrame cf() {\n\treturn createRandomCFrame();\n}\n\nstatic Part* createPart() {\n\treturn new Part(boxShape(1.0, 1.0, 1.0), GlobalCFrame(), {1.0, 1.0, 1.0});\n}\n\nTEST_CASE(testBasicCreateDestroy) {\n\tPart* p = createPart();\n\tp->ensureHasPhysical();\n\tdelete p;\n}\n\nTEST_CASE(testManyAttachBasic) {\n\tPart* a = createPart();\n\tPart* b = createPart();\n\tPart* c = createPart();\n\tPart* d = createPart();\n\n\ta->attach(b, cf());\n\ta->attach(c, cf());\n\tc->attach(d, cf());\n\n\t// a should be mainPart\n\tASSERT_TRUE(a->isMainPart());\n\tASSERT_FALSE(b->isMainPart());\n\tASSERT_FALSE(c->isMainPart());\n\tASSERT_FALSE(d->isMainPart());\n\n\tdelete b;\n\tdelete a;\n\tdelete c;\n\tdelete d;\n}\n\nTEST_CASE(testManualDetach) {\n\tPart* a = createPart();\n\tPart* b = createPart();\n\tPart* c = createPart();\n\tPart* d = createPart();\n\n\ta->attach(b, cf());\n\ta->attach(c, cf());\n\tc->attach(d, cf());\n\n\t// a should be mainPart\n\tASSERT_TRUE(a->isMainPart());\n\tASSERT_FALSE(b->isMainPart());\n\tASSERT_FALSE(c->isMainPart());\n\tASSERT_FALSE(d->isMainPart());\n\n\tb->detach();\n\tASSERT_TRUE(b->isMainPart());\n\n\ta->detach();\n\tASSERT(c->getPhysical()->rigidBody.mainPart != a);\n\n\tdelete b;\n\tdelete a;\n\tdelete c;\n\tdelete d;\n}\n\nTEST_CASE(testManyAttachComplex) {\n\tPart* a = createPart();\n\tPart* b = createPart();\n\tPart* c = createPart();\n\tPart* d = createPart();\n\n\tPart* e1 = createPart();\n\tPart* e2 = createPart();\n\te1->attach(e2, cf());\n\n\tPart* f1 = createPart();\n\tPart* f2 = createPart();\n\tf1->attach(f2, cf());\n\n\tPart* g1 = createPart();\n\tPart* g2 = createPart();\n\tg1->attach(g2, cf());\n\n\t// single new part attachments\n\ta->attach(b, cf());\n\tb->attach(c, cf());\n\td->attach(b, cf());\n\n\ta->attach(e1, cf());\n\ta->attach(f2, cf());\n\tg1->attach(a, cf());\n\n\tASSERT_TRUE(a->getPhysical()->rigidBody.getPartCount() == 10);\n\n\tPart* parts[]{a,b,c,d,e1,e2,f1,f2,g1,g2};\n\tPhysical* aParent = a->getPhysical();\n\tfor(Part* p : parts) {\n\t\tASSERT_TRUE(p->getPhysical() == aParent);\n\t\tdelete p;\n\t}\n}\n\nTEST_CASE(testBasicMakeMainPhysical) {\n\tPart* a = createPart();\n\tPart* b = createPart();\n\n\ta->attach(b, new FixedConstraint(), cf(), cf());\n\n\tASSERT_TRUE(a->getPhysical() != nullptr);\n\tASSERT_TRUE(b->getPhysical() != nullptr);\n\n\tASSERT_TRUE(a->getPhysical()->isMainPhysical());\n\tASSERT_FALSE(b->getPhysical()->isMainPhysical());\n\n\tMotorizedPhysical* m = b->getMainPhysical();\n\tMotorizedPhysical* resultingMain = b->getPhysical()->makeMainPhysical();\n\tASSERT_TRUE(resultingMain == m);\n\n\tASSERT_TRUE(b->getPhysical()->isMainPhysical());\n\tASSERT_FALSE(a->getPhysical()->isMainPhysical());\n\n\tASSERT_TRUE(a->getPhysical()->childPhysicals.size() == 0);\n\tASSERT_TRUE(b->getPhysical()->childPhysicals.size() == 1);\n\tASSERT_TRUE(&b->getPhysical()->childPhysicals[0] == a->getPhysical());\n\tASSERT_TRUE(a->isValid());\n\tASSERT_TRUE(b->isValid());\n}\n\nTEST_CASE(testAdvancedMakeMainPhysical) {\n\tPart* a = createPart();\n\tPart* b = createPart();\n\tPart* c = createPart();\n\tPart* d = createPart();\n\tPart* e = createPart();\n\tPart* f = createPart();\n\tPart* g = createPart();\n\n\ta->attach(b, new FixedConstraint(), cf(), cf());\n\ta->attach(e, new FixedConstraint(), cf(), cf());\n\tb->attach(c, new FixedConstraint(), cf(), cf());\n\tb->attach(d, new FixedConstraint(), cf(), cf());\n\te->attach(f, new FixedConstraint(), cf(), cf());\n\tf->attach(g, new FixedConstraint(), cf(), cf());\n\n\tconst int partCount = 7;\n\tPart* parts[partCount]{a,b,c,d,e,f,g};\n\n\tMotorizedPhysical* m = a->getMainPhysical();\n\n\tGlobalCFrame cframesBefore[partCount];\n\tfor(int i = 0; i < partCount; i++) {\n\t\tcframesBefore[i] = parts[i]->getCFrame();\n\t}\n\n\tm->fullRefreshOfConnectedPhysicals();\n\n\tfor(int i = 0; i < partCount; i++) {\n\t\tGlobalCFrame cfr = parts[i]->getCFrame();\n\t\tASSERT_TOLERANT(cframesBefore[i] == cfr, 0.0005);\n\t\tcframesBefore[i] = cfr;\n\t}\n\n\tMotorizedPhysical* resultingMain = f->getPhysical()->makeMainPhysical();\n\tASSERT_TRUE(resultingMain == m);\n\tASSERT_TRUE(m->isValid());\n\n\tfor(int i = 0; i < partCount; i++) {\n\t\tGlobalCFrame cfr = parts[i]->getCFrame();\n\t\tASSERT_TOLERANT(cframesBefore[i] == cfr, 0.0005);\n\t\tcframesBefore[i] = cfr;\n\t}\n\tm->fullRefreshOfConnectedPhysicals();\n\tfor(int i = 0; i < partCount; i++) {\n\t\tGlobalCFrame cfr = parts[i]->getCFrame();\n\t\tASSERT_TOLERANT(cframesBefore[i] == cfr, 0.0005);\n\t\tcframesBefore[i] = cfr;\n\t}\n}\n\nTEST_CASE(testAttachConnectedPhysicalToConnectedPhysical) {\n\tPart* a = createPart();\n\tPart* b = createPart();\n\tPart* c = createPart();\n\tPart* d = createPart();\n\tPart* e = createPart();\n\tPart* f = createPart();\n\tPart* g = createPart();\n\n\ta->attach(b, new FixedConstraint(), cf(), cf());\n\ta->attach(e, new FixedConstraint(), cf(), cf());\n\tb->attach(c, new FixedConstraint(), cf(), cf());\n\tb->attach(d, new FixedConstraint(), cf(), cf());\n\te->attach(f, new FixedConstraint(), cf(), cf());\n\tf->attach(g, new FixedConstraint(), cf(), cf());\n\n\tPart* a2 = createPart();\n\tPart* b2 = createPart();\n\tPart* c2 = createPart();\n\tPart* d2 = createPart();\n\tPart* e2 = createPart();\n\tPart* f2 = createPart();\n\tPart* g2 = createPart();\n\n\ta2->attach(b2, new FixedConstraint(), cf(), cf());\n\ta2->attach(e2, new FixedConstraint(), cf(), cf());\n\tb2->attach(c2, new FixedConstraint(), cf(), cf());\n\tb2->attach(d2, new FixedConstraint(), cf(), cf());\n\te2->attach(f2, new FixedConstraint(), cf(), cf());\n\tf2->attach(g2, new FixedConstraint(), cf(), cf());\n\n\te->attach(f2, new FixedConstraint(), cf(), cf());\n\n\tPart* parts[]{a,b,c,d,e,f,g,a2,b2,c2,d2,e2,f2,g2};\n\n\tMotorizedPhysical* mainPhys = a->getMainPhysical();\n\n\tfor(Part* p : parts) {\n\t\tASSERT_TRUE(p->getMainPhysical() == mainPhys);\n\t}\n\n\tfor(Part* p : parts) {\n\t\tdelete p;\n\t}\n}\n"
  },
  {
    "path": "tests/physicsTests.cpp",
    "content": "#include \"testsMain.h\"\n\n#include \"compare.h\"\n#include <Physics3D/misc/toString.h>\n#include \"simulation.h\"\n#include \"generators.h\"\n\n#include <Physics3D/world.h>\n#include <Physics3D/inertia.h>\n#include <Physics3D/math/linalg/trigonometry.h>\n#include <Physics3D/math/linalg/eigen.h>\n#include <Physics3D/math/constants.h>\n#include <Physics3D/geometry/shape.h>\n#include <Physics3D/geometry/shapeCreation.h>\n#include <Physics3D/geometry/shapeLibrary.h>\n#include <Physics3D/externalforces/directionalGravity.h>\n#include <Physics3D/hardconstraints/motorConstraint.h>\n#include <Physics3D/hardconstraints/sinusoidalPistonConstraint.h>\n#include <Physics3D/hardconstraints/fixedConstraint.h>\n#include \"../util/log.h\"\n\n\nusing namespace P3D;\n#define REMAINS_CONSTANT(v) REMAINS_CONSTANT_TOLERANT(v, 0.0005)\n#define ASSERT(v) ASSERT_TOLERANT(v, 0.0005)\n\nstatic const double DELTA_T = 0.01;\nstatic const int TICKS = 300;\n\nstatic const PartProperties basicProperties{0.7, 0.2, 0.6};\n\nTEST_CASE_SLOW(positionInvariance) {\n\tRotation rotation = Rotation::fromEulerAngles(0.0, 0.0, 0.0);\n\n\tPosition origins[]{Position(0,0,0), Position(0,0,1), Position(5.3,0,-2.4),Position(0.3,0,0.7),Position(0.0000001,0,0.00000001)};\n\n\tCFrame houseRelative(Vec3(0.7, 0.6, 1.6), Rotation::fromEulerAngles(0.3, 0.7, 0.9));\n\tCFrame icosaRelative(Vec3(0.7, 3.0, 1.6), Rotation::fromEulerAngles(0.1, 0.1, 0.1));\n\n\tfor(Position o:origins) {\n\t\tGlobalCFrame origin(o, rotation);\n\n\t\tWorldPrototype world(DELTA_T);\n\t\tworld.addExternalForce(new DirectionalGravity(Vec3(0, -1, 0)));\n\n\t\tPart housePart(polyhedronShape(ShapeLibrary::house), origin.localToGlobal(houseRelative), {1.0, 1.0, 0.7});\n\t\tPart icosaPart(polyhedronShape(ShapeLibrary::icosahedron), origin.localToGlobal(icosaRelative), {10.0, 0.7, 0.7});\n\t\tPart flooring(boxShape(200.0, 0.3, 200.0), origin, {1.0, 1.0, 0.7});\n\n\t\tworld.addPart(&housePart);\n\t\tworld.addPart(&icosaPart);\n\t\tworld.addTerrainPart(&flooring);\n\n\t\tfor(int i = 0; i < TICKS; i++)\n\t\t\tworld.tick();\n\n\t\tREMAINS_CONSTANT_TOLERANT(origin.globalToLocal(housePart.getCFrame()), 0.0002);\n\t\tREMAINS_CONSTANT_TOLERANT(origin.globalToLocal(icosaPart.getCFrame()), 0.0002);\n\t}\n}\n\nTEST_CASE_SLOW(rotationInvariance) {\n\tCFrame houseRelative(Vec3(0.7, 0.6, 1.6), Rotation::fromEulerAngles(0.3, 0.7, 0.9));\n\tCFrame icosaRelative(Vec3(0.7, 3.0, 1.6), Rotation::fromEulerAngles(0.1, 0.1, 0.1));\n\n\tfor(double rotation = -1.5; rotation < 1.500001; rotation += 0.3) {\n\t\tlogStream << rotation << '\\n';\n\n\t\tGlobalCFrame origin(Position(0.0,0.0,0.0), Rotation::rotY(rotation));\n\n\t\tWorldPrototype world(DELTA_T);\n\t\tworld.addExternalForce(new DirectionalGravity(Vec3(0, -1, 0)));\n\n\t\tPart housePart(polyhedronShape(ShapeLibrary::house), origin.localToGlobal(houseRelative), {1.0, 1.0, 0.7});\n\t\tPart icosaPart(polyhedronShape(ShapeLibrary::icosahedron), origin.localToGlobal(icosaRelative), {10.0, 0.7, 0.7});\n\t\tPart flooring(boxShape(200.0, 0.3, 200.0), origin, {1.0, 1.0, 0.7});\n\n\t\tworld.addPart(&housePart);\n\t\tworld.addPart(&icosaPart);\n\t\tworld.addTerrainPart(&flooring);\n\n\t\tfor(int i = 0; i < TICKS; i++)\n\t\t\tworld.tick();\n\n\t\tREMAINS_CONSTANT_TOLERANT(origin.globalToLocal(housePart.getCFrame()), 0.02);\n\t\tREMAINS_CONSTANT_TOLERANT(origin.globalToLocal(icosaPart.getCFrame()), 0.02);\n\t}\n}\n\nTEST_CASE(applyForceToRotate) {\n\tPart part(boxShape(1.0, 1.0, 1.0), GlobalCFrame(0,0,0, Rotation::fromEulerAngles(0.3, 0.7, 0.9)), {1.0, 1.0, 0.7});\n\tPhysical* partPhys = part.ensureHasPhysical();\n\n\tVec3 relAttach = Vec3(1.0, 0.0, 0.0);\n\tVec3 force = Vec3(0.0, 1.0, 0.0);\n\n\tpartPhys->mainPhysical->applyForce(relAttach, force);\n\tASSERT(partPhys->mainPhysical->totalForce == force);\n\tASSERT(partPhys->mainPhysical->totalMoment == Vec3(0.0, 0.0, 1.0));\n}\n\nTEST_CASE(momentToAngularVelocity) {\n\tPart part(boxShape(1.0, 1.0, 1.0), GlobalCFrame(Rotation::rotY(PI / 2)), {1.0, 1.0, 0.7});\n\tMotorizedPhysical& p = *part.ensureHasPhysical()->mainPhysical;\n\n\tVec3 moment(1.0, 0.0, 0.0);\n\n\tfor(int i = 0; i < 50; i++) {\n\t\tp.applyMoment(moment);\n\t\tp.update(0.05);\n\t}\n\n\tASSERT(p.getMotion().getAngularVelocity() == moment * (50.0 * 0.05) * p.momentResponse(0, 0));\n}\n\nTEST_CASE(rotationImpulse) {\n\tPart part(boxShape(0.2, 20.0, 0.2), GlobalCFrame(0,0,0), {1.0, 1.0, 0.7});\n\tMotorizedPhysical& veryLongBoxPhysical = *part.ensureHasPhysical()->mainPhysical;\n\n\tVec3 xMoment = Vec3(1.0, 0.0, 0.0);\n\tVec3 yMoment = Vec3(0.0, 1.0, 0.0);\n\tVec3 zMoment = Vec3(0.0, 0.0, 1.0);\n\n\t{\n\t\tveryLongBoxPhysical.totalForce = Vec3();\n\t\tveryLongBoxPhysical.totalMoment = Vec3();\n\t}\n}\n\n/*TEST_CASE(testPointAcceleration) {\n\tPart testPart(boxShape(1.0, 2.0, 3.0), GlobalCFrame(0,0,0), {1.0, 1.0, 0.7});\n\ttestPart.ensureHasPhysical();\n\tMotorizedPhysical& testPhys = *testPart.getMainPhysical();\n\tVec3 localPoint(3, 5, 7);\n\tVec3 force(-4, -3, 0.5);\n\tdouble deltaT = 0.00001;\n\n\ttestPhys.applyForce(localPoint, force);\n\n\tVec3 acceleration = testPhys.getMotion().getAcceleration();\n\tVec3 angularAcceleration = testPhys.getMotion().rotation.angularAcceleration;\n\tVec3 pointAcceleration = testPhys.getMotion().getAccelerationOfPoint(localPoint);\n\n\ttestPhys.update(deltaT);\n\n\tVec3 actualAcceleration = testPhys.getMotion().getVelocity() / deltaT;\n\tVec3 actualAngularAcceleration = testPhys.getMotion().rotation.angularVelocity / deltaT;\n\tVec3 actualPointAcceleration = testPhys.getMotion().getVelocityOfPoint(testPhys.getCFrame().localToRelative(localPoint)) / deltaT;\n\n\tASSERT(acceleration == actualAcceleration);\n\tASSERT(angularAcceleration == actualAngularAcceleration);\n\tASSERT(pointAcceleration == actualPointAcceleration);\n}*/\n\n/*TEST_CASE(testGetPointAccelerationMatrix) {\n\tPart testPart(boxShape(1.0, 2.0, 3.0), GlobalCFrame(0,0,0), {1.0, 1.0, 0.7});\n\ttestPart.ensureHasPhysical();\n\tMotorizedPhysical& testPhys = *testPart.getMainPhysical();\n\tVec3 localPoint(3, 5, 7);\n\tVec3 force(-4, -3, 0.5);\n\n\ttestPhys.applyForce(localPoint, force);\n\n\tSymmetricMat3 accelMatrix = testPhys.getResponseMatrix(localPoint);\n\n\tlogStream << accelMatrix;\n\n\tVec3 actualAcceleration = testPhys.getMotion().getAccelerationOfPoint(localPoint);\n\n\tASSERT(actualAcceleration == accelMatrix * force);\n}*/\nTEST_CASE(impulseTest) {\n\tPart part(boxShape(1.0, 2.0, 2.5), GlobalCFrame(0,0,0), {1.0, 1.0, 0.7});\n\tMotorizedPhysical& p = *part.ensureHasPhysical()->mainPhysical;\n\n\tp.applyImpulseAtCenterOfMass(Vec3(15, 0, 0));\n\tASSERT(p.getMotion().getVelocity() == Vec3(3,0,0));\n\tASSERT(p.getMotion().getAngularVelocity() == Vec3(0, 0, 0));\n\n\tVec3 angularImpulse = Vec3(0, 2, 0) % Vec3(-15, 0, 0);\n\n\tp.applyImpulse(Vec3(0, 2, 0), Vec3(-15, 0, 0));\n\tASSERT(p.getMotion().getVelocity() == Vec3(0, 0, 0));\n\tASSERT(p.getMotion().getAngularVelocity() == ~part.getInertia() * angularImpulse);\n}\n\nTEST_CASE(testPointAccelMatrixImpulse) {\n\tPart part(boxShape(1.0, 2.0, 3.0), GlobalCFrame(7.6, 3.4, 3.9, Rotation::fromEulerAngles(1.1, 0.7, 0.9)), {1.0, 1.0, 0.7});\n\tMotorizedPhysical& p = *part.ensureHasPhysical()->mainPhysical;\n\n\tVec3 localPoint(0.8, 0.6, 0.9);\n\tVec3 localImpulse(0.3, -0.7, 0.6);\n\n\tVec3 estimatedAccel = p.getResponseMatrix(localPoint) * localImpulse;\n\n\tp.applyImpulse(part.getCFrame().localToRelative(localPoint), part.getCFrame().localToRelative(localImpulse));\n\n\tVec3 realAccel = part.getCFrame().relativeToLocal(p.getMotion().getVelocityOfPoint(part.getCFrame().localToRelative(localPoint)));\n\n\tASSERT(estimatedAccel == realAccel);\n}\n\nTEST_CASE(inelasticColission) {\n\tPart part(boxShape(1.0, 2.0, 3.0), GlobalCFrame(7.6, 3.4, 3.9, Rotation::fromEulerAngles(1.1, 0.7, 0.9)), {1.0, 1.0, 0.7});\n\tMotorizedPhysical& p = *part.ensureHasPhysical()->mainPhysical;\n\n\tVec3 localPoint(0.8, 0.6, 0.9);\n\tVec3 relativePoint = p.getCFrame().localToRelative(localPoint);\n\n\tp.getMotion().getVelocity() = Vec3(0.3, -1.3, 1.2);\n\tp.getMotion().getAngularVelocity() = Vec3(0.7, 0.5, -0.9);\n\n\tVec3 velOfPoint = p.getMotion().getVelocityOfPoint(relativePoint);\n\n\tASSERT(velOfPoint.y < 0);\n\n\tlogStream << \"totalVelocity: \" << str(velOfPoint);\n\n\tVec3 direction(0.0, 170.0, 0.0);\n\n\t//double inertia = p.getInertiaOfPointInDirection(localPoint, p.getCFrame().relativeToLocal(direction));\n\n\t//Log::warn(\"inertia: %f\", inertia);\n\n\tlogStream << \"velInDirection: \" << velOfPoint * normalize(direction);\n\n\t//Vec3 relativeImpulse = -velOfPoint * direction.normalize() * direction.normalize() * inertia;\n\n\tVec3 desiredAccel = -velOfPoint * direction * direction / lengthSquared(direction);\n\tVec3 relativeImpulse = p.getCFrame().localToRelative(~p.getResponseMatrix(localPoint) * p.getCFrame().relativeToLocal(desiredAccel));\n\tVec3 estimatedAccelLocal = p.getResponseMatrix(localPoint) * p.getCFrame().relativeToLocal(relativeImpulse);\n\n\tVec3 estimatedAccelRelative = p.getCFrame().localToRelative(estimatedAccelLocal);\n\t\n\n\tp.applyImpulse(relativePoint, relativeImpulse);\n\t\n\n\tVec3 velOfPointAfter = p.getMotion().getVelocityOfPoint(relativePoint);\n\tlogStream << \"New velocity: \" << str(velOfPointAfter);\n\tlogStream << \"velInDirection After: \" << velOfPointAfter * normalize(direction);\n\tlogStream << \"estimatedAccelRelative: \" << str(estimatedAccelRelative);\n\tlogStream << \"Actual accel:           \" << str(velOfPointAfter - velOfPoint);\n\n\tASSERT(estimatedAccelRelative == velOfPointAfter - velOfPoint);\n\tASSERT(velOfPointAfter.y == 0);\n}\n\nTEST_CASE(inelasticColission2) {\n\tPart part(boxShape(1.0, 2.0, 3.0), GlobalCFrame(/*Vec3(7.6, 3.4, 3.9), rotationMatrixfromEulerAngles(1.1, 0.7, 0.9)*/), {1.0, 1.0, 0.7});\n\tMotorizedPhysical& p = *part.ensureHasPhysical()->mainPhysical;\n\n\tVec3 localPoint(0.8, 0.6, 0.9);\n\tVec3 relativePoint = p.getCFrame().localToRelative(localPoint);\n\tVec3 normal(0.0, 170.0, 0.0);\n\n\tp.getMotion().getVelocity() = Vec3(0.3, -1.3, 1.2);\n\tp.getMotion().getAngularVelocity() = Vec3(0.7, 0.5, -0.9);\n\n\tVec3 velOfPoint = p.getMotion().getVelocityOfPoint(relativePoint);\n\n\tASSERT(velOfPoint.y < 0);\n\n\tdouble inertia = p.getInertiaOfPointInDirectionRelative(localPoint, normal);\n\n\tdouble normalVelocity = velOfPoint * normalize(normal);\n\n\tdouble desiredAccel = -normalVelocity;\n\n\tVec3 impulse = normalize(normal) * desiredAccel * inertia;\n\n\n\n\tp.applyImpulse(relativePoint, impulse);\n\n\n\tVec3 velOfPointAfter = p.getMotion().getVelocityOfPoint(relativePoint);\n\tlogStream << \"New velocity: \" + str(velOfPointAfter);\n\tlogStream << \"velInDirection After: \", velOfPointAfter * normalize(normal);\n\t//logStream << \"estimatedAccelRelative: \" + str(estimatedAccelRelative);\n\tlogStream << \"Actual accel:           \" + str(velOfPointAfter - velOfPoint);\n\n\t//ASSERT(estimatedAccelRelative == velOfPointAfter - velOfPoint);\n\tASSERT(velOfPointAfter.y == 0);\n}\n\n/*TEST_CASE(testPointAccelMatrixAndInertiaInDirection) {\n\tPart part(boxShape(1.0, 1.0, 1.0), GlobalCFrame(Position(7.6, 3.4, 3.9), Rotation::fromEulerAngles(1.1, 0.7, 0.9)), {1.0, 1.0, 0.7});\n\tMotorizedPhysical p(&part);\n\n\tVec3 localPoint(0.8, 0.6, 0.9);\n\tVec3 localImpulse(0.3, -0.7, 0.6);\n\n\tVec3 estimatedAccel = p.getResponseMatrix(localPoint) * localImpulse;\n\n\tp.applyImpulse(part.getCFrame().localToRelative(localPoint), part.getCFrame().localToRelative(localImpulse));\n\n\tVec3 realAccel = part.getCFrame().relativeToLocal(p.getVelocityOfPoint(part.getCFrame().localToRelative(localPoint)));\n\n\tASSERT(estimatedAccel == realAccel);\n}*/\n\nTEST_CASE(testChangeInertialBasis) {\n\tRotation rotation = Rotation::fromEulerAngles(0.6, 0.3, 0.7);\n\tPolyhedron rotatedTriangle = ShapeLibrary::trianglePyramid.rotated(static_cast<Rotationf>(rotation));\n\tSymmetricMat3 triangleInertia = ShapeLibrary::trianglePyramid.getInertia(CFrame());\n\tSymmetricMat3 rotatedTriangleInertia = rotatedTriangle.getInertia(CFrame());\n\n\tASSERT(getEigenDecomposition(triangleInertia).eigenValues == getEigenDecomposition(rotatedTriangleInertia).eigenValues);\n\tASSERT(getRotatedInertia(triangleInertia, rotation) == rotatedTriangleInertia);\n}\n\nTEST_CASE(testMultiPartPhysicalSimple) {\n\tShape box(boxShape(1.0, 0.5, 0.5));\n\tShape box2(boxShape(1.0, 0.5, 0.5));\n\tShape doubleBox(boxShape(2.0, 0.5, 0.5));\n\tPart p1(box, GlobalCFrame(), {10.0, 0.5, 0.5});\n\tPart p2(box2, GlobalCFrame(), {10.0, 0.5, 0.5});\n\tPart doubleP(doubleBox, GlobalCFrame(), {10.0, 0.5, 0.5});\n\n\tp1.ensureHasPhysical();\n\tMotorizedPhysical& phys = *p1.getMainPhysical();\n\tphys.attachPart(&p2, CFrame(Vec3(1.0, 0.0, 0.0)));\n\n\tdoubleP.ensureHasPhysical();\n\tMotorizedPhysical& phys2 = *doubleP.getMainPhysical();\n\n\tASSERT(phys.totalMass == p1.getMass() + p2.getMass());\n\tASSERT(phys.totalCenterOfMass == Vec3(0.5, 0, 0));\n\tASSERT(phys.forceResponse == phys2.forceResponse);\n\tASSERT(phys.momentResponse == phys2.momentResponse);\n}\n\nTEST_CASE(testMultiPartPhysicalRotated) {\n\tShape box(boxShape(1.0, 0.5, 0.5));\n\tShape box2(boxShape(0.5, 0.5, 1.0));\n\tShape doubleBox(boxShape(2.0, 0.5, 0.5));\n\tPart* p1 = new Part(box, GlobalCFrame(), {10.0, 0.0, 0.7});\n\tPart* p2 = new Part(box2, GlobalCFrame(), {10.0, 0.0, 0.7});\n\tPart* doubleP = new Part(doubleBox, GlobalCFrame(), {10.0, 0, 0.7});\n\n\tMotorizedPhysical phys(p1);\n\tphys.attachPart(p2, CFrame(Vec3(1.0, 0.0, 0.0), Rotation::Predefined::Y_90));\n\n\tMotorizedPhysical phys2(doubleP);\n\n\tASSERT(phys.totalMass == p1->getMass() + p2->getMass());\n\tASSERT(phys.totalCenterOfMass == Vec3(0.5, 0, 0));\n\tASSERT(phys.forceResponse == phys2.forceResponse);\n\tASSERT(phys.momentResponse == phys2.momentResponse);\n}\n\nTEST_CASE(testShapeNativeScaling) {\n\tPolyhedron testPoly = ShapeLibrary::createPointyPrism(4, 1.0f, 1.0f, 0.5f, 0.5f);\n\n\tShape shape1(polyhedronShape(testPoly));\n\tShape shape2 = shape1.scaled(2.0, 4.0, 3.7);\n\n\tPolyhedron scaledTestPoly = testPoly.scaled(2.0f, 4.0f, 3.7f);\n\n\tASSERT(shape2.getInertia() == scaledTestPoly.getInertiaAroundCenterOfMass());\n}\n\nTEST_CASE(testPhysicalInertiaDerivatives) {\n\tPolyhedron testPoly = ShapeLibrary::createPointyPrism(4, 1.0f, 1.0f, 0.5f, 0.5f);\n\n\tPart mainPart(polyhedronShape(testPoly), GlobalCFrame(), basicProperties);\n\tPart part1_mainPart(polyhedronShape(ShapeLibrary::house), mainPart, \n\t\t\t\t\t\tnew SinusoidalPistonConstraint(0.0, 2.0, 1.3), \n\t\t\t\t\t\tCFrame(0.3, 0.7, -0.5, Rotation::fromEulerAngles(0.7, 0.3, 0.7)), \n\t\t\t\t\t\tCFrame(0.1, 0.2, -0.5, Rotation::fromEulerAngles(0.2, -0.257, 0.4)), basicProperties);\n\tPart part2_mainPart(boxShape(1.0, 0.3, 2.0), mainPart, \n\t\t\t\t\t\tnew MotorConstraintTemplate<ConstantMotorTurner>(1.7),\n\t\t\t\t\t\tCFrame(-0.3, 0.7, 0.5, Rotation::fromEulerAngles(0.7, 0.3, 0.7)), \n\t\t\t\t\t\tCFrame(0.1, -0.2, -0.5, Rotation::fromEulerAngles(0.2, -0.257, 0.4)), basicProperties);\n\tPart part1_part1_mainPart(cylinderShape(1.0, 0.3), part1_mainPart, \n\t\t\t\t\t\tnew MotorConstraintTemplate<ConstantMotorTurner>(1.3),\n\t\t\t\t\t\tCFrame(-0.3, 0.7, 0.5, Rotation::fromEulerAngles(0.7, 0.3, 0.7)),\n\t\t\t\t\t\tCFrame(0.1, -0.2, -0.5, Rotation::fromEulerAngles(0.2, -0.257, 0.4)) , basicProperties);\n\tPart part1_part1_part1_mainPart(polyhedronShape(ShapeLibrary::trianglePyramid), part1_part1_mainPart, \n\t\t\t\t\t\tnew SinusoidalPistonConstraint(0.0, 2.0, 1.3),\n\t\t\t\t\t\tCFrame(0.3, 0.7, -0.5, Rotation::fromEulerAngles(0.7, 0.3, 0.7)),\n\t\t\t\t\t\tCFrame(0.1, 0.2, -0.5, Rotation::fromEulerAngles(0.2, -0.257, 0.4)), basicProperties);\n\n\tMotorizedPhysical* motorPhys = mainPart.getMainPhysical();\n\n\tstd::size_t size = motorPhys->getNumberOfPhysicalsInThisAndChildren() - 1;\n\tUnmanagedArray<MonotonicTreeNode<RelativeMotion>> arr(new MonotonicTreeNode<RelativeMotion>[size], size);\n\tFullTaylor<SymmetricMat3> inertiaTaylor = motorPhys->getCOMMotionTree(std::move(arr)).getInertiaDerivatives();\n\n\tdouble deltaT = 0.00001;\n\n\tstd::array<SymmetricMat3, 3> inertias;\n\tinertias[0] = motorPhys->getCOMMotionTree(std::move(arr)).getInertia();\n\tmotorPhys->update(deltaT);\n\tinertias[1] = motorPhys->getCOMMotionTree(std::move(arr)).getInertia();\n\tmotorPhys->update(deltaT);\n\tinertias[2] = motorPhys->getCOMMotionTree(std::move(arr)).getInertia();\n\n\tdelete[] arr.getPtrToFree();\n\n\tFullTaylor<SymmetricMat3> estimatedInertiaTaylor = estimateDerivatives(inertias, deltaT);\n\n\tASSERT_TOLERANT(inertiaTaylor == estimatedInertiaTaylor, 0.01);\n}\n\nTEST_CASE(testCenterOfMassKept) {\n\tPolyhedron testPoly = ShapeLibrary::createPointyPrism(4, 1.0f, 1.0f, 0.5f, 0.5f);\n\n\tPart mainPart(boxShape(1.0, 1.0, 1.0), GlobalCFrame(), basicProperties);\n\tPart part1_mainPart(boxShape(1.0, 1.0, 1.0), mainPart,\n\t\t\t\t\t\tnew SinusoidalPistonConstraint(0.0, 2.0, 1.0),\n\t\t\t\t\t\tCFrame(0.0, 0.0, 0.0, Rotation::Predefined::IDENTITY),\n\t\t\t\t\t\tCFrame(0.0, 0.0, 0.0, Rotation::Predefined::IDENTITY), basicProperties);\n\n\tALLOCA_COMMotionTree(t, mainPart.getMainPhysical(), size);\n\n\tlogStream << t.getRelativePosOfMain();\n\n\tASSERT(t.getRelativePosOfMain() == -t.relativeMotionTree[0].value.locationOfRelativeMotion.getPosition());\n\tASSERT(t.getMotionOfMain() == -t.relativeMotionTree[0].value.relativeMotion.translation);\n}\n\nTEST_CASE(testBasicAngularMomentum) {\n\tdouble motorSpeed = 1.0;\n\tMotorConstraintTemplate<ConstantMotorTurner>* constraint = new MotorConstraintTemplate<ConstantMotorTurner>(motorSpeed);\n\n\tPart mainPart(cylinderShape(1.0, 1.0), GlobalCFrame(), basicProperties);\n\tPart attachedPart(cylinderShape(1.0, 1.0), mainPart,\n\t\t\t\t\t  constraint,\n\t\t\t\t\t\tCFrame(0.0, 0.0, 0.0, Rotation::Predefined::IDENTITY),\n\t\t\t\t\t\tCFrame(0.0, 0.0, 0.0, Rotation::Predefined::IDENTITY), basicProperties);\n\n\tALLOCA_COMMotionTree(t, mainPart.getMainPhysical(), size);\n\n\tSymmetricMat3 inertia = attachedPart.getInertia();\n\tVec3 angularVel = constraint->getRelativeMotion().relativeMotion.getAngularVelocity();\n\tVec3 angularMomentum = inertia * angularVel;\n\n\tASSERT(t.getInternalAngularMomentum() == angularMomentum);\n}\n\nTEST_CASE(testBasicAngularMomentumTurned) {\n\tdouble motorSpeed = 1.0;\n\tMotorConstraintTemplate<ConstantMotorTurner>* constraint = new MotorConstraintTemplate<ConstantMotorTurner>(motorSpeed);\n\n\tPart mainPart(cylinderShape(1.0, 1.0), GlobalCFrame(), basicProperties);\n\tPart attachedPart(cylinderShape(1.0, 1.0), mainPart,\n\t\t\t\t\t  constraint,\n\t\t\t\t\t  CFrame(0.0, 0.0, 0.0, Rotation::Predefined::Y_90),\n\t\t\t\t\t  CFrame(0.0, 0.0, 0.0, Rotation::Predefined::IDENTITY), basicProperties);\n\n\t\n\tALLOCA_COMMotionTree(t, mainPart.getMainPhysical(), size);\n\n\tSymmetricMat3 inertia = attachedPart.getInertia();\n\tVec3 angularVel = constraint->getRelativeMotion().relativeMotion.getAngularVelocity();\n\tVec3 angularMomentum = Rotation::Predefined::Y_90.localToGlobal(inertia * angularVel);\n\n\tASSERT(t.getInternalAngularMomentum() == angularMomentum);\n}\n\nTEST_CASE(testFixedConstraintAngularMomentum) {\n\tdouble motorSpeed = 1.0;\n\n\t\n\tMotorConstraintTemplate<ConstantMotorTurner>* constraint1 = new MotorConstraintTemplate<ConstantMotorTurner>(motorSpeed);\n\n\tdouble offset = 5.0;\n\n\tPart mainPart1(cylinderShape(1.0, 1.0), GlobalCFrame(), basicProperties);\n\tPart attachedPart1(cylinderShape(1.0, 1.0), mainPart1,\n\t\t\t\t\t\tconstraint1,\n\t\t\t\t\t\tCFrame(0.0, 0.0, 0.0, Rotation::Predefined::IDENTITY),\n\t\t\t\t\t\tCFrame(0.0, 0.0, 0.0, Rotation::Predefined::IDENTITY), basicProperties);\n\tPart attachedPart1A(boxShape(1.0, 1.0, 1.0), attachedPart1,\n\t\t\t\t\t\tnew FixedConstraint(),\n\t\t\t\t\t\tCFrame(0.0, 0.0, 0.0, Rotation::Predefined::IDENTITY),\n\t\t\t\t\t\tCFrame(offset, 0.0, 0.0, Rotation::Predefined::IDENTITY), basicProperties);\n\tPart attachedPart1B(boxShape(1.0, 1.0, 1.0), attachedPart1,\n\t\t\t\t\t\tnew FixedConstraint(),\n\t\t\t\t\t\tCFrame(0.0, 0.0, 0.0, Rotation::Predefined::IDENTITY),\n\t\t\t\t\t\tCFrame(-offset, 0.0, 0.0, Rotation::Predefined::IDENTITY), basicProperties);\n\n\tALLOCA_COMMotionTree(t1, mainPart1.getMainPhysical(), size1);\n\n\tMotorConstraintTemplate<ConstantMotorTurner>* constraint2 = new MotorConstraintTemplate<ConstantMotorTurner>(motorSpeed);\n\n\tPart mainPart2(cylinderShape(1.0, 1.0), GlobalCFrame(), basicProperties);\n\tPart attachedPart2(cylinderShape(1.0, 1.0), mainPart2,\n\t\t\t\t\t\tconstraint2,\n\t\t\t\t\t\tCFrame(0.0, 0.0, 0.0, Rotation::Predefined::IDENTITY),\n\t\t\t\t\t\tCFrame(0.0, 0.0, 0.0, Rotation::Predefined::IDENTITY), basicProperties);\n\tPart attachedPart2A(boxShape(1.0, 1.0, 1.0), attachedPart2,\n\t\t\t\t\t\tCFrame(offset, 0.0, 0.0, Rotation::Predefined::IDENTITY), basicProperties);\n\tPart attachedPart2B(boxShape(1.0, 1.0, 1.0), attachedPart2,\n\t\t\t\t\t\tCFrame(-offset, 0.0, 0.0, Rotation::Predefined::IDENTITY), basicProperties);\n\n\tALLOCA_COMMotionTree(t2, mainPart2.getMainPhysical(), size2);\n\t\n\tASSERT(t1.totalMass == t2.totalMass);\n\tASSERT(t1.centerOfMass == t2.centerOfMass);\n\tASSERT(t1.motionOfCenterOfMass == t2.motionOfCenterOfMass);\n\tASSERT(t1.getInertia() == t2.getInertia());\n\tASSERT(t1.getInertiaDerivatives() == t2.getInertiaDerivatives());\n\tASSERT(t1.getMotion() == t2.getMotion());\n\tASSERT(t1.getInternalAngularMomentum() == t2.getInternalAngularMomentum());\n}\n\nstatic Position getTotalCenterOfMassOfPhysical(const MotorizedPhysical* motorPhys) {\n\tdouble totalMass = 0.0;\n\tVec3 totalCenterOfMass(0.0, 0.0, 0.0);\n\n\tmotorPhys->forEachPart([&totalMass, &totalCenterOfMass](const Part& p) {\n\t\tconst GlobalCFrame& pcf = p.getCFrame();\n\t\tconst Vec3 pcom = p.getCenterOfMass() - Position(0,0,0);\n\t\ttotalCenterOfMass += pcom * p.getMass();\n\t\ttotalMass += p.getMass();\n\t});\n\n\treturn Position(0, 0, 0) + totalCenterOfMass / totalMass;\n}\n\nstatic Vec3 getTotalMotionOfCenterOfMassOfPhysical(const MotorizedPhysical* motorPhys) {\n\tdouble totalMass = 0.0;\n\tVec3 totalVelocityOfCenterOfMass(0.0, 0.0, 0.0);\n\n\tmotorPhys->forEachPart([&totalMass, &totalVelocityOfCenterOfMass](const Part& p) {\n\t\tconst GlobalCFrame& pcf = p.getCFrame();\n\t\tVec3 relativePartCOM = pcf.localToRelative(p.getLocalCenterOfMass());\n\t\tMotion m = p.getMotion().getMotionOfPoint(relativePartCOM);\n\t\tVec3 relVel = m.getVelocity();\n\t\ttotalVelocityOfCenterOfMass += relVel * p.getMass();\n\t\ttotalMass += p.getMass();\n\t});\n\n\treturn totalVelocityOfCenterOfMass / totalMass;\n}\n\nstatic SymmetricMat3 getTotalInertiaOfPhysical(const MotorizedPhysical* motorPhys) {\n\tSymmetricMat3 totalInertia{\n\t\t0.0, \n\t\t0.0, 0.0, \n\t\t0.0, 0.0, 0.0\n\t};\n\tPosition com = motorPhys->getCenterOfMass();\n\n\tmotorPhys->forEachPart([&com, &totalInertia](const Part& p) {\n\t\tconst GlobalCFrame& pcf = p.getCFrame();\n\t\tSymmetricMat3 globalInertia = pcf.getRotation().localToGlobal(p.getInertia());\n\t\tVec3 relativePartCOM = pcf.localToRelative(p.getLocalCenterOfMass());\n\t\tVec3 offset = p.getCenterOfMass() - com;\n\t\tSymmetricMat3 inertiaOfThis = getTranslatedInertiaAroundCenterOfMass(globalInertia, p.getMass(), offset);\n\t\ttotalInertia += inertiaOfThis;\n\t});\n\n\treturn totalInertia;\n}\n\nstatic Vec3 getTotalAngularMomentumOfPhysical(const MotorizedPhysical* motorPhys) {\n\tVec3 totalAngularMomentum(0.0, 0.0, 0.0);\n\tPosition com = motorPhys->getCenterOfMass();\n\tVec3 comVel = motorPhys->getMotionOfCenterOfMass().getVelocity();\n\n\tmotorPhys->forEachPart([&com, &comVel, &totalAngularMomentum](const Part& p) {\n\t\tconst GlobalCFrame& pcf = p.getCFrame();\n\t\tSymmetricMat3 globalInertia = pcf.getRotation().localToGlobal(p.getInertia());\n\t\tVec3 relativePartCOM = pcf.localToRelative(p.getLocalCenterOfMass());\n\t\tVec3 offset = p.getCenterOfMass() - com;\n\t\tMotion m = p.getMotion().getMotionOfPoint(relativePartCOM);\n\t\tVec3 relVel = m.getVelocity();\n\t\tVec3 angMomOfThis = getAngularMomentumFromOffset(offset, relVel, m.getAngularVelocity(), globalInertia, p.getMass());\n\t\ttotalAngularMomentum += angMomOfThis;\n\t});\n\n\treturn totalAngularMomentum;\n}\n\nstd::vector<Part> producePhysical() {\n\tstd::vector<Part> result;\n\tresult.reserve(10);\n\tPart& mainPart = result.emplace_back(polyhedronShape(ShapeLibrary::house.rotated(Rotationf::fromEulerAngles(1.0f, -0.3f, 0.5f))), GlobalCFrame(), PartProperties{0.7, 0.2, 0.6});\n\n\tmainPart.ensureHasPhysical();\n\n\tPart& part1_mainPart = result.emplace_back(polyhedronShape(ShapeLibrary::house), mainPart,\n\t\t\t\t\t\t\t\t\t\t\tCFrame(0.3, 0.7, -0.5, Rotation::fromEulerAngles(0.7, 0.3, 0.7)), basicProperties);\n\tPart& part2_mainPart = result.emplace_back(boxShape(1.0, 0.3, 2.0), mainPart,\n\t\t\t\t\t\t\t\t\t\t\tCFrame(0.1, -0.2, -0.5, Rotation::fromEulerAngles(0.2, -0.257, 0.4)), basicProperties);\n\tPart& part1_part1_mainPart = result.emplace_back(cylinderShape(1.0, 0.3), part1_mainPart,\n\t\t\t\t\t\t\t\t\t\t\tCFrame(0.1, -0.2, -0.5, Rotation::fromEulerAngles(0.2, -0.257, 0.4)), basicProperties);\n\tPart& part1_part1_part1_mainPart = result.emplace_back(polyhedronShape(ShapeLibrary::trianglePyramid), part1_part1_mainPart,\n\t\t\t\t\t\t\t\t\t\t\tCFrame(0.1, 0.2, -0.5, Rotation::fromEulerAngles(0.2, -0.257, 0.4)), basicProperties);\n\n\treturn result;\n}\n\nstd::vector<Part> produceMotorizedPhysical() {\n\tstd::vector<Part> result;\n\tresult.reserve(10);\n\tPart& mainPart = result.emplace_back(polyhedronShape(ShapeLibrary::house.rotated(Rotationf::fromEulerAngles(1.0f, -0.3f, 0.5f))), GlobalCFrame(), PartProperties{0.7, 0.2, 0.6});\n\n\tmainPart.ensureHasPhysical();\n\n\tPart& part1_mainPart = result.emplace_back(polyhedronShape(ShapeLibrary::house), mainPart,\n\t\t\t\t\t\tnew SinusoidalPistonConstraint(0.0, 2.0, 1.3),\n\t\t\t\t\t\tCFrame(0.3, 0.7, -0.5, Rotation::fromEulerAngles(0.7, 0.3, 0.7)),\n\t\t\t\t\t\tCFrame(0.1, 0.2, -0.5, Rotation::fromEulerAngles(0.2, -0.257, 0.4)), basicProperties);\n\tPart& part2_mainPart = result.emplace_back(boxShape(1.0, 0.3, 2.0), mainPart,\n\t\t\t\t\t\tnew MotorConstraintTemplate<ConstantMotorTurner>(1.7),\n\t\t\t\t\t\tCFrame(-0.3, 0.7, 0.5, Rotation::fromEulerAngles(0.7, 0.3, 0.7)),\n\t\t\t\t\t\tCFrame(0.1, -0.2, -0.5, Rotation::fromEulerAngles(0.2, -0.257, 0.4)), basicProperties);\n\tPart& part1_part1_mainPart = result.emplace_back(cylinderShape(1.0, 0.3), part1_mainPart,\n\t\t\t\t\t\t\t  new MotorConstraintTemplate<ConstantMotorTurner>(1.3),\n\t\t\t\t\t\t\t  CFrame(-0.3, 0.7, 0.5, Rotation::fromEulerAngles(0.7, 0.3, 0.7)),\n\t\t\t\t\t\t\t  CFrame(0.1, -0.2, -0.5, Rotation::fromEulerAngles(0.2, -0.257, 0.4)), basicProperties);\n\tPart& part1_part1_part1_mainPart = result.emplace_back(polyhedronShape(ShapeLibrary::trianglePyramid), part1_part1_mainPart,\n\t\t\t\t\t\t\t\t\tnew SinusoidalPistonConstraint(0.0, 2.0, 1.3),\n\t\t\t\t\t\t\t\t\tCFrame(0.3, 0.7, -0.5, Rotation::fromEulerAngles(0.7, 0.3, 0.7)),\n\t\t\t\t\t\t\t\t\tCFrame(0.1, 0.2, -0.5, Rotation::fromEulerAngles(0.2, -0.257, 0.4)), basicProperties);\n\n\treturn result;\n}\n\nstruct FullGlobalDiagnostic {\n\tMotion motionOfCOM;\n\tVec3 getVelocity;\n\tdouble kineticEnergy;\n\tdouble inertiaInDirection;\n\tVec3 getTotalAngularMomentum;\n\tPosition positions[TICKS];\n};\n\ntemplate<typename Tol>\nbool tolerantEquals(const FullGlobalDiagnostic& first, const FullGlobalDiagnostic& second, Tol tolerance) {\n\tif(tolerantEquals(first.motionOfCOM, second.motionOfCOM, tolerance) &&\n\t   tolerantEquals(first.getVelocity, second.getVelocity, tolerance) &&\n\t   tolerantEquals(first.kineticEnergy, second.kineticEnergy, tolerance) &&\n\t   tolerantEquals(first.inertiaInDirection, second.inertiaInDirection, tolerance) &&\n\t   tolerantEquals(first.getTotalAngularMomentum, second.getTotalAngularMomentum, tolerance)) {\n\n\t\tfor(std::size_t i = 0; i < TICKS; i++) {\n\t\t\tif(!tolerantEquals(first.positions[i], second.positions[i], tolerance)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t} else {\n\t\treturn false;\n\t}\n}\n\nstd::ostream& operator<<(std::ostream& ostream, const FullGlobalDiagnostic& d) {\n\tostream << \"FullGlobalDiagnostic{motionOfCOM: \" << d.motionOfCOM << \"\\n\";\n\tostream << \"getVelocity: \" << d.getVelocity << \"\\n\";\n\tostream << \"kineticEnergy: \" << d.kineticEnergy << \"\\n\";\n\tostream << \"inertiaInDirection: \" << d.inertiaInDirection << \"\\n\";\n\tostream << \"getTotalAngularMomentum: \" << d.getTotalAngularMomentum << \"\\n\";\n\tostream << \"lastPosition: \" << d.positions[TICKS - 1] << \"}\";\n\treturn ostream;\n}\n\nstatic Vec3 inertiaOfRelativePos = Vec3(2.5, 1.2, -2.0);\nstatic Vec3 inertiaOfRelativeDir = normalize(Vec3(3.5, -2.0, 1.34));\n\nstatic FullGlobalDiagnostic doDiagnostic(MotorizedPhysical* p) {\n\tFullGlobalDiagnostic result;\n\n\tresult.motionOfCOM = p->getMotionOfCenterOfMass();\n\tresult.getVelocity = p->getVelocityOfCenterOfMass();\n\tresult.kineticEnergy = p->getKineticEnergy();\n\tresult.inertiaInDirection = p->getInertiaOfPointInDirectionRelative(inertiaOfRelativePos, inertiaOfRelativeDir);\n\tresult.getTotalAngularMomentum = p->getTotalAngularMomentum();\n\n\tfor(std::size_t i = 0; i < TICKS; i++) {\n\t\tp->update(DELTA_T);\n\t\tresult.positions[i] = p->getCenterOfMass();\n\t}\n\n\treturn result;\n}\n\nstatic const Motion motionOfCOM = Motion(Vec3(1.3, 0.7, -2.1), Vec3(2.1, 0.7, 3.7));\n\nstatic FullGlobalDiagnostic runDiagnosticForCFrame(MotorizedPhysical* p, const GlobalCFrame& cframeOfStart) {\n\tp->setCFrame(cframeOfStart);\n\tp->motionOfCenterOfMass = motionOfCOM;\n\n\tfor(ConnectedPhysical& c : p->childPhysicals) {\n\t\tSinusoidalPistonConstraint* constraint = dynamic_cast<SinusoidalPistonConstraint*>(c.connectionToParent.constraintWithParent.get());\n\t\tconstraint->currentStepInPeriod = 0;\n\t}\n\n\tp->fullRefreshOfConnectedPhysicals();\n\tp->refreshPhysicalProperties();\n\n\treturn doDiagnostic(p);\n}\n\nTEST_CASE(basicFullRotationSymmetryInvariance) {\n\tconst int ticksToSim = 10;\n\n\tPosition origin(-143.3, 700.3, 1000.0);\n\tPart centerPart(sphereShape(1.0), GlobalCFrame(origin), basicProperties);\n\tShape box = boxShape(1.0, 1.0, 1.0);\n\n\tPart xPart(box, centerPart, CFrame(1.0, 0.0, 0.0), basicProperties);\n\tPart yPart(box, centerPart, CFrame(0.0, 1.0, 0.0), basicProperties);\n\tPart zPart(box, centerPart, CFrame(0.0, 0.0, 1.0), basicProperties);\n\tPart nxPart(box, centerPart, CFrame(-1.0, 0.0, 0.0), basicProperties);\n\tPart nyPart(box, centerPart, CFrame(0.0, -1.0, 0.0), basicProperties);\n\tPart nzPart(box, centerPart, CFrame(0.0, 0.0, -1.0), basicProperties);\n\n\tMotorizedPhysical* motorPhys = centerPart.getMainPhysical();\n\n\tFullGlobalDiagnostic reference = runDiagnosticForCFrame(motorPhys, GlobalCFrame(origin));\n\tlogStream << reference;\n\n\tRotation rotations[9]{\n\t\tRotation::Predefined::X_90,\n\t\tRotation::Predefined::X_180,\n\t\tRotation::Predefined::X_270,\n\t\tRotation::Predefined::Y_90,\n\t\tRotation::Predefined::Y_180,\n\t\tRotation::Predefined::Y_270,\n\t\tRotation::Predefined::Z_90,\n\t\tRotation::Predefined::Z_180,\n\t\tRotation::Predefined::Z_270,\n\t};\n\tfor(int i = 0; i < 9; i++) {\n\t\tASSERT(reference == runDiagnosticForCFrame(motorPhys, GlobalCFrame(origin, rotations[i])));\n\t}\n}\n\nTEST_CASE(angularMomentumOverLocalToGlobal) {\n\tconst int ticksToSim = 10;\n\n\tPosition origin(-143.3, 700.3, 1000.0);\n\t\n\tstd::vector<Part> phys = produceMotorizedPhysical();\n\tMotorizedPhysical* motorPhys = phys[0].getMainPhysical();\n\n\n\tMotion motionOfCOM = Motion(Vec3(1.3, 0.7, -2.1), Vec3(2.1, 0.7, 3.7));\n\tRotation rotation = Rotation::fromEulerAngles(1.0, 0.2, -0.9);\n\n\tmotorPhys->setCFrame(GlobalCFrame(origin));\n\tmotorPhys->motionOfCenterOfMass = motionOfCOM;\n\n\tVec3 firstAngularMomentumFromParts = getTotalAngularMomentumOfPhysical(motorPhys);\n\tVec3 firstAngularMomentum = motorPhys->getTotalAngularMomentum();\n\n\tmotorPhys->setCFrame(GlobalCFrame(origin, rotation));\n\tmotorPhys->motionOfCenterOfMass = localToGlobal(rotation, motionOfCOM);\n\n\tVec3 secondAngularMomentumFromParts = getTotalAngularMomentumOfPhysical(motorPhys);\n\tVec3 secondAngularMomentum = motorPhys->getTotalAngularMomentum();\n\n\tASSERT(rotation.localToGlobal(firstAngularMomentum) == secondAngularMomentum);\n\tASSERT(rotation.localToGlobal(firstAngularMomentumFromParts) == secondAngularMomentumFromParts);\n}\n\nTEST_CASE(hardConstrainedFullRotationFollowsCorrectly) {\n\tconst int ticksToSim = 10;\n\n\tPosition origin(-143.3, 700.3, 1000.0);\n\tPart centerPart(sphereShape(1.0), GlobalCFrame(origin), basicProperties);\n\tShape box = boxShape(1.0, 1.0, 1.0);\n\n\tPart zPart(box, centerPart, new SinusoidalPistonConstraint(1.0, 3.0, 1.0), CFrame(0.0, 0.0, 0.0, Rotation::Predefined::IDENTITY), CFrame(0.0, 0.0, 0.0), basicProperties);\n\tPart yPart(box, centerPart, new SinusoidalPistonConstraint(1.0, 3.0, 1.0), CFrame(0.0, 0.0, 0.0, Rotation::Predefined::X_90), CFrame(0.0, 0.0, 0.0), basicProperties);\n\tPart xPart(box, centerPart, new SinusoidalPistonConstraint(1.0, 3.0, 1.0), CFrame(0.0, 0.0, 0.0, Rotation::Predefined::Y_90), CFrame(0.0, 0.0, 0.0), basicProperties);\n\tPart nzPart(box, centerPart, new SinusoidalPistonConstraint(1.0, 3.0, 1.0), CFrame(0.0, 0.0, 0.0, Rotation::Predefined::X_180), CFrame(0.0, 0.0, 0.0), basicProperties);\n\tPart nyPart(box, centerPart, new SinusoidalPistonConstraint(1.0, 3.0, 1.0), CFrame(0.0, 0.0, 0.0, Rotation::Predefined::X_270), CFrame(0.0, 0.0, 0.0), basicProperties);\n\tPart nxPart(box, centerPart, new SinusoidalPistonConstraint(1.0, 3.0, 1.0), CFrame(0.0, 0.0, 0.0, Rotation::Predefined::Y_270), CFrame(0.0, 0.0, 0.0), basicProperties);\n\n\tMotorizedPhysical* p = centerPart.getMainPhysical();\n\n\tFullGlobalDiagnostic reference = runDiagnosticForCFrame(p, GlobalCFrame(origin));\n\tlogStream << reference;\n\n\tRotation rotations[9]{\n\t\tRotation::Predefined::X_90,\n\t\tRotation::Predefined::X_180,\n\t\tRotation::Predefined::X_270,\n\t\tRotation::Predefined::Y_90,\n\t\tRotation::Predefined::Y_180,\n\t\tRotation::Predefined::Y_270,\n\t\tRotation::Predefined::Z_90,\n\t\tRotation::Predefined::Z_180,\n\t\tRotation::Predefined::Z_270,\n\t};\n\tfor(int i = 0; i < 9; i++) {\n\t\tASSERT(reference == runDiagnosticForCFrame(p, GlobalCFrame(origin, rotations[i])));\n\t}\n}\n\nTEST_CASE(basicAngularMomentumOfSinglePart) {\n\tPolyhedron testPoly = ShapeLibrary::createPointyPrism(4, 1.0f, 1.0f, 0.5f, 0.5f);\n\tPart mainPart(polyhedronShape(testPoly), GlobalCFrame(Position(1.3, 2.7, -2.6), Rotation::fromEulerAngles(0.6, -0.7, -0.3)), basicProperties);\n\n\tmainPart.ensureHasPhysical();\n\n\tMotorizedPhysical* motorPhys = mainPart.getMainPhysical();\n\n\tmotorPhys->motionOfCenterOfMass = Motion(Vec3(2.0, 3.0, 1.0), Vec3(-1.7, 3.3, 12.0));\n\n\tALLOCA_COMMotionTree(t, mainPart.getMainPhysical(), size);\n\n\tASSERT(motorPhys->getTotalAngularMomentum() == getTotalAngularMomentumOfPhysical(motorPhys));\n}\n\nTEST_CASE(motorizedPhysicalAngularMomentum) {\n\tstd::vector<Part> phys = produceMotorizedPhysical();\n\tMotorizedPhysical* motorPhys = phys[0].getMainPhysical();\n\n\tALLOCA_COMMotionTree(t, motorPhys, size);\n\n\tASSERT(t.getInternalAngularMomentum() == getTotalAngularMomentumOfPhysical(motorPhys));\n\tASSERT(motorPhys->getTotalAngularMomentum() == getTotalAngularMomentumOfPhysical(motorPhys));\n}\n\nTEST_CASE(physicalTotalAngularMomentum) {\n\tstd::vector<Part> phys = producePhysical();\n\tMotorizedPhysical* motorPhys = phys[0].getMainPhysical();\n\n\tmotorPhys->motionOfCenterOfMass = Motion(Vec3(2.0, 3.0, 1.0), Vec3(-1.7, 3.3, 12.0));\n\n\tALLOCA_COMMotionTree(t, motorPhys, size);\n\n\tASSERT(motorPhys->getTotalAngularMomentum() == getTotalAngularMomentumOfPhysical(motorPhys));\n}\n\nTEST_CASE(basicMotorizedPhysicalTotalAngularMomentum) {\n\tstd::vector<Part> result;\n\tresult.reserve(10);\n\tPart& mainPart = result.emplace_back(boxShape(1.0, 1.0, 1.0), GlobalCFrame(), basicProperties);\n\n\tmainPart.ensureHasPhysical();\n\n\tPart& part1_mainPart = result.emplace_back(polyhedronShape(ShapeLibrary::house), mainPart,\n\t\t\t\t\t\t\t\t\t\t\t   new SinusoidalPistonConstraint(0.0, 2.0, 1.0),\n\t\t\t\t\t\t\t\t\t\t\t   CFrame(0.0, 0.0, 0.0),\n\t\t\t\t\t\t\t\t\t\t\t   CFrame(0.0, 0.0, 0.0), basicProperties);\n\t/*Part& part2_mainPart = result.emplace_back(polyhedronShape(ShapeLibrary::house), mainPart,\n\t\t\t\t\t\t\t\t\t\t\t   new MotorConstraintTemplate<ConstantMotorTurner>(1.7),\n\t\t\t\t\t\t\t\t\t\t\t   CFrame(-0.3, 0.7, 0.5, Rotation::fromEulerAngles(0.7, 0.3, 0.7)),\n\t\t\t\t\t\t\t\t\t\t\t   CFrame(0.7, -2.0, -0.5, Rotation::fromEulerAngles(0.2, -0.257, 0.4)), basicProperties);*/\n\t/*Part& part3_mainPart = result.emplace_back(boxShape(1.0, 1.0, 1.0), mainPart,\n\t\t\t\t\t\t\t\t\t\t\t   new MotorConstraintTemplate<ConstantMotorTurner>(1.7),\n\t\t\t\t\t\t\t\t\t\t\t   CFrame(-0.3, 0.7, 0.5, Rotation::fromEulerAngles(0.7, 0.3, 0.7)),\n\t\t\t\t\t\t\t\t\t\t\t   CFrame(0.7, -2.0, -0.5, Rotation::fromEulerAngles(0.2, -0.257, 0.4)), basicProperties);*/\n\n\tMotorizedPhysical* motorPhys = result[0].getMainPhysical();\n\n\tmotorPhys->motionOfCenterOfMass = Motion(Vec3(0.0, 0.0, 0.0), Vec3(-1.7, 3.3, 12.0));\n\n\tALLOCA_COMMotionTree(t, motorPhys, size);\n\n\tASSERT(motorPhys->getTotalAngularMomentum() == getTotalAngularMomentumOfPhysical(motorPhys));\n}\n\nTEST_CASE(totalInertiaOfPhysical) {\n\tstd::vector<Part> phys = producePhysical();\n\tMotorizedPhysical* motorPhys = phys[0].getMainPhysical();\n\n\tALLOCA_COMMotionTree(t, motorPhys, size);\n\n\tASSERT(t.getInertia() == getTotalInertiaOfPhysical(motorPhys));\n}\n\nTEST_CASE(totalInertiaOfBasicMotorizedPhysical) {\n\tstd::vector<Part> result;\n\tresult.reserve(10);\n\tPart& mainPart = result.emplace_back(polyhedronShape(ShapeLibrary::house), GlobalCFrame(), basicProperties);\n\n\tmainPart.ensureHasPhysical();\n\n\t/*Part& part1_mainPart = result.emplace_back(polyhedronShape(ShapeLibrary::house), mainPart,\n\t\t\t\t\t\t\t\t\t\t\t   new SinusoidalPistonConstraint(0.0, 2.0, 1.0),\n\t\t\t\t\t\t\t\t\t\t\t   CFrame(0.0, 0.0, 0.0),\n\t\t\t\t\t\t\t\t\t\t\t   CFrame(0.0, 0.0, 0.0), basicProperties);*/\n\tPart& part2_mainPart = result.emplace_back(polyhedronShape(ShapeLibrary::house), mainPart,\n\t\t\t\t\t\t\t\t\t\t\t   new MotorConstraintTemplate<ConstantMotorTurner>(1.7),\n\t\t\t\t\t\t\t\t\t\t\t   CFrame(-0.3, 0.7, 0.5, Rotation::fromEulerAngles(0.7, 0.3, 0.7)),\n\t\t\t\t\t\t\t\t\t\t\t   CFrame(0.7, -2.0, -0.5, Rotation::fromEulerAngles(0.2, -0.257, 0.4)), basicProperties);\n\t/*Part& part3_mainPart = result.emplace_back(boxShape(1.0, 1.0, 1.0), mainPart,\n\t\t\t\t\t\t\t\t\t\t\t\tnew MotorConstraintTemplate<ConstantMotorTurner>(1.7),\n\t\t\t\t\t\t\t\t\t\t\t\tCFrame(-0.3, 0.7, 0.5, Rotation::fromEulerAngles(0.7, 0.3, 0.7)),\n\t\t\t\t\t\t\t\t\t\t\t\tCFrame(0.7, -2.0, -0.5, Rotation::fromEulerAngles(0.2, -0.257, 0.4)), basicProperties);*/\n\n\tMotorizedPhysical* motorPhys = result[0].getMainPhysical();\n\n\tALLOCA_COMMotionTree(t, motorPhys, size);\n\n\tASSERT(t.getInertia() == getTotalInertiaOfPhysical(motorPhys));\n}\n\nTEST_CASE(totalCenterOfMassOfPhysical) {\n\tstd::vector<Part> phys = producePhysical();\n\tMotorizedPhysical* motorPhys = phys[0].getMainPhysical();\n\n\tASSERT(motorPhys->getCenterOfMass() == getTotalCenterOfMassOfPhysical(motorPhys));\n}\n\nTEST_CASE(totalCenterOfMassOfMotorizedPhysical) {\n\tstd::vector<Part> phys = produceMotorizedPhysical();\n\tMotorizedPhysical* motorPhys = phys[0].getMainPhysical();\n\n\tASSERT(motorPhys->getCenterOfMass() == getTotalCenterOfMassOfPhysical(motorPhys));\n}\n\nTEST_CASE(totalVelocityOfCenterOfMassOfPhysical) {\n\tstd::vector<Part> phys = producePhysical();\n\tMotorizedPhysical* motorPhys = phys[0].getMainPhysical();\n\n\tmotorPhys->motionOfCenterOfMass = motionOfCOM;\n\n\tASSERT(motorPhys->getMotionOfCenterOfMass().getVelocity() == getTotalMotionOfCenterOfMassOfPhysical(motorPhys));\n}\n\nTEST_CASE(totalVelocityOfCenterOfMassOfMotorizedPhysical) {\n\tstd::vector<Part> phys = produceMotorizedPhysical();\n\tMotorizedPhysical* motorPhys = phys[0].getMainPhysical();\n\n\tmotorPhys->motionOfCenterOfMass = motionOfCOM;\n\n\tASSERT(motorPhys->getMotionOfCenterOfMass().getVelocity() == getTotalMotionOfCenterOfMassOfPhysical(motorPhys));\n}\n\nTEST_CASE(totalInertiaOfMotorizedPhysical) {\n\tstd::vector<Part> phys = produceMotorizedPhysical();\n\tMotorizedPhysical* motorPhys = phys[0].getMainPhysical();\n\n\tALLOCA_COMMotionTree(t, motorPhys, size);\n\n\tASSERT(t.getInertia() == getTotalInertiaOfPhysical(motorPhys));\n}\n\nTEST_CASE(motorizedPhysicalTotalAngularMomentum) {\n\tstd::vector<Part> phys = produceMotorizedPhysical();\n\tMotorizedPhysical* motorPhys = phys[0].getMainPhysical();\n\n\tmotorPhys->motionOfCenterOfMass = Motion(Vec3(2.0, 3.0, 1.0), Vec3(-1.7, 3.3, 12.0));\n\n\tALLOCA_COMMotionTree(t, motorPhys, size);\n\n\tASSERT(motorPhys->getTotalAngularMomentum() == getTotalAngularMomentumOfPhysical(motorPhys));\n}\n\nTEST_CASE(conservationOfAngularMomentum) {\n\tstd::vector<Part> phys = produceMotorizedPhysical();\n\n\tMotorizedPhysical* motorPhys = phys[0].getMainPhysical();\n\n\tmotorPhys->motionOfCenterOfMass = Motion(Vec3(2.0, 3.0, 1.0), Vec3(-1.7, 3.3, 12.0));\n\n\tVec3 initialAngularMomentum = motorPhys->getTotalAngularMomentum();\n\n\tfor(int i = 0; i < TICKS; i++) {\n\t\tmotorPhys->update(DELTA_T);\n\n\t\tASSERT(initialAngularMomentum == motorPhys->getTotalAngularMomentum());\n\t}\n}\n\nTEST_CASE(conservationOfCenterOfMass) {\n\tstd::vector<Part> phys = produceMotorizedPhysical();\n\n\tMotorizedPhysical* motorPhys = phys[0].getMainPhysical();\n\n\tmotorPhys->motionOfCenterOfMass = Motion(Vec3(0.0, 0.0, 0.0), Vec3(-1.7, 3.3, 12.0));\n\n\tPosition initialCenterOfMass = motorPhys->getCenterOfMass();\n\n\tfor(int i = 0; i < TICKS; i++) {\n\t\tmotorPhys->update(DELTA_T);\n\n\t\tASSERT(initialCenterOfMass == motorPhys->getCenterOfMass());\n\t}\n}\n\nTEST_CASE(angularMomentumVelocityInvariance) {\n\tstd::vector<Part> phys = produceMotorizedPhysical();\n\n\tMotorizedPhysical* motorPhys = phys[0].getMainPhysical();\n\n\tmotorPhys->motionOfCenterOfMass = Motion(Vec3(0.0, 0.0, 0.0), Vec3(-1.7, 3.3, 12.0));\n\n\tVec3 stillAngularMomentum = motorPhys->getTotalAngularMomentum();\n\tVec3 stillAngularMomentumPartsBased = getTotalAngularMomentumOfPhysical(motorPhys);\n\n\tmotorPhys->motionOfCenterOfMass = Motion(Vec3(50.3, 12.3, -74.2), Vec3(-1.7, 3.3, 12.0));\n\n\tVec3 movingAngularMomentum = motorPhys->getTotalAngularMomentum();\n\tVec3 movingAngularMomentumPartsBased = getTotalAngularMomentumOfPhysical(motorPhys);\n\n\tASSERT(stillAngularMomentum == movingAngularMomentum);\n\tASSERT(stillAngularMomentumPartsBased == movingAngularMomentumPartsBased);\n}\n\nTEST_CASE(setVelocity) {\n\tfor(int iter = 0; iter < 100; iter++) {\n\t\tstd::vector<Part> phys = produceMotorizedPhysical();\n\n\t\tMotorizedPhysical* motorPhys = phys[0].getMainPhysical();\n\t\tmotorPhys->motionOfCenterOfMass = generateMotion();\n\n\t\tPart& p = oneOf(phys);\n\n\t\t{\n\t\t\tVec3 chosenVelocity = generateVec3();\n\t\t\tVec3 prevAngularVelocity = p.getAngularVelocity();\n\t\t\tp.setVelocity(chosenVelocity);\n\t\t\tASSERT(p.getVelocity() == chosenVelocity);\n\t\t\tASSERT(p.getAngularVelocity() == prevAngularVelocity); // angular velocity is maintained\n\t\t}\n\t\t{\n\t\t\tVec3 chosenAngularVelocity = generateVec3();\n\t\t\tp.setAngularVelocity(chosenAngularVelocity);\n\t\t\tASSERT(p.getAngularVelocity() == chosenAngularVelocity);\n\t\t}\n\t\t{\n\t\t\tVec3 chosenMotionVel = generateVec3();\n\t\t\tVec3 chosenMotionAngularVel = generateVec3();\n\t\t\tp.setMotion(chosenMotionVel, chosenMotionAngularVel);\n\n\t\t\tASSERT(p.getVelocity() == chosenMotionVel);\n\t\t\tASSERT(p.getAngularVelocity() == chosenMotionAngularVel);\n\t\t\tASSERT(p.getMotion().getVelocity() == chosenMotionVel);\n\t\t\tASSERT(p.getMotion().getAngularVelocity() == chosenMotionAngularVel);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "tests/randomValues.h",
    "content": "#pragma once\n\n#include <stddef.h>\n\n#include <random>\n#include <array>\n\n#include <Physics3D/math/linalg/vec.h>\n#include <Physics3D/math/linalg/mat.h>\n#include <Physics3D/math/cframe.h>\n#include <Physics3D/math/constants.h>\n#include <Physics3D/math/linalg/trigonometry.h>\n\n#include <Physics3D/motion.h>\n#include <Physics3D/relativeMotion.h>\n\nnamespace P3D {\ninline double createRandomDouble() {\n\treturn 2.0 * rand() / RAND_MAX - 1.0;\n}\n\ninline double createRandomNonzeroDouble() {\n\ttryAgain:\n\tdouble result = createRandomDouble();\n\n\tif(std::abs(result) < 0.3) {\n\t\tgoto tryAgain;\n\t}\n\n\treturn result;\n}\n\n// creates a random vector with elements between -1.0 and 1.0\ntemplate<typename T, std::size_t Size>\nVector<T, Size> createRandomVecTemplate() {\n\tVector<T, Size> result;\n\tfor(std::size_t i = 0; i < Size; i++) {\n\t\tresult[i] = createRandomDouble();\n\t}\n\treturn result;\n}\n// creates a random vector with elements between -1.0 and 1.0\ntemplate<typename T, std::size_t Height, std::size_t Width>\nMatrix<T, Height, Width> createRandomMatrixTemplate() {\n\tMatrix<T, Height, Width> result;\n\tfor(std::size_t y = 0; y < Height; y++) {\n\t\tfor(std::size_t x = 0; x < Width; x++) {\n\t\t\tresult(x, y) = createRandomDouble();\n\t\t}\n\t}\n\treturn result;\n}\n// creates a random average sized vector with elements between -1.0 and 1.0\ntemplate<typename T, std::size_t Size>\nVector<T, Size> createRandomNonzeroVecTemplate() {\n\tVector<T, Size> result;\n\ttryAgain:\n\tfor(std::size_t i = 0; i < Size; i++) {\n\t\tresult[i] = createRandomDouble();\n\t}\n\tif(lengthSquared(result) < 0.3) {\n\t\tgoto tryAgain;\n\t}\n\treturn result;\n}\n// creates a random rotation\ntemplate<typename T>\nRotationTemplate<T> createRandomRotationTemplate() {\n\tVector<T, 3> angles = createRandomNonzeroVecTemplate<T, 3>() * (PI / 2);\n\treturn Rotation::fromEulerAngles(angles.x, angles.y, angles.z);\n}\n// creates a random rotation\ntemplate<typename T>\nCFrameTemplate<T> createRandomCFrameTemplate() {\n\treturn CFrameTemplate<T>(createRandomNonzeroVecTemplate<double, 3>(), createRandomRotationTemplate<double>());\n}\n\ninline Vec3 createRandomVec() {\n\treturn createRandomVecTemplate<double, 3>();\n}\ninline Vec3 createRandomNonzeroVec3() {\n\treturn createRandomNonzeroVecTemplate<double, 3>();\n}\ninline Rotation createRandomRotation() {\n\treturn createRandomRotationTemplate<double>();\n}\ninline CFrame createRandomCFrame() {\n\treturn createRandomCFrameTemplate<double>();\n}\n\ninline TranslationalMotion createRandomTranslationalMotion() {\n\treturn TranslationalMotion(createRandomNonzeroVec3(), createRandomNonzeroVec3());\n}\ninline RotationalMotion createRandomRotationalMotion() {\n\treturn RotationalMotion(createRandomNonzeroVec3(), createRandomNonzeroVec3());\n}\n\ninline Motion createRandomMotion() {\n\treturn Motion(createRandomTranslationalMotion(), createRandomRotationalMotion());\n}\ninline RelativeMotion createRandomRelativeMotion() {\n\treturn RelativeMotion(createRandomMotion(), createRandomCFrame());\n}\n\ntemplate<typename T, std::size_t Size, T(*createFunc)()>\ninline Derivatives<T, Size> createRandomDerivatives() {\n\tDerivatives<T, Size> result;\n\n\tfor(T& item : result) {\n\t\titem = createFunc();\n\t}\n\n\treturn result;\n}\ntemplate<typename T, std::size_t Size, T(*createFunc)()>\ninline TaylorExpansion<T, Size> createRandomTaylorExpansion() {\n\treturn TaylorExpansion<T, Size>{createRandomDerivatives<T, Size, createFunc>()};\n}\ntemplate<typename T, std::size_t Size, T(*createFunc)()>\ninline FullTaylorExpansion<T, Size> createRandomFullTaylorExpansion() {\n\treturn FullTaylorExpansion<T, Size>{createRandomDerivatives<T, Size, createFunc>()};\n}\ntemplate<typename T, std::size_t Size, T(*createFunc)()>\ninline std::array<T, Size> createRandomArray() {\n\tstd::array<T, Size> result;\n\n\tfor(T& item : result) {\n\t\titem = createFunc();\n\t}\n\n\treturn result;\n}\n};\n"
  },
  {
    "path": "tests/rotationTests.cpp",
    "content": "#include \"testsMain.h\"\n\n#include \"compare.h\"\n#include \"testValues.h\"\n\n#include <Physics3D/misc/toString.h>\n\n#include <Physics3D/math/linalg/vec.h>\n#include <Physics3D/math/linalg/quat.h>\n#include <Physics3D/math/linalg/mat.h>\n#include <Physics3D/math/linalg/trigonometry.h>\n#include <Physics3D/math/rotation.h>\n#include <Physics3D/math/linalg/commonMatrices.h>\n\n#include <cmath>\n\nusing namespace P3D;\n#define ASSERT(condition) ASSERT_TOLERANT(condition, 0.00000001)\n\n#define FOR_XYZ(start, end, delta) for(auto x = start; x < end; x += delta) for(auto y = start; y < end; y += delta) for(auto z = start; z < end; z += delta) \n\nTEST_CASE(testFromRotationVecInvertsFromRotationMatrix) {\n\tFOR_XYZ(-1.55, 1.55, 0.13) {\n\t\tVec3 v(x, y, z);\n\t\tRotation rot = Rotation::fromRotationVector(v);\n\n\t\tVec3 resultingVec = rot.asRotationVector();\n\n\t\t// logStream << \"v = \" << v << \"\\n  rot = \" << rot << \"  resultingVec = \" << resultingVec;\n\n\t\tASSERT(v == resultingVec);\n\n\t\tRotation m = Rotation::fromEulerAngles(x, y, z);\n\n\t\tVec3 rotVec = m.asRotationVector();\n\n\t\tRotation resultingRot = Rotation::fromRotationVector(rotVec);\n\n\t\t// logStream << \"m = \" << m << \"\\n  rotVec = \" << rotVec << \"  resultingMat = \" << resultingMat;\n\n\t\tASSERT(m == resultingRot);\n\t}\n}\n\nTEST_CASE(rotationGlobalToLocalInvertsLocalToGlobal) {\n\tFOR_XYZ(-1.55, 1.55, 0.13) {\n\t\tRotation rotToTest = Rotation::fromEulerAngles(x, y, z);\n\n\t\tVec3 testVec(0.7, -0.5, 0.3);\n\t\tASSERT(rotToTest.localToGlobal(rotToTest.globalToLocal(testVec)) == testVec);\n\t\tASSERT(rotToTest.globalToLocal(rotToTest.localToGlobal(testVec)) == testVec);\n\n\t\tRotation testRot = Rotation::fromEulerAngles(0.5, 0.4, 0.5);\n\t\tASSERT(rotToTest.localToGlobal(rotToTest.globalToLocal(testRot)) == testRot);\n\t\tASSERT(rotToTest.globalToLocal(rotToTest.localToGlobal(testRot)) == testRot);\n\n\t\tSymmetricMat3 testMat{\n\t\t\t0.7,\n\t\t\t0.3, 0.8,\n\t\t\t-0.2, 0.4, -1.0,\n\t\t};\n\t\tASSERT(rotToTest.localToGlobal(rotToTest.globalToLocal(testMat)) == testMat);\n\t\tASSERT(rotToTest.globalToLocal(rotToTest.localToGlobal(testMat)) == testMat);\n\t}\n}\n\nTEST_CASE(rotationGlobalToLocalMatrixIdentity) {\n\tFOR_XYZ(-1.55, 1.55, 0.13) {\n\t\tRotation rotToTest = Rotation::fromEulerAngles(x, y, z);\n\n\t\tVec3 testVec(0.7, -0.5, 0.3);\n\t\tSymmetricMat3 testMat{\n\t\t\t0.7,\n\t\t\t0.3, 0.8,\n\t\t\t-0.2, 0.4, -1.0,\n\t\t};\n\n\t\tASSERT(rotToTest.localToGlobal(testMat * testVec) == rotToTest.localToGlobal(testMat) * rotToTest.localToGlobal(testVec));\n\t\tASSERT(rotToTest.globalToLocal(testMat * testVec) == rotToTest.globalToLocal(testMat) * rotToTest.globalToLocal(testVec));\n\t}\n}\n\nTEST_CASE(rotationAssociative) {\n\tFOR_XYZ(-1.55, 1.55, 0.13) {\n\t\tRotation rotToTest1 = Rotation::fromEulerAngles(x, y, z);\n\t\tRotation rotToTest2 = Rotation::fromEulerAngles(-0.17, 0.26, -0.247);\n\n\t\tVec3 testVec(0.7, -0.5, 0.3);\n\t\tRotation testRot = Rotation::fromEulerAngles(0.5, 0.4, 0.5);\n\t\tSymmetricMat3 testMat{\n\t\t\t0.7,\n\t\t\t0.3, 0.8,\n\t\t\t-0.2, 0.4, -1.0,\n\t\t};\n\n\t\tASSERT(rotToTest1.localToGlobal(rotToTest2.localToGlobal(testVec)) == rotToTest1.localToGlobal(rotToTest2).localToGlobal(testVec));\n\n\t\tASSERT(rotToTest1.localToGlobal(rotToTest2.localToGlobal(testRot)) == rotToTest1.localToGlobal(rotToTest2).localToGlobal(testRot));\n\n\t\tASSERT(rotToTest1.localToGlobal(rotToTest2.localToGlobal(testMat)) == rotToTest1.localToGlobal(rotToTest2).localToGlobal(testMat));\n\t}\n}\n\nTEST_CASE(rotXrotYrotZ) {\n\tFOR_XYZ(-1.5, 1.5, 0.1) {\n\t\tdouble angle = x;\n\n\t\tVec2 a(y, z);\n\t\tMat2 rotMat{\n\t\t\tstd::cos(angle), -std::sin(angle),\n\t\t\tstd::sin(angle), std::cos(angle)\n\t\t};\n\t\tVec2 b = rotMat * a;\n\n\t\tdouble offset = 0.57;\n\n\t\tASSERT(Rotation::rotX(angle) * Vec3(offset, a.x, a.y) == Vec3(offset, b.x, b.y));\n\t\tASSERT(Rotation::rotY(angle) * Vec3(a.y, offset, a.x) == Vec3(b.y, offset, b.x));\n\t\tASSERT(Rotation::rotZ(angle) * Vec3(a.x, a.y, offset) == Vec3(b.x, b.y, offset));\n\t}\n}\n\nTEST_CASE(faceDirection) {\n\tFOR_XYZ(-1.5, 1.5, 0.1) {\n\t\tif(x == 0.0 && y == 0.0 && z == 0.0) continue;\n\t\tVec3 faceDirection = normalize(Vec3(x, y, z));\n\n\t\tASSERT(Rotation::faceX(faceDirection) * Vec3(1.0, 0.0, 0.0) == faceDirection);\n\t\tASSERT(Rotation::faceY(faceDirection) * Vec3(0.0, 1.0, 0.0) == faceDirection);\n\t\tASSERT(Rotation::faceZ(faceDirection) * Vec3(0.0, 0.0, 1.0) == faceDirection);\n\t}\n}\n\nTEST_CASE(rotationMatrix) {\n\tFOR_XYZ(-1.55, 1.55, 0.1) {\n\t\tMat3 mat = rotationMatrixfromEulerAngles(x, y, z);\n\t\tRotation rot = Rotation::fromEulerAngles(x, y, z);\n\t\tASSERT(rot == Rotation::fromRotationMatrix(mat));\n\t\tASSERT(mat == rot.asRotationMatrix());\n\t}\n}\n\nTEST_CASE(rotationQuaternionNegative) {\n\tFOR_XYZ(-1.55, 1.55, 0.1) {\n\t\tQuaternionRotationTemplate<double> quatRot = QuaternionRotationTemplate<double>::fromEulerAngles(x, y, z);\n\t\tQuat4 q1 = quatRot.asRotationQuaternion();\n\t\tQuat4 q2 = -q1;\n\n\t\tQuaternionRotationTemplate<double> rq1 = QuaternionRotationTemplate<double>::fromRotationQuaternion(q1);\n\t\tQuaternionRotationTemplate<double> rq2 = QuaternionRotationTemplate<double>::fromRotationQuaternion(q2);\n\n\t\tASSERT(rq1.asRotationVector() == rq2.asRotationVector());\n\t\tASSERT(rq1.asRotationMatrix() == rq2.asRotationMatrix());\n\t}\n}\n\nTEST_CASE(quaternionFromRotVecInverse) {\n\t// 1.55 to try to stay below a length of PI, since otherwise duplicate vectors will emerge\n\tFOR_XYZ(-1.55, 1.55, 0.1) {\n\t\tVec3 rotVec = Vec3(x, y, z);\n\t\tASSERT(rotVec == rotationVectorFromRotationQuaternion(rotationQuaternionFromRotationVec(rotVec)));\n\t}\n}\n\nTEST_CASE(rotationImplementationIdenticalFromEulerAngles) {\n\tFOR_XYZ(1.55, 1.55, 0.1) {\n\t\tQuaternionRotationTemplate<double> quatRot = QuaternionRotationTemplate<double>::fromEulerAngles(x, y, z);\n\t\tMatrixRotationTemplate<double> matRot = MatrixRotationTemplate<double>::fromEulerAngles(x, y, z);\n\n\t\tASSERT(quatRot.asRotationMatrix() == matRot.asRotationMatrix());\n\t\tASSERT(quatRot.asRotationQuaternion() == matRot.asRotationQuaternion());\n\t\tASSERT(quatRot.asRotationVector() == matRot.asRotationVector());\n\t}\n}\n\nTEST_CASE(rotationImplementationIdenticalLocalGlobal) {\n\tFOR_XYZ(1.5, 1.5, 0.5) {\n\t\tQuaternionRotationTemplate<double> quatRot = QuaternionRotationTemplate<double>::fromEulerAngles(x, y, z);\n\t\tMatrixRotationTemplate<double> matRot = MatrixRotationTemplate<double>::fromEulerAngles(x, y, z);\n\n\t\tFOR_XYZ(1.5, 1.5, 0.5) {\n\t\t\tVec3 vec = Vec3(x, y, z);\n\t\t\tASSERT(quatRot.localToGlobal(vec) == matRot.localToGlobal(vec));\n\t\t\tASSERT(quatRot.globalToLocal(vec) == matRot.globalToLocal(vec));\n\t\t}\n\t\tFOR_XYZ(1.5, 1.5, 0.5) {\n\t\t\tQuaternionRotationTemplate<double> quatRot2 = QuaternionRotationTemplate<double>::fromEulerAngles(x, y, z);\n\t\t\tMatrixRotationTemplate<double> matRot2 = MatrixRotationTemplate<double>::fromEulerAngles(x, y, z);\n\n\t\t\tASSERT(quatRot.localToGlobal(quatRot2).asRotationMatrix() == matRot.localToGlobal(matRot2).asRotationMatrix());\n\t\t\tASSERT(quatRot.globalToLocal(quatRot2).asRotationMatrix() == matRot.globalToLocal(matRot2).asRotationMatrix());\n\t\t\tASSERT((quatRot * quatRot2).asRotationMatrix() == (matRot * matRot2).asRotationMatrix());\n\t\t}\n\t\tSymmetricMat3 mat{\n\t\t\t1.3,\n\t\t\t0.4, -2.1,\n\t\t\t-1.2, 0.1, 0.7\n\t\t};\n\n\t\tASSERT(quatRot.localToGlobal(mat) == matRot.localToGlobal(mat));\n\t\tASSERT(quatRot.globalToLocal(mat) == matRot.globalToLocal(mat));\n\t}\n}\n\nTEST_CASE(rotationImplementationIdenticalInverse) {\n\tFOR_XYZ(1.5, 1.5, 0.5) {\n\t\tQuaternionRotationTemplate<double> quatRot = QuaternionRotationTemplate<double>::fromEulerAngles(x, y, z);\n\t\tMatrixRotationTemplate<double> matRot = MatrixRotationTemplate<double>::fromEulerAngles(x, y, z);\n\n\t\tASSERT((~quatRot).asRotationMatrix() == (~matRot).asRotationMatrix());\n\t}\n}\n\nTEST_CASE(rotationImplementationIdenticalFaceMatrices) {\n\tFOR_XYZ(1.5, 1.5, 0.5) {\n\t\tVec3 faceDir = Vec3(x, y, z);\n\n\n\t\tASSERT(MatrixRotationTemplate<double>::faceX(faceDir).asRotationMatrix() == QuaternionRotationTemplate<double>::faceX(faceDir).asRotationMatrix());\n\t\tASSERT(MatrixRotationTemplate<double>::faceY(faceDir).asRotationMatrix() == QuaternionRotationTemplate<double>::faceY(faceDir).asRotationMatrix());\n\t\tASSERT(MatrixRotationTemplate<double>::faceZ(faceDir).asRotationMatrix() == QuaternionRotationTemplate<double>::faceZ(faceDir).asRotationMatrix());\n\t}\n}\n\nTEST_CASE(rotationImplementationIdenticalGetXYZ) {\n\tFOR_XYZ(1.5, 1.5, 0.5) {\n\t\tMatrixRotationTemplate<double> matRot = MatrixRotationTemplate<double>::fromEulerAngles(x, y, z);\n\t\tQuaternionRotationTemplate<double> quatRot = QuaternionRotationTemplate<double>::fromEulerAngles(x, y, z);\n\n\t\tASSERT(matRot.getX() == quatRot.getX());\n\t\tASSERT(matRot.getY() == quatRot.getY());\n\t\tASSERT(matRot.getZ() == quatRot.getZ());\n\n\t\tASSERT(matRot.getX() == matRot.localToGlobal(Vec3(1, 0, 0)));\n\t\tASSERT(matRot.getY() == matRot.localToGlobal(Vec3(0, 1, 0)));\n\t\tASSERT(matRot.getZ() == matRot.localToGlobal(Vec3(0, 0, 1)));\n\n\t\tASSERT(quatRot.getX() == quatRot.localToGlobal(Vec3(1, 0, 0)));\n\t\tASSERT(quatRot.getY() == quatRot.localToGlobal(Vec3(0, 1, 0)));\n\t\tASSERT(quatRot.getZ() == quatRot.localToGlobal(Vec3(0, 0, 1)));\n\t}\n}\n"
  },
  {
    "path": "tests/simulation.h",
    "content": "#pragma once\n\n\n#include <Physics3D/math/linalg/vec.h>\n#include <Physics3D/math/taylorExpansion.h>\n#include <Physics3D/math/rotation.h>\n#include <Physics3D/math/cframe.h>\n#include <Physics3D/motion.h>\n\n#include <array>\n\n\nnamespace P3D {\ntemplate<std::size_t Size>\nstd::array<Vec3, Size + 1> computeTranslationOverTime(Vec3 start, TaylorExpansion<Vec3, Size> derivatives, double deltaT) {\n\tstd::array<Vec3, Size + 1> result;\n\n\tfor(std::size_t i = 0; i < Size + 1; i++) {\n\t\tresult[i] = start + derivatives(deltaT * i);\n\t}\n\n\treturn result;\n}\n\ntemplate<std::size_t Size>\nstd::array<Rotation, Size + 1> computeRotationOverTime(Rotation start, TaylorExpansion<Vec3, Size> derivatives, double deltaT) {\n\tstd::array<Rotation, Size + 1> result;\n\n\tfor(std::size_t i = 0; i < Size + 1; i++) {\n\t\tresult[i] = Rotation::fromRotationVector(derivatives(deltaT * i)) * start;\n\t}\n\n\treturn result;\n}\n\ninline std::array<Vec3, 3> computeTranslationOverTime(Vec3 start, TranslationalMotion motion, double deltaT) {\n\treturn computeTranslationOverTime(start, motion.translation, deltaT);\n}\ninline std::array<Rotation, 3> computeRotationOverTime(Rotation start, RotationalMotion motion, double deltaT) {\n\treturn computeRotationOverTime(start, motion.rotation, deltaT);\n}\ninline std::array<CFrame, 3> computeCFrameOverTime(CFrame start, Motion motion, double deltaT) {\n\tstd::array<CFrame, 3> result;\n\n\tfor(std::size_t i = 0; i < 3; i++) {\n\t\tdouble t = deltaT * i;\n\t\tVec3 offset = start.getPosition() + motion.translation.getOffsetAfterDeltaT(t);\n\t\tRotation rot = Rotation::fromRotationVector(motion.rotation.getRotationAfterDeltaT(t)) * start.getRotation();\n\n\t\tresult[i] = CFrame(offset, rot);\n\t}\n\n\treturn result;\n}\ntemplate<typename T, std::size_t Size>\nstd::array<T, Size> computeOverTime(const TaylorExpansion<T, Size>& taylor, double deltaT) {\n\tstd::array<T, Size> result;\n\n\tfor(std::size_t i = 0; i < Size; i++) {\n\t\tresult[i] = taylor(deltaT * i);\n\t}\n\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Size>\nstd::array<T, Size> computeOverTime(const FullTaylorExpansion<T, Size>& taylor, double deltaT) {\n\tstd::array<T, Size> result;\n\n\tfor(std::size_t i = 0; i < Size; i++) {\n\t\tresult[i] = taylor(deltaT * i);\n\t}\n\n\treturn result;\n}\n\ntemplate<typename T, std::size_t Size>\ninline FullTaylorExpansion<T, Size> estimateDerivatives(const std::array<T, Size>& points, double deltaT) {\n\tstruct Recurse {\n\t\tstatic T estimateLastDerivative(const std::array<T, Size>& points, std::size_t index, std::size_t size, double invDT) {\n\t\t\tif(size == 0) {\n\t\t\t\treturn points[index];\n\t\t\t} else {\n\t\t\t\tT delta = estimateLastDerivative(points, index + 1, size - 1, invDT) - estimateLastDerivative(points, index, size - 1, invDT);\n\t\t\t\treturn delta * invDT;\n\t\t\t}\n\t\t}\n\t};\n\tFullTaylorExpansion<T, Size> result;\n\n\tdouble invDT = 1.0 / deltaT;\n\tfor(std::size_t i = 0; i < Size; i++) {\n\t\tresult.derivs[i] = Recurse::estimateLastDerivative(points, 0, i, invDT);\n\t}\n\treturn result;\n}\n\n//template<typename T>\n//inline FullTaylorExpansion<T, 3> estimateDerivatives(const std::array<T, 3>& points, double deltaT) {\n//\treturn FullTaylorExpansion<T, 3>{points[0], (points[1] - points[0]) / deltaT, (points[0] + points[2] - points[1] * 2.0) / (deltaT * deltaT)};\n//}\n};\n"
  },
  {
    "path": "tests/testFrameworkConsistencyTests.cpp",
    "content": "#include \"testsMain.h\"\n\n#include \"compare.h\"\n#include \"testValues.h\"\n#include \"simulation.h\"\n#include \"randomValues.h\"\n\n#include <array>\n\n#include <Physics3D/misc/toString.h>\n#include <Physics3D/math/taylorExpansion.h>\n\nusing namespace P3D;\n#define DELTA_T 0.005\n\nTEST_CASE(testEstimateDerivativesOfComputeOverTime) {\n\tFullTaylorExpansion<double, 5> startTaylor = createRandomFullTaylorExpansion<double, 5, createRandomDouble>();\n\tlogStream << \"startTaylor: \" << startTaylor << \"\\n\";\n\tstd::array<double, 5> points = computeOverTime(startTaylor, DELTA_T);\n\tFullTaylorExpansion<double, 5> endTaylor = estimateDerivatives(points, DELTA_T);\n\tASSERT_TOLERANT(startTaylor == endTaylor, 0.01);\n}\n"
  },
  {
    "path": "tests/testValues.cpp",
    "content": "#include \"testValues.h\"\n\n#include <Physics3D/math/rotation.h>\n\nnamespace P3D {\nconst Vec3 vectors[13]{\n\tVec3(0.0, 0.0, 0.0),\n\tVec3(1.0, 0.0, 0.0),\n\tVec3(0.0, 1.0, 0.0),\n\tVec3(0.0, 0.0, 1.0),\n\tVec3(-1.0, 0.0, 0.0),\n\tVec3(0.0, -1.0, 0.0),\n\tVec3(0.0, 0.0, -1.0),\n\tVec3(2.3, 7.6, 0.1),\n\tVec3(1000.3, 934.2, 3.401),\n\tVec3(2.6, 0.65, 1.7),\n\tVec3(-2.32, 0.0000012, 3.8),\n\tVec3(-5.3, -4.3, -3.3),\n\tVec3(-1000, -1000, -1000),\n\n};\nconst Vec3 unitVectors[12]{\n\tVec3(1.0, 0.0, 0.0),\n\tVec3(0.0, 1.0, 0.0),\n\tVec3(0.0, 0.0, 1.0),\n\tVec3(-1.0, 0.0, 0.0),\n\tVec3(0.0, -1.0, 0.0),\n\tVec3(0.0, 0.0, -1.0),\n\tnormalize(Vec3(2.3, 7.6, 0.1)),\n\tnormalize(Vec3(1000.3, 934.2, 3.401)),\n\tnormalize(Vec3(2.6, 0.65, 1.7)),\n\tnormalize(Vec3(-2.32, 0.0000012, 3.8)),\n\tnormalize(Vec3(-5.3, -4.3, -3.3)),\n\tnormalize(Vec3(-1000, -1000, -1000)),\n};\nconst Mat3 matrices[9]{\n\tMat3{0,0,0,0,0,0,0,0,0},\n\tMat3{1,0,0,0,1,0,0,0,1},\n\tMat3{0,1,0,0,0,1,0,0,0},\n\tMat3{0,0,1,0,1,0,1,0,0},\n\tMat3{0,0,0,1,0,0,0,1,0},\n\tMat3{1,0,0,0,0,0,0,0,0},\n\tMat3{1,1,1,1,1,1,1,1,1},\n\tMat3{5.3, 0,0,0, 7.3, 0,0,0, 2.3},\n\tMat3{3.7, 2.3, -3.5, 1.3, -2.5, 1.6, -3.2, 2.3, 3.4},\n};\nconst Rotation rotations[19]{\n\tRotation(),\n\tRotation::rotX(0.8),\n\tRotation::rotY(0.8),\n\tRotation::rotZ(0.8),\n\tRotation::rotX(-0.8),\n\tRotation::rotY(-0.8),\n\tRotation::rotZ(-0.8),\n\tRotation::fromEulerAngles(0.2, 0.3, 0.4),\n\tRotation::fromEulerAngles(1.2, -0.5, 0.3),\n\tRotation::Predefined::IDENTITY,\n\tRotation::Predefined::X_90,\n\tRotation::Predefined::X_180,\n\tRotation::Predefined::X_270,\n\tRotation::Predefined::Y_90,\n\tRotation::Predefined::Y_180,\n\tRotation::Predefined::Y_270,\n\tRotation::Predefined::Z_90,\n\tRotation::Predefined::Z_180,\n\tRotation::Predefined::Z_270,\n};\n\nVec3f badVerticesI[8]{\n\t{3.7427008831009605f, 0.19949999999997348f, -2.8372588570310806f},\n\t{3.7427008831009791f, -0.00050000000002671519f, -2.8372588570310575f},\n\t{4.7430976602077610f, -0.00050000000004078726f, -3.8166496311117655f},\n\t{4.7430976602077424f, 0.19949999999995938f, -3.8166496311117886f},\n\t{4.1624397862784015f, 0.19950000000005996f, -2.4085173811281768f},\n\t{4.1624397862784202f, -0.00049999999994022881f, -2.4085173811281537f},\n\t{5.1628365633852020f, -0.00049999999995430089f, -3.3879081552088617f},\n\t{5.1628365633851834f, 0.19950000000004586f, -3.3879081552088848f},\n};\n\nVec3f badVerticesJ[8]{\n\t{5.1677962452787920f, -0.00049999999985722576f, -3.3185062700045100f},\n\t{5.1677962452787707f, 0.19950000000014328f, -3.3185062700046259f},\n\t{6.5642349861367375f, 0.19950000000024037f, -3.4183002729857077f},\n\t{6.5642349861367588f, -0.00049999999976013676f, -3.4183002729855918f},\n\t{5.1250273868583260f, -0.00050000000020963831f, -3.9169800160865020f},\n\t{5.1250273868583047f, 0.19949999999979087f, -3.9169800160866179f},\n\t{6.5214661277162715f, 0.19949999999988796f, -4.0167740190677002f},\n\t{6.5214661277162929f, -0.00050000000011254930f, -4.0167740190675838f}\n};\n};"
  },
  {
    "path": "tests/testValues.h",
    "content": "#pragma once\n\n#include <Physics3D/math/linalg/vec.h>\n#include <Physics3D/math/linalg/mat.h>\n#include <Physics3D/math/rotation.h>\n\nnamespace P3D {\nextern const Vec3 vectors[13];\nextern const Vec3 unitVectors[12];\nextern const Mat3 matrices[9];\nextern const Rotation rotations[19];\n\n// test for bad vertices\nextern Vec3f badVerticesI[8];\nextern Vec3f badVerticesJ[8];\n};\n\n"
  },
  {
    "path": "tests/tests.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"boundsTree2Tests.cpp\" />\n    <ClCompile Include=\"constraintTests.cpp\" />\n    <ClCompile Include=\"ecsTests.cpp\" />\n    <ClCompile Include=\"estimateMotion.cpp\" />\n    <ClCompile Include=\"estimationTests.cpp\" />\n    <ClCompile Include=\"generators.cpp\" />\n    <ClCompile Include=\"geometryTests.cpp\" />\n    <ClCompile Include=\"guiTests.cpp\" />\n    <ClCompile Include=\"indexedShapeTests.cpp\" />\n    <ClCompile Include=\"inertiaTests.cpp\" />\n    <ClCompile Include=\"jointTests.cpp\" />\n    <ClCompile Include=\"lexerTests.cpp\" />\n    <ClCompile Include=\"mathTests.cpp\" />\n    <ClCompile Include=\"rotationTests.cpp\" />\n    <ClCompile Include=\"motionTests.cpp\" />\n    <ClCompile Include=\"physicalStructureTests.cpp\" />\n    <ClCompile Include=\"physicsTests.cpp\" />\n    <ClCompile Include=\"testFrameworkConsistencyTests.cpp\" />\n    <ClCompile Include=\"testsMain.cpp\" />\n    <ClCompile Include=\"testValues.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"compare.h\" />\n    <ClInclude Include=\"estimateMotion.h\" />\n    <ClInclude Include=\"generators.h\" />\n    <ClInclude Include=\"randomValues.h\" />\n    <ClInclude Include=\"simulation.h\" />\n    <ClInclude Include=\"testsMain.h\" />\n    <ClInclude Include=\"testValues.h\" />\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <VCProjectVersion>15.0</VCProjectVersion>\n    <ProjectGuid>{874CA9E0-23D2-4B91-837B-BCE8B7C9668D}</ProjectGuid>\n    <RootNamespace>tests</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup />\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>engine.lib;graphics.lib;physics.lib;util.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalIncludeDirectories>$(SolutionDir)include;$(SolutionDir)</AdditionalIncludeDirectories>\n      <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <AdditionalLibraryDirectories>$(SolutionDir)lib;$(OutDir)</AdditionalLibraryDirectories>\n      <AdditionalDependencies>engine.lib;graphics.lib;Physics3D.lib;util.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <Link>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <AdditionalDependencies>engine.lib;graphics.lib;physics.lib;util.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n      <AdditionalIncludeDirectories>$(SolutionDir)include;$(SolutionDir)</AdditionalIncludeDirectories>\n      <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>\n      <PreprocessorDefinitions>_MBCS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <AdditionalLibraryDirectories>$(SolutionDir)lib;$(OutDir)</AdditionalLibraryDirectories>\n      <AdditionalDependencies>engine.lib;graphics.lib;Physics3D.lib;util.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "tests/testsMain.cpp",
    "content": "#include \"testsMain.h\"\n\n#include <vector>\n#include <iostream>\n#include <cstring>\n#include <stdio.h>\n\n#include <string>\n#include <fstream>\n#include \"stdarg.h\"\n\n#include <chrono>\n\n#include \"../util/terminalColor.h\"\n#include \"../util/parseCPUIDArgs.h\"\n#include \"../util/cmdParser.h\"\n\n#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)\nstatic const char sepChar = '\\\\';\n#else\nstatic const char sepChar = '/';\n#endif\n\n\nusing namespace std;\nusing namespace chrono;\n\nstatic const TerminalColor SUCCESS_COLOR = TerminalColor::GREEN;\nstatic const TerminalColor FAILURE_COLOR = TerminalColor::RED;\nstatic const TerminalColor ERROR_COLOR = TerminalColor::MAGENTA;\nstatic const TerminalColor SKIP_COLOR = TerminalColor::LIGHT_GRAY;\n\nstringstream logStream;\nthread_local TestInterface __testInterface;\n// a referenceable boolean, for use in AssertComparer and TolerantAssertComparer\n// using just a literal true would cause bugs as the literal falls out of scope after the return, leading to unpredictable results\nconst bool reffableTrue = true;\n\nstatic void resetLog() {\n\tlogStream.str(\"\");\n\tlogStream.clear();\n}\n\nchar logBuffer[1 << 16];\n\nvoid logf(const char* format, ...) {\n\n\tva_list args;\n\tva_start(args, format);\n\tint length = std::vsnprintf(logBuffer, 1 << 16, format, args);\n\tva_end(args);\n\n\tlogStream << logBuffer << '\\n';\n}\n\nstatic void printDeltaTime(time_point<system_clock> startTime, TerminalColor c) {\n\tduration<double> delta = system_clock::now() - startTime;\n\tsetColor(c);\n\tcout << \" (\" << fixed << delta.count() << \"s)\\n\";\n}\n\nstatic ifstream getFileStream(const char* fileName) {\n\tifstream s(fileName);\n\tif(s.good()) return s;\n\n\tstring path = string(\"tests\") + sepChar + fileName;\n\ts = ifstream(path);\n\tif(s.good()) return s;\n\n\tpath = string(\"..\") + sepChar + path;\n\ts = ifstream(path);\n\tif(s.good()) return s;\n\n\treturn ifstream(string(\"..\") + sepChar + path);\n}\n\n#define SHOW_LINES_BEFORE 5\n#define SHOW_LINES_AFTER 2\n\nstatic void printFileSlice(const char* fileName, int line) {\n\tifstream inFile = getFileStream(fileName);\n\n\tint t = 0;\n\n\tif(inFile.good()) {\n\t\t// skip lines until right before first line to show\n\t\tfor(int i = 0; i < line - SHOW_LINES_BEFORE - 1; i++) {\n\t\t\tstring l;\n\t\t\tgetline(inFile, l);\n\t\t}\n\n\t\tsetColor(TerminalColor::WHITE);\n\n\t\tstring s;\n\t\tfor(int i = -SHOW_LINES_BEFORE; i <= SHOW_LINES_AFTER; i++) {\n\t\t\tif(!getline(inFile, s)) break;\n\t\t\tif(i == 0) {\n\t\t\t\tsetColor(TerminalColor::YELLOW);\n\t\t\t}\n\t\t\tprintf(\"%d: %s\", line + i, s.c_str());\n\t\t\tif(i == 0) {\n\t\t\t\tcout << \"  <<<<\";\n\t\t\t\tsetColor(TerminalColor::WHITE);\n\t\t\t}\n\t\t\tcout << endl;\n\t\t}\n\t} else {\n\t\tsetColor(TerminalColor::WHITE);\n\t\tprintf(\"Could not open File %s for debugging :(\\n\", fileName);\n\t}\n}\n\nstatic void dumpLog() {\n\tsetColor(TerminalColor::GREEN);\n\tcout << logStream.str().c_str();\n}\nenum class TestResult {\n\tSUCCESS = 0,\n\tFAILURE = 1,\n\tERROR = 2,\n\tSKIP = 3\n};\n\nstruct TestFlags {\n\tbool coverageEnabled;\n\tbool allowSkip;\n\tbool catchErrors;\n\tbool debugOnFailure;\n};\n\nclass Test {\npublic:\n\tconst char* filePath;\n\tconst char* fileName;\n\tconst char* funcName;\n\tTestType type;\n\tvoid(*testFunc)();\n\n\tTest() :\n\t\tfilePath(nullptr), funcName(nullptr), fileName(nullptr), testFunc(nullptr), type(TestType::NORMAL) {};\n\tTest(const char* filePath, const char* funcName, void(*testFunc)(), TestType type) :\n\t\tfilePath(filePath),\n\t\tfuncName(funcName),\n\t\ttestFunc(testFunc),\n\t\ttype(type),\n\t\tfileName(std::strrchr(this->filePath, sepChar) ? std::strrchr(this->filePath, sepChar) + 1 : this->filePath) {}\nprivate:\n\tTestResult runNoErrorChecking(TestFlags flags, time_point<system_clock>& startTime) {\n\t\t__testInterface = TestInterface(flags.debugOnFailure);\n\n\t\ttry {\n\t\t\tstartTime = system_clock::now();\n\n\t\t\ttestFunc();\n\n\t\t\tstd::size_t assertCount = __testInterface.getAssertCount();\n\t\t\tsetColor(assertCount > 0 ? TerminalColor::GRAY : TerminalColor::RED);\n\t\t\tcout << \" [\" << assertCount << \"]\";\n\n\t\t\tprintDeltaTime(startTime, SUCCESS_COLOR);\n\n\t\t\treturn TestResult::SUCCESS;\n\t\t} catch(AssertionError& e) {\n\n\t\t\tprintDeltaTime(startTime, FAILURE_COLOR);\n\t\t\tdumpLog();\n\n\t\t\tsetColor(TerminalColor::RED);\n\t\t\tprintf(\"An assertion was incorrect at line %d:\\n\", e.line);\n\n\t\t\tprintFileSlice(filePath, e.line);\n\n\t\t\tsetColor(TerminalColor::YELLOW);\n\t\t\tcout << e.what() << endl;\n\t\t\tsetColor(TerminalColor::WHITE);\n\n\t\t\treturn TestResult::FAILURE;\n\t\t}\n\t}\npublic:\n\tTestResult run(TestFlags flags) {\n\t\tresetLog();\n\n\t\tsetColor(TerminalColor::CYAN);\n\t\tcout << fileName << \":\" << funcName;\n\n\t\tif(flags.allowSkip && type == TestType::SLOW) {\n\t\t\tsetColor(SKIP_COLOR);\n\t\t\tcout << \" (skip)\\n\";\n\t\t\treturn TestResult::SKIP;\n\t\t}\n\n\t\ttime_point<system_clock> startTime;\n\n\t\tif(!flags.catchErrors) {\n\t\t\treturn runNoErrorChecking(flags, startTime);\n\t\t} else {\n\t\t\ttry {\n\t\t\t\treturn runNoErrorChecking(flags, startTime);\n\t\t\t} catch(exception& e) {\n\t\t\t\tprintDeltaTime(startTime, ERROR_COLOR);\n\t\t\t\tdumpLog();\n\t\t\t\tsetColor(TerminalColor::RED); printf(\"An general error was thrown: %s\\n\", e.what());\n\t\t\t\treturn TestResult::ERROR;\n\t\t\t} catch(string& e) {\n\t\t\t\tprintDeltaTime(startTime, ERROR_COLOR);\n\t\t\t\tdumpLog();\n\t\t\t\tsetColor(TerminalColor::RED); printf(\"An string exception was thrown: %s\\n\", e.c_str());\n\t\t\t\treturn TestResult::ERROR;\n\t\t\t} catch(const char* ex) {\n\t\t\t\tprintDeltaTime(startTime, ERROR_COLOR);\n\t\t\t\tdumpLog();\n\t\t\t\tsetColor(TerminalColor::RED); printf(\"A char* exception was thrown: %s\\n\", ex);\n\t\t\t\treturn TestResult::ERROR;\n\t\t\t} catch(...) {\n\t\t\t\tprintDeltaTime(startTime, ERROR_COLOR);\n\t\t\t\tdumpLog();\n\t\t\t\tsetColor(TerminalColor::RED); printf(\"An unknown exception was thrown\\n\");\n\t\t\t\treturn TestResult::ERROR;\n\t\t\t}\n\t\t}\n\t}\n};\n\nAssertionError::AssertionError(int line, const char* info) : line(line), info(info) {}\nconst char* AssertionError::what() const noexcept { return info; }\n\n// For some reason having this in static memory breaks it, a pointer seems to work\nvector<Test>* tests = nullptr;\n\n#ifdef _MSC_VER\n#define WIN32_LEAN_AND_MEAN\n#include <Windows.h>\nHANDLE console;\n\nstatic void initConsole() {\n\tconsole = GetStdHandle(STD_OUTPUT_HANDLE);\n\tHWND consoleWindow = GetConsoleWindow();\n\n\tRECT r;\n\tGetWindowRect(consoleWindow, &r);\n\n\tMoveWindow(consoleWindow, r.left, r.top, 800, 800, TRUE);\n}\n#else\nstatic void initConsole() {}\n#endif\n\nstatic bool isCoveredBy(Test& test, const std::vector<std::string>& filters) {\n\tif(filters.size() == 0) {\n\t\treturn true;\n\t}\n\tfor(const std::string& filter : filters) {\n\t\tif(filter == test.fileName || filter + \".cpp\" == test.fileName || filter == test.funcName || filter == test.fileName + std::string(\":\") + test.funcName) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nstatic void runTests(const std::vector<std::string>& filter, TestFlags flags) {\n\tsetColor(TerminalColor::WHITE); cout << \"Starting tests: \";\n\tsetColor(SUCCESS_COLOR); cout << \"[SUCCESS] \";\n\tsetColor(FAILURE_COLOR); cout << \"[FAILURE] \";\n\tsetColor(ERROR_COLOR); cout << \"[ERROR] \";\n\tsetColor(SKIP_COLOR); cout << \"[SKIP]\\n\";\n\tsetColor(TerminalColor::WHITE); cout << \"Number of tests: \" << tests->size() << endl;\n\n\tint totalTestsRan = 0;\n\tint resultCounts[4]{0,0,0,0};\n\tfor(Test& t : *tests) {\n\t\tif(isCoveredBy(t, filter)) {\n\t\t\tTestResult result = t.run(flags);\n\t\t\tif(result != TestResult::SKIP) totalTestsRan++;\n\t\t\tresultCounts[static_cast<int>(result)]++;\n\t\t}\n\t}\n\n\tsetColor(TerminalColor::WHITE);\n\tcout << \"Tests finished! Ran \" << totalTestsRan << \"/\" << tests->size() << \" tests\\n\";\n\n\tsetColor(SUCCESS_COLOR); cout << resultCounts[0] << \" SUCCESS\\n\";\n\tsetColor(FAILURE_COLOR); cout << resultCounts[1] << \" FAILURE\\n\";\n\tsetColor(ERROR_COLOR); cout << resultCounts[2] << \" ERROR\\n\";\n\tsetColor(SKIP_COLOR); cout << resultCounts[3] << \" SKIP\" << endl;\n}\n\nTestFlags getTestFlags(const Util::ParsedArgs& cmdArgs) {\n\tTestFlags result;\n\n\tresult.coverageEnabled = cmdArgs.hasFlag(\"coverage\");\n\tresult.catchErrors = !cmdArgs.hasFlag(\"nocatch\");\n\tresult.allowSkip = cmdArgs.argCount() == 0;\n\tresult.debugOnFailure = cmdArgs.hasFlag(\"debug\");\n\n\tif(cmdArgs.hasFlag(\"noskip\")) result.allowSkip = false;\n\n\treturn result;\n}\n\nint main(int argc, const char** argv) {\n\tinitConsole();\n\n\tUtil::ParsedArgs cmdArgs(argc, argv);\n\n\tstd::cout << Util::printAndParseCPUIDArgs(cmdArgs).c_str() << \"\\n\";\n\tTestFlags flags = getTestFlags(cmdArgs);\n\n\trunTests(cmdArgs.args(), flags);\n\n\tif(flags.coverageEnabled) return 0;\n\n\twhile(true) {\n\t\tstring input;\n\n\t\tsetColor(TerminalColor::WHITE);\n\t\tcout << \"> \";\n\t\tcin >> input;\n\n\t\tif(input == \"\") {\n\t\t\tcontinue;\n\t\t} else if(input == \"exit\") {\n\t\t\tbreak;\n\t\t} else {\n\t\t\tflags.allowSkip = false;\n\t\t\trunTests(std::vector<std::string>{input}, flags);\n\t\t}\n\t}\n}\n\nstatic void logAssertError(string text) {\n\tsetColor(TerminalColor::RED);\n\tcout << text.c_str();\n}\n\nTestAdder::TestAdder(const char* file, const char* name, void(*f)(), TestType isSlow) {\n\tif(tests == nullptr) tests = new vector<Test>();\n\n\ttests->push_back(Test(file, name, f, isSlow));\n}\n"
  },
  {
    "path": "tests/testsMain.h",
    "content": "#pragma once\n\n#include \"compare.h\"\n#include <Physics3D/misc/toString.h>\n#include <sstream>\n\nclass TestInterface {\n\tsize_t assertCount = 0;\npublic:\n\tbool debugOnFailure;\n\tTestInterface() : debugOnFailure(false) {}\n\tTestInterface(bool debugOnFailure) : debugOnFailure(debugOnFailure) {}\n\tinline void markAssert() {\n\t\tassertCount++;\n\t}\n\tinline size_t getAssertCount() const { return assertCount; }\n};\n\nenum class TestType {\n\tNORMAL,\n\tSLOW\n};\n\n#define __JOIN2(a,b) a##b\n#define __JOIN(a,b) __JOIN2(a,b)\n#define TEST_CASE(func) void func(); static TestAdder __JOIN(tAdder, __LINE__)(__FILE__, #func, func, TestType::NORMAL); void func()\n#define TEST_CASE_SLOW(func) void func(); static TestAdder __JOIN(tAdder, __LINE__)(__FILE__, #func, func, TestType::SLOW); void func()\n\nstruct TestAdder {\n\tTestAdder(const char* filePath, const char* nameName, void(*testFunc)(), TestType isSlow);\n};\n\nclass AssertionError {\n\tconst char* info;\npublic:\n\tint line;\n\tAssertionError(int line, const char* info);\n\tconst char* what() const noexcept;\n};\n\nvoid logf(const char* format, ...);\nextern std::stringstream logStream;\nextern thread_local TestInterface __testInterface;\nextern const bool reffableTrue;\n\n// Testing utils:\n\ntemplate<typename R, typename P>\nconst char* errMsg(const R& first, const P& second, const char* sep) {\n\tstd::stringstream s;\n\ts << first;\n\ts << ' ';\n\ts << sep;\n\ts << '\\n';\n\ts << second;\n\n\tstd::string msg = s.str();\n\n\tconst char* data = msg.c_str();\n\tchar* dataBuf = new char[msg.size() + 1];\n\tfor(int i = 0; i < msg.size() + 1; i++)\n\t\tdataBuf[i] = data[i];\n\n\treturn dataBuf;\n}\n\ntemplate<typename R>\nconst char* errMsg(const R& first) {\n\tstd::stringstream s;\n\ts << \"(\";\n\ts << first;\n\ts << \")\";\n\tstd::string msg = s.str();\n\n\tconst char* data = msg.c_str();\n\tchar* dataBuf = new char[msg.size() + 1];\n\tfor(int i = 0; i < msg.size() + 1; i++)\n\t\tdataBuf[i] = data[i];\n\n\treturn dataBuf;\n}\n\n\n#ifdef _MSC_VER\n#define __DEBUG_BREAK __debugbreak();\n#else\n#define __DEBUG_BREAK\n#endif\n#define __ASSERT_FAILURE(line, printText) if(__testInterface.debugOnFailure) {__DEBUG_BREAK} throw AssertionError(line, printText)\n\ntemplate<typename T>\nclass AssertComparer {\npublic:\n\tconst int line;\n\tconst T& arg;\n\n\tAssertComparer(int line, const T& arg) : line(line), arg(arg) {}\n\n\ttemplate<typename P> AssertComparer<bool> operator<(const P& other) const { if(!(arg < other)) { __ASSERT_FAILURE(line, errMsg(arg, other, \"<\")); }; return AssertComparer<bool>(this->line, reffableTrue); }\n\ttemplate<typename P> AssertComparer<bool> operator>(const P& other) const { if(!(arg > other)) { __ASSERT_FAILURE(line, errMsg(arg, other, \">\")); }; return AssertComparer<bool>(this->line, reffableTrue); }\n\ttemplate<typename P> AssertComparer<bool> operator<=(const P& other) const { if(!(arg <= other)) { __ASSERT_FAILURE(line, errMsg(arg, other, \"<=\")); }; return AssertComparer<bool>(this->line, reffableTrue); }\n\ttemplate<typename P> AssertComparer<bool> operator>=(const P& other) const { if(!(arg >= other)) { __ASSERT_FAILURE(line, errMsg(arg, other, \">=\")); }; return AssertComparer<bool>(this->line, reffableTrue); }\n\ttemplate<typename P> AssertComparer<bool> operator==(const P& other) const { if(!(arg == other)) { __ASSERT_FAILURE(line, errMsg(arg, other, \"==\")); }; return AssertComparer<bool>(this->line, reffableTrue); }\n\ttemplate<typename P> AssertComparer<bool> operator!=(const P& other) const { if(!(arg != other)) { __ASSERT_FAILURE(line, errMsg(arg, other, \"!=\")); }; return AssertComparer<bool>(this->line, reffableTrue); }\n};\n\ntemplate<typename T, typename Tol>\nclass TolerantAssertComparer {\npublic:\n\tconst int line;\n\tconst T& arg;\n\tconst Tol tolerance;\n\n\tTolerantAssertComparer(int line, const T& arg, Tol tolerance) : line(line), arg(arg), tolerance(tolerance) {}\n\n\ttemplate<typename T2> TolerantAssertComparer<bool, Tol> operator<(const T2& other) const { if(!tolerantLessThan(arg, other, tolerance)) { __ASSERT_FAILURE(line, errMsg(arg, other, \"<\")); }; return TolerantAssertComparer<bool, Tol>(this->line, reffableTrue, this->tolerance); }\n\ttemplate<typename T2> TolerantAssertComparer<bool, Tol> operator>(const T2& other) const { if(!tolerantGreaterThan(arg, other, tolerance)) { __ASSERT_FAILURE(line, errMsg(arg, other, \">\")); }; return TolerantAssertComparer<bool, Tol>(this->line, reffableTrue, this->tolerance); }\n\ttemplate<typename T2> TolerantAssertComparer<bool, Tol> operator<=(const T2& other) const { if(!tolerantLessOrEqual(arg, other, tolerance)) { __ASSERT_FAILURE(line, errMsg(arg, other, \"<=\")); }; return TolerantAssertComparer<bool, Tol>(this->line, reffableTrue, this->tolerance); }\n\ttemplate<typename T2> TolerantAssertComparer<bool, Tol> operator>=(const T2& other) const { if(!tolerantGreaterOrEqual(arg, other, tolerance)) { __ASSERT_FAILURE(line, errMsg(arg, other, \">=\")); }; return TolerantAssertComparer<bool, Tol>(this->line, reffableTrue, this->tolerance); }\n\ttemplate<typename T2> TolerantAssertComparer<bool, Tol> operator==(const T2& other) const { if(!tolerantEquals(arg, other, tolerance)) { __ASSERT_FAILURE(line, errMsg(arg, other, \"==\")); }; return TolerantAssertComparer<bool, Tol>(this->line, reffableTrue, this->tolerance); }\n\ttemplate<typename T2> TolerantAssertComparer<bool, Tol> operator!=(const T2& other) const { if(!tolerantNotEquals(arg, other, tolerance)) { __ASSERT_FAILURE(line, errMsg(arg, other, \"!=\")); }; return TolerantAssertComparer<bool, Tol>(this->line, reffableTrue, this->tolerance); }\n};\n\nstruct AssertBuilder {\n\tint line;\n\tAssertBuilder(int line) : line(line) {};\n\ttemplate<typename T>\n\tAssertComparer<T> operator<(const T& other) const { return AssertComparer<T>(line, other); }\n};\n\ntemplate<typename Tol>\nstruct TolerantAssertBuilder {\n\tint line;\n\tTol tolerance;\n\tTolerantAssertBuilder(int line, Tol tolerance) : line(line), tolerance(tolerance) {};\n\ttemplate<typename T>\n\tTolerantAssertComparer<T, Tol> operator<(const T& other) const { return TolerantAssertComparer<T, Tol>(line, other, tolerance); }\n};\n\n#define ASSERT_STRICT(condition) do {if(!(AssertBuilder(__LINE__) < condition).arg) {__ASSERT_FAILURE(__LINE__, \"false\");}__testInterface.markAssert(); }while(false)\n#define ASSERT_TOLERANT(condition, tolerance) do {if(!(TolerantAssertBuilder<decltype(tolerance)>(__LINE__, tolerance) < condition).arg) {__ASSERT_FAILURE(__LINE__, \"false\");} __testInterface.markAssert(); }while(false)\n#define ASSERT_TRUE(condition) do {if(!(condition)) {__ASSERT_FAILURE(__LINE__, \"false\");}__testInterface.markAssert(); }while(false)\n#define ASSERT_FALSE(condition) do {if(condition) {__ASSERT_FAILURE(__LINE__, \"true\");}__testInterface.markAssert(); }while(false)\n\n#define PREV_VAL_NAME __JOIN(____previousValue, __LINE__)\n#define ISFILLED_NAME __JOIN(____isFilled, __LINE__)\n#define REMAINS_CONSTANT_STRICT(value) do{\\\n\tstatic bool ISFILLED_NAME = false;\\\n\tstatic auto PREV_VAL_NAME = value;\\\n\tif(ISFILLED_NAME) ASSERT_STRICT(PREV_VAL_NAME == (value));\\\n\tISFILLED_NAME = true;\\\n}while(false)\n#define REMAINS_CONSTANT_TOLERANT(value, tolerance) do{\\\n\tstatic bool ISFILLED_NAME = false;\\\n\tstatic auto PREV_VAL_NAME = value;\\\n\tif(ISFILLED_NAME) ASSERT_TOLERANT(PREV_VAL_NAME == (value), tolerance);\\\n\tISFILLED_NAME = true;\\\n}while(false)\n"
  },
  {
    "path": "util/cmdParser.h",
    "content": "#pragma once\n\n#include <vector>\n#include <string>\n\nnamespace Util {\nclass ParsedArgs {\n\tstruct OptionalArg {\n\t\tstd::string option;\n\t\tstd::string value;\n\t};\n\tstd::vector<std::string> inputArgs;\n\tstd::vector<std::string> flags;\n\tstd::vector<OptionalArg> optionals;\npublic:\n\n\tParsedArgs(int argc, const char** argv) {\n\t\tfor(int i = 1; i < argc; i++) {\n\t\t\tconst char* item = argv[i];\n\t\t\tif(item[0] == '-') {\n\t\t\t\tif(item[1] == '-') {\n\t\t\t\t\tif(i + 1 < argc) {\n\t\t\t\t\t\toptionals.push_back(OptionalArg{std::string(item + 2), std::string(argv[i + 1])});\n\t\t\t\t\t\ti++;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow \"No associated value for the final optional arg\";\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tflags.emplace_back(item + 1);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tinputArgs.emplace_back(item);\n\t\t\t}\n\t\t}\n\t}\n\n\tbool hasFlag(const char* flag) const {\n\t\tfor(const std::string& f : flags) {\n\t\t\tif(f == flag) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tstd::string getOptional(const char* key) const {\n\t\tfor(const OptionalArg& o : optionals) {\n\t\t\tif(o.option == key) {\n\t\t\t\treturn o.value;\n\t\t\t}\n\t\t}\n\t\treturn std::string();\n\t}\n\n\tstd::size_t argCount() const { return inputArgs.size(); }\n\tconst std::vector<std::string>& args() { return inputArgs; }\n\n\tconst std::string& operator[](std::size_t index) const { return inputArgs[index]; }\n\n\tauto begin() const { return inputArgs.begin(); }\n\tauto end() const { return inputArgs.end(); }\n};\n};\n"
  },
  {
    "path": "util/fileUtils.cpp",
    "content": "#include \"fileUtils.h\"\n\n#include \"log.h\"\n#include <fstream>\n#include <sstream>\n\n#ifdef _WIN32\n\t#include <direct.h>\n\t#include <Windows.h>\n\n\tbool Util::doesFileExist(const std::string& fileName) {\n\t\tstruct stat buffer;\n\t\tif (stat(fileName.c_str(), &buffer) != -1) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\t\n\tstd::string Util::getFullPath(const std::string& fileName) {\n\t\tTCHAR buf[MAX_PATH] = TEXT(\"\");\n\t\tTCHAR** lppPart = {NULL};\n\t\tGetFullPathName(fileName.c_str(), MAX_PATH, buf, lppPart);\n\t\treturn std::string(buf);\n\t}\n\n#else\n\t#include <stdlib.h>\n\t// for some reason gcc still does not support <filesystem>\n\t#if __GNUC__ >= 8\n\t#include <filesystem>\n\tnamespace fs = std::filesystem;\n\t#else\n\t#include <experimental/filesystem>\n\tnamespace fs = std::experimental::filesystem;\n\t#endif\n\n\tbool Util::doesFileExist(const std::string& fileName) {\n\t\treturn fs::exists(fileName);\n\t}\n\n\tstd::string Util::getFullPath(const std::string& fileName) {\n\t\tchar* path = realpath(fileName.c_str(), NULL);\n\t\tstd::string result(path);\n\t\tfree(path);\n\t\treturn result;\n\t}\n#endif\n\nnamespace Util {\n\nvoid warnIfFileExists(const std::string& fileName) {\n\tif (doesFileExist(fileName)) {\n\t\tLog::warn(\"File already exists: %s\", fileName.c_str());\n\t}\n}\n\nstd::string parseFile(const std::string& path) {\n\tif (path.empty())\n\t\treturn std::string();\n\n\tstd::ifstream fileStream(path);\n\n\tLog::setDelimiter(\"\");\n\tLog::info(\"Reading (%s) ... \", path.c_str());\n\n\tif (fileStream.fail() || !fileStream.is_open()) {\n\t\tLog::error(\"Fail\");\n\t\tLog::setDelimiter(\"\\n\");\n\n\t\treturn \"\";\n\t}\n\n\tLog::debug(\"Done\");\n\tLog::setDelimiter(\"\\n\");\n\n\tstd::string line;\n\tstd::stringstream stringStream;\n\twhile (getline(fileStream, line))\n\t\tstringStream << line << \"\\n\";\n\n\tfileStream.close();\n\n\treturn stringStream.str();\n}\n\n};"
  },
  {
    "path": "util/fileUtils.h",
    "content": "#pragma once\n\n#include <string>\n\nnamespace Util {\n\nbool doesFileExist(const std::string& fileName);\nvoid warnIfFileExists(const std::string& fileName);\nstd::string parseFile(const std::string& path);\nstd::string getFullPath(const std::string& filename);\n\n};"
  },
  {
    "path": "util/iteratorUtils.h",
    "content": "#pragma once\n\nstruct iterator_end {};\n\ntemplate<typename Iterator, typename IteratorEnd>\nclass default_iterator {\nprivate:\n\tIterator current;\n\tIterator end;\n\npublic:\n\tdefault_iterator() = default;\n\tdefault_iterator(const Iterator& start, const Iterator& end) : current(start), end(end) {\n\n\t}\n\n\tdefault_iterator& operator++() {\n\t\t++current;\n\n\t\treturn *this;\n\t}\n\n\tbool operator!=(IteratorEnd) const {\n\t\treturn current != end;\n\t}\n\n\tdecltype(*current)& operator*() const {\n\t\treturn *current;\n\t}\n\n\tbool operator==(Iterator iterator) const {\n\t\treturn current == iterator;\n\t}\n};\n\ntemplate<typename Iterator, typename IteratorEnd, typename Filter>\nclass filter_iterator {\nprivate:\n\tIterator current;\n\tIterator end;\n\tFilter filter;\n\npublic:\n\tfilter_iterator() = default;\n\tfilter_iterator(const Iterator& start, const Iterator& end, const Filter& filter) : current(start), end(end), filter(filter) {\n\t\twhile (current != end && !filter(current))\n\t\t\t++current;\n\t}\n\n\tfilter_iterator& operator++() {\n\t\tdo {\n\t\t\t++current;\n\t\t} while (current != end && !filter(current));\n\n\t\treturn *this;\n\t}\n\n\tbool operator!=(IteratorEnd) const {\n\t\treturn current != end;\n\t}\n\n\tdecltype(*current)& operator*() const {\n\t\treturn *current;\n\t}\n\n\tbool operator==(Iterator iterator) const {\n\t\treturn current == iterator;\n\t}\n};\n\ntemplate<typename Iterator, typename IteratorEnd, typename Transform>\nclass transform_iterator {\nprivate:\n\tIterator current;\n\tIterator end;\n\tTransform transform;\n\npublic:\n\ttransform_iterator() = default;\n\ttransform_iterator(const Iterator& start, const Iterator& end, const Transform& transform) : current(start), end(end), transform(transform) {\n\n\t}\n\n\ttransform_iterator& operator++() {\n\t\t++current;\n\n\t\treturn *this;\n\t}\n\n\tbool operator!=(IteratorEnd) const {\n\t\treturn current != end;\n\t}\n\n\tdecltype(transform(current)) operator*() const {\n\t\treturn transform(current);\n\t}\n\n\tbool operator==(Iterator iterator) const {\n\t\treturn current == iterator;\n\t}\n};\n\ntemplate<typename Iterator, typename IteratorEnd, typename Filter, typename Transform>\nclass filter_transform_iterator {\nprivate:\n\tIterator current;\n\tIterator end;\n\tFilter filter;\n\tTransform transform;\n\npublic:\n\tfilter_transform_iterator() = default;\n\tfilter_transform_iterator(const Iterator& start, const Iterator& end, const Filter& filter, const Transform& transform) : current(start), end(end), filter(filter), transform(transform) {\n\t\twhile (current != end && !filter(current))\n\t\t\t++current;\n\t}\n\n\tfilter_transform_iterator& operator++() {\n\t\tdo {\n\t\t\t++current;\n\t\t} while (current != end && !filter(current));\n\n\t\treturn *this;\n\t}\n\n\tbool operator!=(IteratorEnd) const {\n\t\treturn current != end;\n\t}\n\n\tdecltype(transform(current)) operator*() const {\n\t\treturn transform(current);\n\t}\n\n\tbool operator==(Iterator iterator) const {\n\t\treturn current == iterator;\n\t}\n};"
  },
  {
    "path": "util/log.cpp",
    "content": "#include \"log.h\"\n\n#include <stack>\n#include <iostream>\n#include <stdarg.h>\n\n#include \"terminalColor.h\"\n\nnamespace Log {\n\tstatic Level logLevel = Level::INFO;\n\n\tstatic std::stack<std::string> subjects;\n\tstatic std::string lastSubject = \"\";\n\tstatic bool newSubject = false;\n\n\tstatic std::string delimiter = \"\\n\";\n\n\tstatic FILE* logFile = nullptr;\n\n\tstatic void logTogether(const char* message, va_list args) {\n\t\tvprintf(message, args);\n\t\tif(logFile) {\n\t\t\tvfprintf(logFile, message, args);\n\t\t\tfflush(logFile);\n\t\t}\n\t}\n\n// the va_list must be recreated for both print and fprint\n#define va_logf(format, message) va_list args; va_start(args, format); vprintf(message.c_str(), args); va_end(args); if(logFile) {va_start(args, format); vfprintf(logFile, message.c_str(), args); va_end(args); fflush(logFile);}\n\n\tvoid init(const char* logFileName) {\n#ifdef _MSC_VER\n\t\tfopen_s(&logFile, logFileName, \"w\");\n#else\n\t\tlogFile = fopen(logFileName, \"w\");\n#endif\n\t}\n\tvoid stop() {\n\t\tfclose(logFile);\n\t\tlogFile = nullptr; // set to nullptr to prevent logs after program end from crashing the program by writing to an invalid file\n\t}\n\n\tstd::string topSubject() {\n\t\tif (subjects.empty())\n\t\t\treturn \"\";\n\n\t\treturn subjects.top();\n\t}\n\n\tsubject::subject(const std::string& title) {\n\t\tif (subjects.empty()) {\n\t\t\tsubjects.push(title);\n\t\t\tnewSubject = title != lastSubject;\n\t\t} else {\n\t\t\tif (title == subjects.top()) {\n\t\t\t\tnewSubject = false;\n\t\t\t} else if (title == lastSubject) {\n\t\t\t\tnewSubject = false;\n\t\t\t} else {\n\t\t\t\tnewSubject = true;\n\t\t\t}\n\t\t\tsubjects.push(title);\n\t\t}\n\t}\n\n\tsubject::~subject() {\n\t\tlastSubject = subjects.top();\n\t\tsubjects.pop();\n\t\tnewSubject = lastSubject != topSubject();\n\t}\n\n\tbool emptySubject() {\n\t\treturn topSubject().empty();\n\t}\n\n\tvoid setLogLevel(Level level) {\n\t\tlogLevel = level;\n\t}\n\n\tLevel getLogLevel() {\n\t\treturn logLevel;\n\t}\n\n\tstatic void printSubject(std::string subject) {\n\t\tsetColor(Color::SUBJECT);\n\t\tprintf(subject.c_str());\n\t\tfprintf(logFile, subject.c_str());\n\t\tfflush(logFile);\n\t\tsetColor(Color::NORMAL);\n\t\tnewSubject = false;\n\t}\n\n\tstatic void addSubjectIfNeeded() {\n\t\tif(newSubject && !topSubject().empty()) printSubject(\"\\n[\" + topSubject() + \"]:\\n\");\n\t\tif(!emptySubject()) printSubject(\"|\\t\");\n\t}\n\n\tvoid setDelimiter(std::string delimiter) {\n\t\tLog::delimiter = delimiter;\n\t}\n\n\tvoid debug(std::string format, ...) {\n\t\tif (logLevel != Level::NONE) {\n\t\t\taddSubjectIfNeeded();\n\t\t\tstd::string message = \"[DEBUG]: \" + format + delimiter;\n\t\t\tsetColor(Color::DEBUG);\n\t\t\tva_logf(format, message);\n\t\t\tsetColor(Color::NORMAL);\n\t\t}\n\t}\n\n\tvoid info(std::string format, ...) {\n\t\tif (logLevel <= Level::INFO) {\n\t\t\taddSubjectIfNeeded();\n\t\t\tstd::string message = \"[INFO]: \" + format + delimiter;\n\t\t\tsetColor(Color::INFO);\n\t\t\tva_logf(format, message);\n\t\t\tsetColor(Color::NORMAL);\n\t\t}\n\t}\n\n\tvoid warn(std::string format, ...) {\n\t\tif (logLevel <= Level::WARNING) {\n\t\t\taddSubjectIfNeeded();\n\t\t\tstd::string message = \"[WARN]: \" + format + delimiter;\n\t\t\tsetColor(Color::WARNING);\n\t\t\tva_logf(format, message);\n\t\t\tsetColor(Color::NORMAL);\n\t\t}\n\t}\n\n\tvoid error(std::string format, ...) {\n\t\tif (logLevel <= Level::ERROR) {\n\t\t\taddSubjectIfNeeded();\n\t\t\tstd::string message = \"[ERROR]: \" + format + delimiter;\n\t\t\tsetColor(Color::ERROR);\n\t\t\tva_logf(format, message);\n\t\t\tsetColor(Color::NORMAL);\n\t\t}\n\t}\n\n\tvoid fatal(std::string format, ...) {\n\t\tif (logLevel <= Level::FATAL) {\n\t\t\taddSubjectIfNeeded();\n\t\t\tstd::string message = \"[FATAL]: \" + format + delimiter;\n\t\t\tsetColor(Color::FATAL);\n\t\t\tva_logf(format, message);\n\t\t\tsetColor(Color::NORMAL);\n\t\t}\n\t}\n\n\tvoid print(std::string format,  ...) {\n\t\tsetColor(Color::NORMAL);\n\t\tva_logf(format, format);\n\t}\n\n\tvoid print(TerminalColorPair color, std::string format, ...) {\n\t\tsetColor(color);\n\t\tva_logf(format, format);\n\t}\n}\n"
  },
  {
    "path": "util/log.h",
    "content": "#pragma once\n\n#include <string>\n\n#include \"terminalColor.h\"\n\n#define LOG_DEBUG(FMT, ...) Log::debug(std::string(\"[%s:%d] \") + FMT, __FUNCTION__, __LINE__, __VA_ARGS__);\n\nnamespace Log {\n\t\n\tnamespace Color {\n\t\tconst TerminalColorPair DEBUG   { TerminalColor::GREEN  , TerminalColor::BLACK};\n\t\tconst TerminalColorPair INFO    { TerminalColor::CYAN   , TerminalColor::BLACK};\n\t\tconst TerminalColorPair WARNING { TerminalColor::YELLOW , TerminalColor::BLACK};\n\t\tconst TerminalColorPair ERROR   { TerminalColor::RED    , TerminalColor::BLACK};\n\t\tconst TerminalColorPair FATAL   { TerminalColor::BLACK  , TerminalColor::RED  };\n\t\tconst TerminalColorPair NORMAL  { TerminalColor::WHITE  , TerminalColor::BLACK};\n\t\tconst TerminalColorPair SUBJECT { TerminalColor::MAGENTA, TerminalColor::BLACK};\n\t}\n\n\tenum class Level : char {\n\t\tINFO    = 0,\n\t\tWARNING = 1,\n\t\tERROR   = 2,\n\t\tFATAL   = 3,\n\t\tNONE    = 4\n\t};\n\t\n\tclass subject {\n\tpublic:\n\t\tsubject(const std::string& title);\n\t\t~subject();\n\n\t\tsubject(subject&& other) = delete;\n\t\tsubject(const subject&) = delete;\n\t\tsubject& operator=(subject&& other) = delete;\n\t\tsubject& operator=(const subject&) = delete;\n\t};\n\n\tvoid init(const char* logFile);\n\tvoid stop();\n\n\tvoid setDelimiter(std::string delimiter);\n\n\tvoid debug(std::string format, ...);\n\tvoid info(std::string format, ...);\n\tvoid warn(std::string format, ...);\n\tvoid error(std::string format, ...);\n\tvoid fatal(std::string format, ...);\n\tvoid print(std::string format, ...);\n\tvoid print(TerminalColorPair color, std::string format, ...);\n\n\tvoid setLogLevel(Log::Level logLevel);\n\tLevel getLogLevel();\n};\n"
  },
  {
    "path": "util/parseCPUIDArgs.h",
    "content": "#pragma once\n\n#include <Physics3D/misc/cpuid.h>\n\n#include \"cmdParser.h\"\n\n#include <string>\n\nnamespace Util {\ninline std::string printAndParseCPUIDArgs(const ParsedArgs& cmdArgs) {\n\tstd::string message(\"Detected CPU Technologies: \");\n\tfor(size_t i = 0; i < P3D::CPUIDCheck::TECHNOLOGY_COUNT; i++) {\n\t\tif(P3D::CPUIDCheck::hasTechnology(1U << i)) message.append(P3D::CPUIDCheck::NAMES[i]).append(\" \");\n\t}\n\n\tbool disabledSomething = false;\n\n\tfor(int techI = 0; techI < P3D::CPUIDCheck::TECHNOLOGY_COUNT; techI++) {\n\t\tif(cmdArgs.hasFlag(P3D::CPUIDCheck::NAMES[techI])) {\n\t\t\tP3D::CPUIDCheck::disableTechnology(1 << techI);\n\t\t\tmessage.append(\"\\nDisabled technology -\").append(P3D::CPUIDCheck::NAMES[techI]);\n\t\t\tdisabledSomething = true;\n\t\t}\n\t}\n\n\tif(disabledSomething) {\n\t\tmessage.append(\"\\nEnabled CPU Technologies: \");\n\n\t\tfor(size_t i = 0; i < P3D::CPUIDCheck::TECHNOLOGY_COUNT; i++) {\n\t\t\tif(P3D::CPUIDCheck::hasTechnology(1U << i)) message.append(P3D::CPUIDCheck::NAMES[i]).append(\" \");\n\t\t}\n\t}\n\n\treturn message;\n}\n\ninline std::string printAndParseCPUIDArgs(int argc, const char** argv) {\n\treturn printAndParseCPUIDArgs(ParsedArgs(argc, argv));\n}\n};\n"
  },
  {
    "path": "util/properties.cpp",
    "content": "#include \"properties.h\"\n\n#include <fstream>\n\n#include \"stringUtil.h\"\n#include \"log.h\"\n\nnamespace Util {\n\nstd::regex Properties::regex = std::regex(\" *.+ *: *.+ *\");\n\nstd::string Properties::get(const std::string& property) const {\n\ttry {\n\t\tstd::string value = properties.at(property);\n\t\treturn value;\n\t} catch (const std::out_of_range&) {\n\t\treturn \"\";\n\t}\n}\n\nstd::map<std::string, std::string> Properties::get() {\n\treturn properties;\n}\n\nvoid Properties::set(const std::string& property, const std::string& value) {\n\tif (properties.find(property) == properties.end())\n\t\tproperties.insert(std::make_pair(property, value));\n\telse\n\t\tproperties[property] = value;\n}\n\nvoid Properties::remove(const std::string& property) {\n\tfor (auto iterator = properties.begin(); iterator != properties.end(); iterator++) {\n\t\tif (iterator->first == property) {\n\t\t\tproperties.erase(iterator);\n\t\t\treturn;\n\t\t}\n\t}\n}\n\nnamespace PropertiesParser {\n\tProperties read(const std::string& file) {\n\t\tLog::subject s(file);\n\n\t\tstd::ifstream inputstream;\n\t\tinputstream.open(file.c_str());\n\n\t\tif (!inputstream.is_open()) {\n\t\t\tLog::error(\"Properties file can't be found\");\n\t\t\treturn Properties();\n\t\t}\n\n\t\tProperties properties(file);\n\n\t\tstd::string line;\n\t\twhile (getline(inputstream, line)) {\n\t\t\tline = trim(line);\n\t\t\t\n\t\t\tif (line.empty() || line.at(0) == '#') {\n\t\t\t\tcontinue;\n\t\t\t} else if (!std::regex_match(line, Properties::regex)) {\n\t\t\t\tLog::warn(\"Incorrect syntax: %s\", line.c_str());\n\t\t\t} else {\n\t\t\t\tsize_t pos = line.find(':');\n\t\t\t\tstd::string property = rtrim(line.substr(0, pos));\n\t\t\t\tstd::string value = until(ltrim(line.substr(pos + 1, line.length())), ' ');\n\n\t\t\t\tproperties.set(property, value);\n\t\t\t}\n\t\t}\n\n\t\tinputstream.close();\n\n\t\treturn properties;\n\t}\n\n\tvoid write(const std::string& filename, Properties& properties) {\n\t\tLog::subject s(filename);\n\n\t\tLog::info(\"Writing %d properties\", properties.get().size());\n\n\t\tstd::ifstream ifile;\n\t\tifile.open(filename.c_str(), std::ios::in);\n\n\t\tif (!ifile.is_open()) \n\t\t\tLog::error(\"Properties file can't be found, creating new one\");\n\t\t\n\t\t// Read and save\n\t\tstd::string line;\n\t\tstd::vector<std::string> lines;\n\t\twhile (getline(ifile, line)) {\n\t\t\tstd::string trimmedLine = trim(line);\n\n\t\t\tif (trimmedLine.empty() || trimmedLine.at(0) == '#' || !std::regex_match(trimmedLine, Properties::regex)) { \n\t\t\t\tlines.push_back(line);\n\t\t\t\tcontinue;\n\t\t\t} else {\n\t\t\t\tsize_t pos = line.find(':');\n\t\t\t\tstd::string property = line.substr(0, pos);\n\t\t\t\tstd::string value = line.substr(pos + 1, line.length());\n\t\t\t\tstd::string trimmedProperty = rtrim(property);\t\t\t\t\n\t\t\t\tstd::string trimmedValue = until(ltrim(value), ' ');\n\t\t\t\tstd::string newTrimmedValue = properties.get(trimmedProperty);\n\n\t\t\t\tif (trimmedValue == newTrimmedValue) {\n\t\t\t\t\tlines.push_back(line);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tauto position = value.find(trimmedValue);\n\t\t\t\tstd::string newValue = value.replace(position, position + trimmedValue.length(), newTrimmedValue);\n\n\t\t\t\tstd::string newLine = property + \":\" + newValue;\n\n\t\t\t\tlines.push_back(newLine);\n\t\t\t}\n\t\t}\n\t\tifile.close();\n\n\t\t// Write\n\t\tstd::ofstream ofile;\n\t\tofile.open(filename.c_str(), std::ios::out | std::ios::trunc);\n\t\tfor (std::string& line : lines) \n\t\t\tofile << line << std::endl;\n\t\tofile.close();\n\t}\n}\n\n};"
  },
  {
    "path": "util/properties.h",
    "content": "#pragma once\n\n#include <string>\n#include <map>\t\n#include <regex>\n\nnamespace Util {\n\nclass Properties {\nprivate:\t\n\tstd::string filename;\n\tstd::map<std::string, std::string> properties;\n\npublic:\n\tstatic std::regex regex;\n\t\n\tinline Properties() {};\n\tinline Properties(const std::string& filename) : filename(filename) {};\n\n\tstd::string get(const std::string& property) const;\n\tstd::map<std::string, std::string> get();\n\tvoid set(const std::string& property, const std::string& value);\n\tvoid remove(const std::string& property);\n\n};\n\nnamespace PropertiesParser {\n\tProperties read(const std::string& file);\n\tvoid write(const std::string& file, Properties& properties);\n};\n\n};"
  },
  {
    "path": "util/resource/resource.cpp",
    "content": "#include \"resource.h\"\n\n#include \"resourceManager.h\"\n\nvoid Resource::setName(const std::string& name) {\n\tResourceManager::onResourceNameChange(this, name);\n}\n\nvoid Resource::setPath(const std::string& path) {\n\tResourceManager::onResourcePathChange(this, path);\n}\n\nstd::string Resource::getName() const {\n\treturn name;\n}\n\nstd::string Resource::getPath() const {\n\treturn path;\n}\n\nResource::Resource(const std::string& path) {\n\tthis->name = path;\n\tthis->path = path;\n}\n\nResource::Resource(const std::string& name, const std::string& path) {\n\tthis->name = name;\n\tthis->path = path;\n}"
  },
  {
    "path": "util/resource/resource.h",
    "content": "#pragma once\n\n#include <string>\n\nclass ResourceManager;\n\n#pragma region ResourceAllocator\n\n//! ResourceAllocator\ntemplate<typename T>\nclass ResourceAllocator {\n\tfriend ResourceManager;\n\t\nprotected:\n\tResourceAllocator() {};\n\npublic:\n\tvirtual T* load(const std::string& name, const std::string& path) = 0;\n};\n\n#pragma endregion\n\n#pragma region Resource\n\n//! Resource\nenum class ResourceType {\n\tNone = 0,\n\tMesh,\n\tFont,\n\tTexture,\n\tShader,\n\tOBJ\n};\n\nclass Resource {\n\tfriend ResourceManager;\n\nprotected:\n\tstd::string path;\n\tstd::string name;\n\n\tResource(const std::string& path);\n\tResource(const std::string& name, const std::string& path);\n\npublic:\n\tvirtual ResourceType getType() const = 0;\n\tvirtual std::string getTypeName() const = 0;\n\tvirtual void close() = 0;\n\n\tstd::string getName() const;\n\tstd::string getPath() const;\n\n\tvoid setName(const std::string& name);\n\tvoid setPath(const std::string& path);\n\n\ttemplate<typename T>\n\tstatic ResourceAllocator<T> getAllocator() {\n\t\treturn T::getAllocator();\n\t}\n};\n\n#define DEFINE_RESOURCE(type, path) \\\n\tinline static std::string getDefaultPath() { return path; } \\\n\tinline static ResourceType getStaticType() { return ResourceType::type; } \\\n\tinline static std::string getStaticTypeName() { return #type; } \\\n\tinline virtual std::string getTypeName() const override { return getStaticTypeName(); } \\\n\tinline virtual ResourceType getType() const override { return getStaticType(); }\n\n#pragma endregion"
  },
  {
    "path": "util/resource/resourceDescriptor.h",
    "content": "#pragma once\n\n#include <string>\n\n#ifdef _MSC_VER\nstruct ResourceDescriptor {\n\tconst int id;\n\tconst std::string type;\n};\n#else\n// ResourceDescriptors for reading from files\nstruct ResourceDescriptor {\n\tconst char* fileName;\n\tconst std::string type;\n};\n#endif"
  },
  {
    "path": "util/resource/resourceLoader.cpp",
    "content": "#include \"resourceLoader.h\"\n\n#include \"resourceDescriptor.h\"\n\n#include \"../log.h\"\n\n#ifdef _WIN32\n\n#include <windows.h>\n\nclass ResourceLoader {\npublic:\n\tstruct Parameters {\n\t\tstd::size_t size = 0;\n\t\tvoid* pointer = nullptr;\n\t};\n\nprivate:\n\tHRSRC hResource = nullptr;\n\tHGLOBAL hMemory = nullptr;\n\n\tParameters parameters;\n\npublic:\n\tResourceLoader(int id, const std::string& type) {\n\t\thResource = FindResource(nullptr, MAKEINTRESOURCEA(id), type.c_str());\n\t\thMemory = LoadResource(nullptr, hResource);\n\n\t\tparameters.size = SizeofResource(nullptr, hResource);\n\t\tparameters.pointer = LockResource(hMemory);\n\t}\n\n\tstd::string getResourceString() const {\n\t\tstd::string string;\n\t\tif (parameters.pointer != nullptr)\n\t\t\tstring = std::string(reinterpret_cast<char*>(parameters.pointer), parameters.size);\n\t\treturn string;\n\t}\n};\n\nstd::string getResourceAsString(const ResourceDescriptor* list, int id) {\n\tResourceDescriptor resource = list[id];\n\tResourceLoader manager(resource.id, resource.type);\n\treturn manager.getResourceString();\n}\n#else\n\n#include <string>\n#include <fstream>\n#include <streambuf>\n\nstd::string getResourceAsString(const ResourceDescriptor* list, int id) {\n\tconst ResourceDescriptor& resource = list[id];\n\tstd::ifstream file;\n\tfile.open(resource.fileName, std::ios::in);\n\tif(!file) {\n\t\tLog::error(\"Could not open %s\", resource.fileName);\n\t\tthrow std::runtime_error(\"Could not open file!\");\n\t}\n\treturn std::string(std::istreambuf_iterator<char>(file),\n\t\t\t\t\t   std::istreambuf_iterator<char>());\n}\n\n#endif\n\n"
  },
  {
    "path": "util/resource/resourceLoader.h",
    "content": "#pragma once\n\n#include <string>\n\nstruct ResourceDescriptor;\n\nstd::string getResourceAsString(const ResourceDescriptor* list, int id);\n"
  },
  {
    "path": "util/resource/resourceManager.cpp",
    "content": "#include \"resourceManager.h\"\n\nstd::unordered_map<ResourceType, Resource*> ResourceManager::defaultResources = {};\nstd::unordered_map<std::string, ResourceManager::CountedResource> ResourceManager::resources = {};\n\nResourceManager::ResourceManager() {\n\n}\n\nResourceManager::~ResourceManager() {\n\tResourceManager::close();\n}"
  },
  {
    "path": "util/resource/resourceManager.h",
    "content": "#pragma once\n\n#include \"../log.h\"\n\n#include <typeinfo>\n#include <unordered_map>\n#include <map>\n#include <vector>\n\n#include \"resource.h\"\n\nclass ResourceManager {\n\tfriend Resource;\n\nprivate:\n\tstruct CountedResource {\n\t\tResource* value;\n\t\tint count;\n\t};\n\n\tstatic std::unordered_map<ResourceType, Resource*> defaultResources;\n\tstatic std::unordered_map<std::string, CountedResource> resources;\n\n\tstatic void onResourceNameChange(Resource* changedResource, const std::string& newName) {\n\t\tauto iterator = ResourceManager::resources.find(changedResource->getName());\n\n\t\tif (iterator == ResourceManager::resources.end()) {\n\t\t\tLog::error(\"The changed resource is not found (%s)\", changedResource->getName().c_str());\n\t\t\treturn;\n\t\t} else {\n\t\t\tif (ResourceManager::resources.find(newName) != ResourceManager::resources.end()) {\n\t\t\t\tLog::error(\"Resource name has already been taken (%s)\", newName.c_str());\n\t\t\t\treturn;\n\t\t\t} else {\n\t\t\t\tCountedResource countedResource = iterator->second;\n\t\t\t\tcountedResource.value->name = newName;\n\t\t\t\tResourceManager::resources.emplace(newName, countedResource);\n\t\t\t\tResourceManager::resources.erase(iterator);\n\t\t\t}\n\t\t}\n\t}\n\n\tstatic void onResourcePathChange(Resource* changedResource, const std::string& newPath) {\n\t\tauto iterator = ResourceManager::resources.find(changedResource->getName());\n\n\t\tif (iterator == ResourceManager::resources.end()) {\n\t\t\tLog::error(\"The changed resource is not found (%s)\", changedResource->getName().c_str());\n\t\t\treturn;\n\t\t} else {\n\t\t\tauto& resource = iterator->second.value;\n\n\t\t\tif (resource->getName() == resource->getPath()) {\n\t\t\t\tonResourceNameChange(changedResource, newPath);\t\n\t\t\t} else {\n\t\t\t\t//? Load new resource\n\t\t\t}\n\n\t\t\tresource->path = newPath;\n\t\t}\n\t}\n\n\tResourceManager();\n\t~ResourceManager();\n\npublic:\n\ttemplate<typename T>\n\tstatic T* getDefaultResource() {\n\t\t//Log::subject(\"DEFAULT\");\n\t\t//Log::debug(\"Getting default resource: (%s)\", T::getStaticTypeName().c_str());\n\t\tauto iterator = ResourceManager::defaultResources.find(T::getStaticType());\n\n\t\tif (iterator != ResourceManager::defaultResources.end()) {\n\t\t\t//Log::debug(\"Found default resource: (%s)\", T::getStaticTypeName().c_str());\n\t\t\treturn static_cast<T*>(iterator->second);\n\t\t} else {\n\t\t\t//Log::debug(\"Default resource not found: (%s), trying to load default resource\", T::getStaticTypeName().c_str());\n\t\t\tResource* defaultResource = ResourceManager::add<T>(\"default_\" + T::getStaticTypeName(), T::getDefaultPath());\n\n\t\t\tif (defaultResource) {\n\t\t\t\t//Log::debug(\"Loaded default resource; (%s)\", T::getStaticTypeName().c_str());\n\t\t\t\tResourceManager::defaultResources[T::getStaticType()] = defaultResource;\n\t\t\t\treturn static_cast<T*>(defaultResource);\n\t\t\t} else {\n\t\t\t\t//Log::debug(\"Default resource not loaded: (%s)\", T::getStaticTypeName().c_str());\n\t\t\t\treturn nullptr;\n\t\t\t}\n\t\t}\n\t}\n\n\ttemplate<typename T, typename = std::enable_if<std::is_base_of<Resource, T>::value>>\n\tstatic T* get(const std::string& name) {\n\t\t//Log::subject s(\"GET\");\n\t\t//Log::debug(\"Getting resource: (%s)\", name.c_str());\n\n\t\tauto iterator = ResourceManager::resources.find(name);\n\n\t\tif (iterator != ResourceManager::resources.end()) {\n\t\t\t//Log::debug(\"Found resource: (%s)\", name.c_str());\n\n\t\t\treturn static_cast<T*>(iterator->second.value);\n\t\t} else {\n\t\t\t//Log::warn(\"Resource not loaded: (%s), using default resource\", name.c_str());\n\t\t\treturn ResourceManager::getDefaultResource<T>();\n\t\t}\n\t}\n\n\tstatic void add(Resource* resource) {\n\t\tif (resource == nullptr)\n\t\t\treturn;\n\n\t\tauto iterator = ResourceManager::resources.find(resource->name);\n\n\t\tif (iterator != ResourceManager::resources.end()) {\n\t\t\tauto& resource = (*iterator).second;\n\t\t\tresource.count++;\n\t\t} else {\n\t\t\tCountedResource countedResource = { resource, 1 };\n\t\t\tResourceManager::resources.emplace(resource->name, countedResource);\n\t\t}\n\t}\n\n\ttemplate<typename T, typename = std::enable_if_t<std::is_base_of<Resource, T>::value>>\n\tstatic T* add(const std::string& name, const std::string& path) {\n\t\tLog::subject s(\"ADD\");\n\t\t//Log::debug(\"Adding resource: (%s, %s)\", name.c_str(), path.c_str());\n\n\t\tauto iterator = ResourceManager::resources.find(name);\n\n\t\tif (iterator != ResourceManager::resources.end()) {\n\t\t\t//Log::debug(\"Found resource: (%s, %s)\", name.c_str(), path.c_str());\n\t\t\tauto& resource = (*iterator).second;\n\t\t\tresource.count++; \n\t\t\treturn static_cast<T*>(resource.value);\n\t\t} else {\n\t\t\t//Log::debug(\"Resource not found: (%s, %s), trying to load resource\", name.c_str(), path.c_str());\n\n\t\t\tT* resource = T::getAllocator().load(name, path);\n\n\t\t\tif (resource == nullptr) {\n\t\t\t\tLog::warn(\"Resource not loaded: (%s, %s)\", name.c_str(), path.c_str());\n\t\t\t\treturn nullptr;\n\t\t\t} else {\n\t\t\t\t//Log::debug(\"Loaded resource: (%s, %s)\", name.c_str(), path.c_str());\n\n\t\t\t\tCountedResource countedResource = { resource, 1 };\n\t\t\t\tResourceManager::resources.emplace(name, countedResource);\n\n\t\t\t\treturn resource;\n\t\t\t}\n\t\t}\n\t}\n\n\ttemplate<typename T, typename = std::enable_if<std::is_base_of<Resource, T>::value>>\n\tstatic T* add(const std::string& path) {\n\t\treturn add<T>(path, path);\n\t}\n\n\tstatic void close() {\n\t\tfor (auto iterator : resources) {\n\t\t\titerator.second.value->close();\n\t\t}\n\n\t\tresources.clear();\n\t\tdefaultResources.clear();\n\t}\n\n\tstatic bool exists(const std::string& name) {\n\t\tauto iterator = ResourceManager::resources.find(name);\n\t\treturn iterator != ResourceManager::resources.end();\n\t}\n\n\ttemplate<typename T, typename = std::enable_if<std::is_base_of<Resource, T>::value>>\n\tstatic std::vector<T*> getResourcesOfClass() {\n\t\tstd::vector<T*> list;\n\n\t\tfor (auto iterator : ResourceManager::resources) {\n\t\t\tif (typeid(T) == typeid(iterator.second.value))\n\t\t\t\tlist.push_back(static_cast<T*>(iterator.second.value));\n\t\t}\n\n\t\treturn list;\n\t}\n\n\tstatic std::vector<Resource*> getResourcesOfType(ResourceType type) {\n\t\tstd::vector<Resource*> list;\n\t\t\n\t\tfor (auto iterator : ResourceManager::resources) {\n\t\t\tif (iterator.second.value->getType() == type)\n\t\t\t\tlist.push_back(iterator.second.value);\n\t\t}\n\n\t\treturn list;\n\t}\n\n\tstatic std::vector<Resource*> getResources() {\n\t\tstd::vector<Resource*> list;\n\n\t\tfor (auto iterator : ResourceManager::resources) {\n\t\t\tlist.push_back(iterator.second.value);\n\t\t}\n\n\t\treturn list;\n\t}\n\n\tstatic std::map<std::string, std::vector<Resource*>> getResourceMap() {\n\t\tstd::map<std::string, std::vector<Resource*>> map;\n\n\t\tfor (auto iterator : ResourceManager::resources) {\n\t\t\tResource* resource = iterator.second.value;\n\n\t\t\tif (map.find(resource->getTypeName()) == map.end())\n\t\t\t\tmap[resource->getTypeName()] = std::vector<Resource*>();\n\n\t\t\tmap[resource->getTypeName()].push_back(resource);\n\t\t}\n\n\t\treturn map;\n\t}\n};"
  },
  {
    "path": "util/stringUtil.cpp",
    "content": "#include \"stringUtil.h\"\n\n#include <algorithm>\n#include <vector>\n#include <string>\n\nnamespace Util {\n\nstatic std::string demangle_win(const std::string& fullName) {\n\tstd::string name = fullName;\n\n\tstd::size_t angleIndex = name.find_first_of('<');\n\tif (angleIndex != std::string::npos)\n\t\tname = name.substr(0, angleIndex);\n\n\tstd::size_t colonIndex = name.find_last_of(':');\n\tif (colonIndex != std::string::npos)\n\t\tname = name.substr(colonIndex + 1);\n\n\treturn name;\n}\n\n#ifdef __GNUG__\n\n\t#include <cstdlib>\n\t#include <memory>\n\t#include <cxxabi.h>\n\n\tstd::string demangle(const std::string& fullName) {\n\t\tint status = 0;\n\n\t\tstd::unique_ptr<char, void(*)(void*)> demangled {\n\t\t\tabi::__cxa_demangle(fullName.c_str(), NULL, NULL, &status),\n\t\t\tstd::free\n\t\t};\n\n\t\tif (status != 0)\n\t\t\treturn fullName;\n\n\t\tstd::string result = demangled.get();\n\t\tstd::string name = demangle_win(result);\n\n\t\treturn name;\n\t}\n\n#elif _MSC_VER\n\n\tstd::string demangle(const std::string& fullName) {\n\t\treturn demangle_win(fullName);\n\t}\n\n#else\n\n\tstd::string demangle(const std::string& fullName) {\n\t\treturn fullName;\n\t}\n\n#endif\n\nstd::string decamel(const std::string& string) {\n\tstd::string result = string;\n\n\tif (result.empty())\n\t\treturn result;\n\n\tfor (std::size_t index = string.size() - 1; index >= 1; index--)\n\t\tif (isupper(string[index]))\n\t\t\tresult.insert(index, \" \");\n\n\treturn result;\n}\n\nstd::vector<std::string> split(const std::string& string, char splitter) {\n\tstd::vector<std::string> elements;\n\tsize_t length = string.size();\n\tsize_t start = 0;\n\n\tfor (size_t i = 0; i < length; i++) {\n\t\tif (string[i] == splitter) {\n\t\t\telements.push_back(string.substr(start, i - start));\n\t\t\tstart = i + 1;\n\t\t}\n\t}\n\n\tif (start < length)\n\t\telements.push_back(string.substr(start, length - start));\n\n\treturn elements;\n}\n\nstd::vector<std::string_view> split_view(const std::string_view& string, char splitter) {\n\tstd::vector<std::string_view> elements;\n\tsize_t length = string.size();\n\tsize_t start = 0;\n\n\tfor (size_t i = 0; i < length; i++) {\n\t\tif (string[i] == splitter) {\n\t\t\telements.push_back(string.substr(start, i - start));\n\t\t\tstart = i + 1;\n\t\t}\n\t}\n\n\tif (start < length)\n\t\telements.push_back(string.substr(start, length - start));\n\n\treturn elements;\n}\n\nbool startsWith(const std::string& string, const std::string& prefix) {\n\tsize_t l1 = string.length();\n\tsize_t l2 = prefix.length();\n\n\tif (l2 > l1)\n\t\treturn false;\n\n\tfor (size_t i = 0; i < l2; i++) {\n\t\tif (string[i] != prefix[i])\n\t\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nbool endsWith(const std::string& string, const std::string& suffix) {\n\tsize_t l1 = string.length();\n\tsize_t l2 = suffix.length();\n\n\tif (l2 > l1)\n\t\treturn false;\n\n\tfor (size_t i = 1; i <= l2; i++) {\n\t\tif (string[l1 - i] != suffix[l2 - i])\n\t\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nstd::string until(const std::string& string, char end) {\n\tsize_t l = string.length();\n\tfor (size_t i = 0; i < l; i++) {\n\t\tif (string.at(i) == end)\n\t\t\treturn string.substr(0, i);\n\t}\n\n\treturn string;\n}\n\nstd::string ltrim(const std::string& string) {\n\tstd::string result = string;\n\tauto iterator = std::find_if(result.begin(),\n\t                             result.end(),\n\t                             [](int ch) {\n\t\t                             return ch != ' ' && ch != '\\t' && ch != '\\n' && ch != '\\r';\n\t                             });\n\tresult.erase(result.begin(), iterator);\n\treturn result;\n}\n\nstd::string rtrim(const std::string& string) {\n\tstd::string result = string;\n\tauto iterator = std::find_if(result.rbegin(),\n\t                             result.rend(),\n\t                             [](int ch) {\n\t\t                             return ch != ' ' && ch != '\\t' && ch != '\\n' && ch != '\\r';\n\t                             });\n\tresult.erase(iterator.base(), result.end());\n\treturn result;\n}\n\nstd::string trim(const std::string& string) {\n\treturn ltrim(rtrim(string));\n}\n\n};\n"
  },
  {
    "path": "util/stringUtil.h",
    "content": "#pragma once\n\n#include <vector>\n#include <string>\n#include <memory>\n#include <stdexcept>\n\nnamespace Util {\n\n\tstd::string demangle(const std::string& fullName);\n\tstd::string decamel(const std::string& string);\n\n\ttemplate<typename T>\n\tstd::string typeName() {\n\t\treturn typeid(T).name();\n\t}\n\n\tstd::vector<std::string> split(const std::string& string, char splitter);\n\tstd::vector<std::string_view> split_view(const std::string_view& string, char splitter);\n\tbool startsWith(const std::string& string, const std::string& prefix);\n\tbool endsWith(const std::string& string, const std::string& suffix);\n\n\tstd::string until(const std::string& string, char end);\n\n\tstd::string ltrim(const std::string& string);\n\tstd::string rtrim(const std::string& string);\n\tstd::string trim(const std::string& string);\n\n\ttemplate<typename... Args>\n\tstd::string format(const std::string& format, Args... args) {\n\t\tint size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\\0'\n\t\tif (size_s <= 0) \n\t\t\tthrow std::runtime_error(\"Error during formatting.\");\n\t\t\n\t\tauto size = static_cast<size_t>(size_s);\n\t\tauto buffer = std::make_unique<char[]>(size);\n\t\tstd::snprintf(buffer.get(), size, format.c_str(), args ...);\n\n\t\treturn std::string(buffer.get(), buffer.get() + size - 1); // We don't want the '\\0' inside\n\t}\n\n};"
  },
  {
    "path": "util/systemVariables.cpp",
    "content": "#include \"systemVariables.h\"\n\n#include <unordered_map>\n#include <stdexcept>\n\nstatic std::unordered_map<std::string, int> variables;\n\nint SystemVariables::get(const std::string& key) {\n\tconst auto iterator = variables.find(key);\n\n\tif (iterator == variables.end())\n\t\tthrow std::runtime_error(\"System variable \\\"\" + key + \"\\\" not found\");\n\n\treturn iterator->second;\n}\n\nvoid SystemVariables::set(const std::string& key, int value) {\n\tvariables[key] = value;\n}"
  },
  {
    "path": "util/systemVariables.h",
    "content": "#pragma once\n\n#include <string>\n\nstruct SystemVariables {\npublic:\n\tstatic int get(const std::string& key);\n\tstatic void set(const std::string& key, int value);\n};\n\n"
  },
  {
    "path": "util/terminalColor.cpp",
    "content": "#include \"terminalColor.h\"\n\nvoid setColor(TerminalColor foreground) {\n\tsetColor(foreground, TerminalColor::BLACK);\n}\n\nvoid setColor(TerminalColorPair color) {\n\tsetColor(color.foreground, color.background);\n}\n\n#ifdef _MSC_VER\n\n#include <Windows.h>\nstatic HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);\nvoid setColor(TerminalColor foreground, TerminalColor background) {\n\tSetConsoleTextAttribute(console, int(foreground) | (int(background) << 4));\n}\n\n#else\n\n#include <iostream>\nstatic char cvtWinColorToUnixColor(int winColor){\n\tswitch(winColor){\n\t\tcase 0: return '0';   // BLACK\n\t\tcase 1: return '4';   // BLUE\n\t\tcase 2: return '2';   // GREEN\n\t\tcase 3: return '6';   // AQUA\n\t\tcase 4: return '1';   // RED\n\t\tcase 5: return '5';   // MAGENTA\n\t\tcase 6: return '3';   // YELLOW\n\t\tcase 7: return '7';   // WHITE\n\t\tdefault: return '7';  // WHITE\n\t}\n}\nvoid setColor(TerminalColor foreground, TerminalColor background) {\n\tstd::cout << \"\\033[0;\";\n\tif(int(foreground) & 0b00001000){ // strong\n\t\tstd::cout << \"1;\";\n\t}\n\tif(background != TerminalColor::BLACK) {\n\t\tstd::cout << '4' << cvtWinColorToUnixColor(int(background) & 0b00000111) << ';';\n\t}\n\tstd::cout << '3' << cvtWinColorToUnixColor(int(foreground) & 0b00000111);\n\n\tstd::cout << 'm';\n}\n\n#endif\n\n\n"
  },
  {
    "path": "util/terminalColor.h",
    "content": "#pragma once\n\nenum class TerminalColor {\n\tBLACK = 0,\n\tDARK_BLUE = 1,\n\tDARK_GREEN = 2,\n\tAQUA = 3,\n\tDARK_RED = 4,\n\tPURPLE = 5,\n\tDARK_YELLOW = 6,\n\tLIGHT_GRAY = 7,\n\tGRAY = 8,\n\tBLUE = 9,\n\tGREEN = 10,\n\tCYAN = 11,\n\tRED = 12,\n\tMAGENTA = 13,\n\tYELLOW = 14,\n\tWHITE = 15,\n};\n\nstruct TerminalColorPair {\n\tTerminalColor foreground;\n\tTerminalColor background;\n};\n\nvoid setColor(TerminalColor foreground);\nvoid setColor(TerminalColor foreground, TerminalColor background);\nvoid setColor(TerminalColorPair color);\n"
  },
  {
    "path": "util/tracker.h",
    "content": "#pragma once\n\ntemplate<typename T>\nstruct Tracker {\npublic:\n\tstatic int created;\n\tstatic int alive;\n\n\tTracker() {\n\t\tcreated++;\n\t\talive++;\n\t}\n\n\tTracker(const Tracker&) {\n\t\tcreated++;\n\t\talive++;\n\t}\n\nprotected:\n\t~Tracker() {\n\t\talive--;\n\t}\n};\n\ntemplate<typename T> \nint Tracker<T>::created(0);\n\ntemplate<typename T>\nint Tracker<T>::alive(0);"
  },
  {
    "path": "util/typetraits.h",
    "content": "#pragma once\n\n#include <type_traits>\n\n/**\n * Determine if the given type is a templated type\n */\n\ntemplate<typename>\nstruct is_template : std::false_type {};\n\ntemplate<template<typename...> typename Type, typename... Arguments>\nstruct is_template<Type<Arguments...>> : std::true_type {};\n\n\n/**\n * Determine if the given types are unique\n */\n\ntemplate<typename...>\ninline constexpr auto unique_types = std::true_type {};\n\ntemplate<typename T, typename... Rest>\ninline constexpr auto unique_types<T, Rest...> = std::bool_constant<(!std::is_same_v<T, Rest> && ...) && unique_types<Rest...>> {};\n\n/**\n * Determine if the first type is part of the parameter pack\n */\ntemplate<typename T, typename... Ts>\ninline constexpr auto is_part_of = std::disjunction_v<std::is_same<T, Ts>...>;"
  },
  {
    "path": "util/util.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <VCProjectVersion>15.0</VCProjectVersion>\n    <ProjectGuid>{60F3448D-6447-47CD-BF64-8762F8DB9361}</ProjectGuid>\n    <RootNamespace>util</RootNamespace>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v142</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup />\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n      <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <Link>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <ConformanceMode>true</ConformanceMode>\n      <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>\n      <PreprocessorDefinitions>_MBCS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n    </ClCompile>\n    <Link>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"log.cpp\" />\n    <ClCompile Include=\"fileUtils.cpp\" />\n    <ClCompile Include=\"properties.cpp\" />\n    <ClCompile Include=\"resource\\resource.cpp\" />\n    <ClCompile Include=\"resource\\resourceLoader.cpp\" />\n    <ClCompile Include=\"resource\\resourceManager.cpp\" />\n    <ClCompile Include=\"stringUtil.cpp\" />\n    <ClCompile Include=\"systemVariables.cpp\" />\n    <ClCompile Include=\"terminalColor.cpp\" />\n    <ClCompile Include=\"valueCycle.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"cmdParser.h\" />\n    <ClInclude Include=\"iteratorUtils.h\" />\n    <ClInclude Include=\"log.h\" />\n    <ClInclude Include=\"fileUtils.h\" />\n    <ClInclude Include=\"math\\mat3.h\" />\n    <ClInclude Include=\"math\\mat4.h\" />\n    <ClInclude Include=\"math\\rot3.h\" />\n    <ClInclude Include=\"math\\vec3.h\" />\n    <ClInclude Include=\"parseCPUIDArgs.h\" />\n    <ClInclude Include=\"properties.h\" />\n    <ClInclude Include=\"resource\\resource.h\" />\n    <ClInclude Include=\"resource\\resourceLoader.h\" />\n    <ClInclude Include=\"resource\\resourceManager.h\" />\n    <ClInclude Include=\"stringUtil.h\" />\n    <ClInclude Include=\"systemVariables.h\" />\n    <ClInclude Include=\"terminalColor.h\" />\n    <ClInclude Include=\"tracker.h\" />\n    <ClInclude Include=\"typetraits.h\" />\n    <ClInclude Include=\"valueCycle.h\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "util/valueCycle.cpp",
    "content": "#include \"valueCycle.h\"\n\nnamespace Util {\n\nfloat linear(float t) {\n\treturn t;\n}\n\nfloat smoothstep(float t) {\n\treturn t * t * (3.0f - 2.0f * t);\n}\n\nfloat easeInQuad(float t) {\n\treturn t * t;\n}\n\nfloat easeOutQuad(float t) {\n\treturn t * (2.0f - t);\n}\n\nfloat easeInOutQuad(float t) {\n\treturn (t < 0.5f) ? 2.0f * t * t : -1.0f + (4.0f - 2.0f * t) * t;\n}\n\nfloat easeInCubic(float t) {\n\treturn t * t * t;\n}\n\nfloat easeOutCubic(float t) {\n\treturn (--t) * t * t + 1;\n}\n\nfloat easeInOuCubic(float t) {\n\treturn (t < 0.5f) ? 4.0f * t * t * t : (t - 1.0f) * (2.0f * t - 2.0f) * (2.0f * t - 2.0f) + 1.0f;\n}\n\n};"
  },
  {
    "path": "util/valueCycle.h",
    "content": "#pragma once\n\n#include <map>\n#include <vector>\n#include <initializer_list>\n\nnamespace Util {\n\nfloat linear(float t);\nfloat smoothstep(float t);\nfloat easeInQuad(float t);\nfloat easeOutQuad(float t);\nfloat easeInOutQuad(float t);\nfloat easeInCubic(float t);\nfloat easeOutCubic(float t);\nfloat easeInOuCubic(float t);\n\ntemplate<typename T, float (*interpolate)(float)>\nstruct ValueCycle {\nprivate:\n\tstd::map<float, T> keyframes;\n\npublic:\n\tValueCycle() {}\n\tValueCycle(std::initializer_list<std::pair<float, T>> keyframes) : keyframes(keyframes) {}\n\n\t/*\n\t\tAdd a keyframe at the given time\n\t*/\n\tvoid addKeyframe(float time, const T& frame) {\n\t\tkeyframes[time] = frame;\n\t}\n\n\t/*\n\t\tDelete the keyframe at the given time\n\t*/\n\tvoid deleteKeyframe(float time) {\n\t\tkeyframes.erase(time);\n\t}\n\n\t/*\n\t\tSample the keyframe, time should be between 0.0f and 1.0f\n\t*/\n\tT sample(float time) {\n\t\tstd::pair<float, T> previous;\n\t\tstd::pair<float, T> next;\n\n\t\tfor (const auto& iterator : keyframes) {\n\t\t\tif (iterator.first > time) {\n\t\t\t\tnext = iterator;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tprevious = iterator;\n\t\t}\n\n\t\tfloat blend = interpolate((time - previous.first) / (next.first - previous.first));\n\t\treturn (1.0f - blend) * previous.second + blend * next.second;\n\t}\n\n\t/*\n\t\tGet all timestamps\n\t*/\n\tstd::vector<float> getTimestamps() {\n\t\tstd::vector<float> timestamps;\n\t\ttimestamps.reserve(keyframes.size());\n\n\t\tfor (const auto& timestamp : keyframes)\n\t\t\ttimestamps.push_back(timestamp.first);\n\t\t\n\t\treturn timestamps;\n\t}\n};\n\n}"
  },
  {
    "path": "world.grammar",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ufwb version=\"1.17\">\n    <grammar name=\"Physics3D World File Format\" start=\"id:218\" fileextension=\"world\">\n        <structure name=\"Physics3D world\" id=\"218\" length=\"0\" alignment=\"0\" repeatmin=\"0\" repeatmax=\"-1\" encoding=\"ISO_8859-1:1987\" endian=\"little\" signed=\"yes\">\n            <structure name=\"fileHeader\" id=\"219\" encoding=\"ISO_8859-1:1987\" endian=\"little\" signed=\"yes\">\n                <number name=\"version\" id=\"220\" fillcolor=\"00FF00\" type=\"integer\" length=\"4\"/>\n                <number name=\"shapeClassCount\" id=\"221\" fillcolor=\"FF0000\" type=\"integer\" length=\"4\"/>\n                <structure name=\"ShapeClass\" id=\"222\" repeat=\"id:221\" repeatmin=\"0\" repeatmax=\"-1\" endian=\"little\" signed=\"yes\" order=\"variable\">\n                    <structref name=\"&lt;ConvexPolyhedron&gt;\" id=\"224\" structure=\"id:223\"/>\n                </structure>\n            </structure>\n            <number name=\"worldAge\" id=\"227\" fillcolor=\"11FF00\" type=\"integer\" length=\"8\"/>\n            <number name=\"layerCount\" id=\"228\" fillcolor=\"FF0000\" type=\"integer\" length=\"4\"/>\n            <binary name=\"layerMask\" id=\"229\" length=\"layerCount * (layerCount + 1) / 2\"/>\n            <structure name=\"ColissionLayer\" id=\"230\" repeat=\"id:228\" repeatmin=\"0\" repeatmax=\"-1\">\n                <structref name=\"terrainLayer\" id=\"232\" structure=\"id:231\"/>\n            </structure>\n            <number name=\"physicalCount\" id=\"234\" fillcolor=\"FF0000\" type=\"integer\" length=\"4\"/>\n            <structure name=\"MotorizedPhysical\" id=\"235\" repeat=\"id:234\" repeatmin=\"0\" repeatmax=\"-1\">\n                <structref name=\"motionOfCOM\" id=\"237\" structure=\"id:236\"/>\n                <structref name=\"cframe\" id=\"239\" structure=\"id:238\"/>\n                <structref name=\"underlyingPhysical\" id=\"241\" structure=\"id:240\"/>\n            </structure>\n            <number name=\"constraintGroups\" id=\"243\" fillcolor=\"FF0000\" type=\"integer\" length=\"4\"/>\n            <structure name=\"ConstraintGroup\" id=\"244\" repeat=\"id:243\" repeatmin=\"0\" repeatmax=\"-1\">\n                <number name=\"constraintsInGroup\" id=\"245\" fillcolor=\"FF0000\" type=\"integer\" length=\"4\"/>\n                <structure name=\"Constraint\" id=\"246\" repeatmin=\"0\" repeatmax=\"-1\">\n                    <number name=\"physicalIndex1\" id=\"247\" fillcolor=\"FFFF00\" type=\"integer\" length=\"4\"/>\n                    <number name=\"physicalIndex2\" id=\"248\" fillcolor=\"FFFF00\" type=\"integer\" length=\"4\"/>\n                    <structure name=\"ConstraintData\" id=\"249\" order=\"variable\">\n                        <structref name=\"&lt;BallConstraint&gt;\" id=\"251\" repeatmin=\"0\" structure=\"id:250\"/>\n                        <structref name=\"&lt;HingeConstraint&gt;\" id=\"432\" repeatmin=\"0\" structure=\"id:419\"/>\n                        <structref name=\"&lt;BarConstraint&gt;\" id=\"433\" repeatmin=\"0\" structure=\"id:426\"/>\n                    </structure>\n                </structure>\n            </structure>\n            <number name=\"externalForceCount\" id=\"255\" fillcolor=\"FF0000\" type=\"integer\" length=\"4\"/>\n            <structure name=\"ExternalForce\" id=\"256\" repeat=\"id:255\" repeatmin=\"0\" repeatmax=\"-1\" fillcolor=\"FF9500\" order=\"variable\">\n                <structref name=\"&lt;GravityForce&gt;\" id=\"258\" repeatmin=\"0\" structure=\"id:257\"/>\n            </structure>\n        </structure>\n        <structure name=\"Layer\" id=\"231\" repeat=\"id:228\" repeatmin=\"0\" repeatmax=\"-1\" encoding=\"ISO_8859-1:1987\" endian=\"little\" signed=\"yes\">\n            <number name=\"partsInLayer\" id=\"261\" fillcolor=\"FF0000\" type=\"integer\" length=\"4\"/>\n            <structure name=\"NonPhysicalPart\" id=\"262\" repeat=\"id:261\" repeatmin=\"0\" repeatmax=\"-1\">\n                <structref name=\"cframe\" id=\"263\" structure=\"id:238\"/>\n                <structref name=\"part\" id=\"265\" structure=\"id:264\"/>\n            </structure>\n        </structure>\n        <structure name=\"Vec3\" id=\"268\" alignment=\"0\" encoding=\"ISO_8859-1:1987\" endian=\"little\" signed=\"yes\" fillcolor=\"00FFE2\">\n            <number name=\"x\" id=\"269\" fillcolor=\"55FFFF\" type=\"float\" length=\"8\"/>\n            <number name=\"y\" id=\"270\" fillcolor=\"55FFFF\" type=\"float\" length=\"8\"/>\n            <number name=\"z\" id=\"271\" fillcolor=\"55FFFF\" type=\"float\" length=\"8\"/>\n        </structure>\n        <structure name=\"CFrame\" id=\"273\" encoding=\"ISO_8859-1:1987\" endian=\"little\" signed=\"yes\">\n            <structref name=\"position\" id=\"274\" structure=\"id:268\"/>\n            <structref name=\"rotation\" id=\"276\" structure=\"id:275\"/>\n        </structure>\n        <structure name=\"GlobalCFrame\" id=\"238\" encoding=\"ISO_8859-1:1987\" endian=\"little\" signed=\"yes\">\n            <structref name=\"position\" id=\"279\" structure=\"id:278\"/>\n            <structref name=\"rotation\" id=\"280\" structure=\"id:275\"/>\n        </structure>\n        <structure name=\"Position\" id=\"278\" encoding=\"ISO_8859-1:1987\" endian=\"little\" signed=\"yes\">\n            <number name=\"x\" id=\"282\" fillcolor=\"0000FF\" type=\"integer\" length=\"8\"/>\n            <number name=\"y\" id=\"283\" fillcolor=\"0000FF\" type=\"integer\" length=\"8\"/>\n            <number name=\"z\" id=\"284\" fillcolor=\"0000FF\" type=\"integer\" length=\"8\"/>\n        </structure>\n        <structure name=\"Rotation\" id=\"275\" encoding=\"ISO_8859-1:1987\" endian=\"little\" signed=\"yes\">\n            <number name=\"r00\" id=\"286\" fillcolor=\"55FFFF\" type=\"float\" length=\"8\"/>\n            <number name=\"r01\" id=\"287\" fillcolor=\"55FFFF\" type=\"float\" length=\"8\"/>\n            <number name=\"r02\" id=\"288\" fillcolor=\"55FFFF\" type=\"float\" length=\"8\"/>\n            <number name=\"r10\" id=\"289\" fillcolor=\"55FFFF\" type=\"float\" length=\"8\"/>\n            <number name=\"r11\" id=\"290\" fillcolor=\"55FFFF\" type=\"float\" length=\"8\"/>\n            <number name=\"r12\" id=\"291\" fillcolor=\"55FFFF\" type=\"float\" length=\"8\"/>\n            <number name=\"r20\" id=\"292\" fillcolor=\"55FFFF\" type=\"float\" length=\"8\"/>\n            <number name=\"r21\" id=\"293\" fillcolor=\"55FFFF\" type=\"float\" length=\"8\"/>\n            <number name=\"r22\" id=\"294\" fillcolor=\"55FFFF\" type=\"float\" length=\"8\"/>\n        </structure>\n        <structure name=\"Motion\" id=\"236\" encoding=\"ISO_8859-1:1987\" endian=\"little\" signed=\"yes\">\n            <structref name=\"velocity\" id=\"296\" structure=\"id:268\"/>\n            <structref name=\"acceleration\" id=\"297\" structure=\"id:268\"/>\n            <structref name=\"angularVelocity\" id=\"298\" structure=\"id:268\"/>\n            <structref name=\"angularAcceleration\" id=\"299\" structure=\"id:268\"/>\n        </structure>\n        <structure name=\"Physical\" id=\"240\" encoding=\"ISO_8859-1:1987\" endian=\"little\" signed=\"yes\">\n            <structure name=\"RigidBody\" id=\"301\">\n                <number name=\"layer\" id=\"302\" fillcolor=\"FFFF00\" type=\"integer\" length=\"4\"/>\n                <structref name=\"mainPart\" id=\"303\" structure=\"id:264\"/>\n                <number name=\"attachedPartCount\" id=\"304\" fillcolor=\"FF0000\" type=\"integer\" length=\"4\"/>\n                <structure name=\"AttachedPart\" id=\"305\" repeat=\"id:304\" repeatmin=\"0\" repeatmax=\"-1\">\n                    <structref name=\"attachment\" id=\"306\" structure=\"id:273\"/>\n                    <number name=\"layer\" id=\"307\" fillcolor=\"FFFF00\" type=\"integer\" length=\"4\"/>\n                    <structref name=\"part\" id=\"308\" structure=\"id:264\"/>\n                </structure>\n            </structure>\n            <number name=\"connectedPhysicalCount\" id=\"311\" fillcolor=\"FF0000\" type=\"integer\" length=\"4\"/>\n            <structure name=\"ConnectedPhysical\" id=\"312\" repeat=\"id:311\" repeatmin=\"0\" repeatmax=\"-1\">\n                <structure name=\"HardPhysicalConnection\" id=\"313\">\n                    <structref name=\"attachOnChild\" id=\"314\" structure=\"id:273\"/>\n                    <structref name=\"attachOnParent\" id=\"315\" structure=\"id:273\"/>\n                    <structure name=\"Constraint\" id=\"316\" order=\"variable\">\n                        <structref name=\"&lt;FixedConstraint&gt;\" id=\"318\" repeatmin=\"0\" structure=\"id:317\"/>\n                        <structref name=\"&lt;MotorConstraint&gt;\" id=\"320\" repeatmin=\"0\" structure=\"id:319\"/>\n                        <structref name=\"&lt;SinusoidalPistonConstraint&gt;\" id=\"322\" repeatmin=\"0\" structure=\"id:321\"/>\n                        <structref name=\"&lt;SinusoidalMotorConstraint&gt;\" id=\"324\" repeatmin=\"0\" structure=\"id:323\"/>\n                    </structure>\n                </structure>\n                <structref name=\"childPhys\" id=\"327\" structure=\"id:240\"/>\n            </structure>\n        </structure>\n        <structure name=\"Part\" id=\"264\" encoding=\"ISO_8859-1:1987\" endian=\"little\" signed=\"yes\">\n            <structure name=\"Shape\" id=\"330\" fillcolor=\"FFAA00\">\n                <number name=\"shapeClassID\" id=\"331\" fillcolor=\"FFFF00\" type=\"integer\" length=\"4\" minval=\"0\">\n                    <fixedvalues>\n                        <fixedvalue name=\"box\" value=\"18446744073709551615\"/>\n                        <fixedvalue name=\"sphere\" value=\"18446744073709551614\"/>\n                        <fixedvalue name=\"cylinder\" value=\"18446744073709551613\"/>\n                    </fixedvalues>\n                </number>\n                <number name=\"width\" id=\"332\" fillcolor=\"55FFFF\" type=\"float\" length=\"8\"/>\n                <number name=\"height\" id=\"333\" fillcolor=\"55FFFF\" type=\"float\" length=\"8\"/>\n                <number name=\"depth\" id=\"334\" fillcolor=\"55FFFF\" type=\"float\" length=\"8\"/>\n            </structure>\n            <structure name=\"PartProperties\" id=\"336\">\n                <number name=\"density\" id=\"337\" fillcolor=\"55FFFF\" type=\"float\" length=\"8\"/>\n                <number name=\"friction\" id=\"338\" fillcolor=\"55FFFF\" type=\"float\" length=\"8\"/>\n                <number name=\"bouncyness\" id=\"339\" fillcolor=\"55FFFF\" type=\"float\" length=\"8\"/>\n                <structref name=\"conveyorEffect\" id=\"340\" structure=\"id:268\"/>\n            </structure>\n            <structref name=\"applicationExtention\" id=\"343\" structure=\"id:342\"/>\n        </structure>\n        <structure name=\"PartExtention\" id=\"342\" encoding=\"ISO_8859-1:1987\" endian=\"little\" signed=\"yes\">\n            <structure name=\"Material\" id=\"345\">\n                <structure name=\"TextureIDs\" id=\"346\">\n                    <number name=\"albedo\" id=\"347\" fillcolor=\"AAAA7F\" type=\"integer\" length=\"4\"/>\n                    <number name=\"normal\" id=\"348\" fillcolor=\"AAAA7F\" type=\"integer\" length=\"4\"/>\n                    <number name=\"metalness\" id=\"349\" fillcolor=\"AAAA7F\" type=\"integer\" length=\"4\"/>\n                    <number name=\"roughness\" id=\"350\" fillcolor=\"AAAA7F\" type=\"integer\" length=\"4\"/>\n                    <number name=\"ao\" id=\"351\" fillcolor=\"AAAA7F\" type=\"integer\" length=\"4\"/>\n                    <number name=\"gloss\" id=\"352\" fillcolor=\"AAAA7F\" type=\"integer\" length=\"4\"/>\n                    <number name=\"specular\" id=\"353\" fillcolor=\"AAAA7F\" type=\"integer\" length=\"4\"/>\n                    <number name=\"displacement\" id=\"354\" fillcolor=\"AAAA7F\" type=\"integer\" length=\"4\"/>\n                </structure>\n                <structure name=\"Color\" id=\"356\">\n                    <number name=\"r\" id=\"357\" fillcolor=\"AAAA00\" type=\"float\" length=\"4\"/>\n                    <number name=\"g\" id=\"358\" fillcolor=\"AAAA00\" type=\"float\" length=\"4\"/>\n                    <number name=\"b\" id=\"359\" fillcolor=\"AAAA00\" type=\"float\" length=\"4\"/>\n                    <number name=\"a\" id=\"360\" fillcolor=\"AAAA00\" type=\"float\" length=\"4\"/>\n                </structure>\n                <number name=\"metalness\" id=\"362\" fillcolor=\"AAAA00\" type=\"float\" length=\"4\"/>\n                <number name=\"roughness\" id=\"363\" fillcolor=\"AAAA00\" type=\"float\" length=\"4\"/>\n                <number name=\"ao\" id=\"364\" fillcolor=\"AAAA00\" type=\"float\" length=\"4\"/>\n            </structure>\n            <string name=\"name\" id=\"366\" fillcolor=\"C1775E\" type=\"zero-terminated\"/>\n        </structure>\n        <structure name=\"ExternalForce\" id=\"368\" encoding=\"ISO_8859-1:1987\" endian=\"little\" signed=\"yes\">\n            <number name=\"forceType\" id=\"369\" fillcolor=\"FFAA00\" type=\"integer\" length=\"4\"/>\n        </structure>\n        <structure name=\"GravityForce\" id=\"257\" extends=\"id:368\">\n            <number name=\"forceType\" id=\"371\" type=\"integer\">\n                <fixedvalues>\n                    <fixedvalue name=\"gravity\" value=\"0\"/>\n                </fixedvalues>\n            </number>\n            <structref name=\"gravity\" id=\"372\" structure=\"id:268\"/>\n        </structure>\n        <structure name=\"ShapeClass\" id=\"374\" encoding=\"ISO_8859-1:1987\" endian=\"little\" signed=\"yes\">\n            <number name=\"classType\" id=\"375\" fillcolor=\"FFAA00\" type=\"integer\" length=\"4\"/>\n        </structure>\n        <structure name=\"ConvexPolyhedron\" id=\"223\" extends=\"id:374\">\n            <number name=\"classType\" id=\"377\" type=\"integer\">\n                <fixedvalues>\n                    <fixedvalue name=\"convexPolyhedron\" value=\"0\"/>\n                </fixedvalues>\n            </number>\n            <number name=\"vertexCount\" id=\"378\" fillcolor=\"FF0000\" type=\"integer\" length=\"4\"/>\n            <number name=\"triangleCount\" id=\"379\" fillcolor=\"FF0000\" type=\"integer\" length=\"4\"/>\n            <structure name=\"Vec3f\" id=\"380\" repeat=\"id:378\" repeatmin=\"0\" repeatmax=\"-1\">\n                <number name=\"x\" id=\"381\" fillcolor=\"55FFFF\" type=\"float\" length=\"4\"/>\n                <number name=\"y\" id=\"382\" fillcolor=\"55FFFF\" type=\"float\" length=\"4\"/>\n                <number name=\"z\" id=\"383\" fillcolor=\"55FFFF\" type=\"float\" length=\"4\"/>\n            </structure>\n            <structure name=\"Triangle\" id=\"385\" repeat=\"id:379\" repeatmin=\"0\" repeatmax=\"-1\">\n                <number name=\"a\" id=\"386\" fillcolor=\"55FF7F\" type=\"integer\" length=\"4\"/>\n                <number name=\"b\" id=\"387\" fillcolor=\"55FF7F\" type=\"integer\" length=\"4\"/>\n                <number name=\"c\" id=\"388\" fillcolor=\"55FF7F\" type=\"integer\" length=\"4\"/>\n            </structure>\n        </structure>\n        <structure name=\"HardConstraint\" id=\"391\" encoding=\"ISO_8859-1:1987\" endian=\"little\" signed=\"yes\">\n            <number name=\"constraintType\" id=\"392\" fillcolor=\"FFAA00\" type=\"integer\" length=\"4\"/>\n        </structure>\n        <structure name=\"FixedConstraint\" id=\"317\" length=\"0\" alignment=\"0\" extends=\"id:391\" encoding=\"ISO_8859-1:1987\" endian=\"little\" signed=\"yes\">\n            <number name=\"constraintType\" mustmatch=\"yes\" id=\"394\" type=\"integer\">\n                <fixedvalues>\n                    <fixedvalue name=\"fixed\" value=\"0\"/>\n                </fixedvalues>\n            </number>\n        </structure>\n        <structure name=\"MotorConstraint\" id=\"319\" length=\"0\" alignment=\"0\" extends=\"id:391\" encoding=\"ISO_8859-1:1987\" endian=\"little\" signed=\"yes\">\n            <number name=\"constraintType\" mustmatch=\"yes\" id=\"396\" type=\"integer\">\n                <fixedvalues>\n                    <fixedvalue name=\"motor\" value=\"1\"/>\n                </fixedvalues>\n            </number>\n            <number name=\"speed\" id=\"397\" type=\"float\" length=\"8\"/>\n            <number name=\"currentAngle\" id=\"398\" type=\"float\" length=\"8\"/>\n        </structure>\n        <structure name=\"SinusoidalPistonConstraint\" id=\"321\" length=\"0\" alignment=\"0\" extends=\"id:391\" encoding=\"ISO_8859-1:1987\" endian=\"little\" signed=\"yes\">\n            <number name=\"constraintType\" mustmatch=\"yes\" id=\"400\" type=\"integer\">\n                <fixedvalues>\n                    <fixedvalue name=\"piston\" value=\"2\"/>\n                </fixedvalues>\n            </number>\n            <number name=\"minValue\" id=\"401\" type=\"float\" length=\"8\"/>\n            <number name=\"maxValue\" id=\"402\" type=\"float\" length=\"8\"/>\n            <number name=\"period\" id=\"403\" type=\"float\" length=\"8\"/>\n            <number name=\"currentStepInPeriod\" id=\"404\" type=\"float\" length=\"8\"/>\n        </structure>\n        <structure name=\"SinusoidalMotorConstraint\" id=\"323\" length=\"0\" alignment=\"0\" extends=\"id:391\" encoding=\"ISO_8859-1:1987\" endian=\"little\" signed=\"yes\">\n            <number name=\"constraintType\" mustmatch=\"yes\" id=\"406\" type=\"integer\">\n                <fixedvalues>\n                    <fixedvalue name=\"sinusoidalMotor\" value=\"3\"/>\n                </fixedvalues>\n            </number>\n            <number name=\"minValue\" id=\"407\" type=\"float\" length=\"8\"/>\n            <number name=\"maxValue\" id=\"408\" type=\"float\" length=\"8\"/>\n            <number name=\"period\" id=\"409\" type=\"float\" length=\"8\"/>\n            <number name=\"currentStepInPeriod\" id=\"410\" type=\"float\" length=\"8\"/>\n        </structure>\n        <structure name=\"Constraint\" id=\"412\" encoding=\"ISO_8859-1:1987\" endian=\"little\" signed=\"yes\">\n            <number name=\"constraintType\" id=\"413\" fillcolor=\"FFAA00\" type=\"integer\" length=\"4\"/>\n        </structure>\n        <structure name=\"BallConstraint\" id=\"250\" extends=\"id:412\" endian=\"little\" signed=\"yes\">\n            <number name=\"constraintType\" mustmatch=\"yes\" id=\"415\" type=\"integer\">\n                <fixedvalues>\n                    <fixedvalue name=\"ball\" value=\"0\"/>\n                </fixedvalues>\n            </number>\n            <structref name=\"attachA\" id=\"416\" structure=\"id:268\"/>\n            <structref name=\"attachB\" id=\"417\" structure=\"id:268\"/>\n        </structure>\n        <structure name=\"HingeConstraint\" id=\"419\" extends=\"id:412\">\n            <number name=\"constraintType\" mustmatch=\"yes\" id=\"420\" type=\"integer\">\n                <fixedvalues>\n                    <fixedvalue name=\"hinge\" value=\"0\"/>\n                </fixedvalues>\n            </number>\n            <structref name=\"attachA\" id=\"422\" structure=\"id:268\"/>\n            <structref name=\"axisA\" id=\"423\" structure=\"id:268\"/>\n            <structref name=\"attachB\" id=\"424\" structure=\"id:268\"/>\n            <structref name=\"axisB\" id=\"425\" structure=\"id:268\"/>\n        </structure>\n        <structure name=\"BarConstraint\" id=\"426\" extends=\"id:412\">\n            <number name=\"constraintType\" mustmatch=\"yes\" id=\"428\" type=\"integer\">\n                <fixedvalues>\n                    <fixedvalue name=\"bar\" value=\"0\"/>\n                </fixedvalues>\n            </number>\n            <structref name=\"attachA\" id=\"429\" structure=\"id:268\"/>\n            <structref name=\"attachB\" id=\"430\" structure=\"id:268\"/>\n            <number name=\"length\" id=\"431\" type=\"float\" length=\"8\"/>\n        </structure>\n    </grammar>\n</ufwb>\n"
  }
]