diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 000000000..734ccc0a4 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,59 @@ +FROM ubuntu:24.04 + +ARG VulkanSDKVersion=1.4.335.0 +ARG SDL3TagOrCommit=release-3.4.0 + +WORKDIR /app + +# Install basic build tools +RUN apt-get update && apt-get install -y \ + curl \ + xz-utils \ + cmake \ + ninja-build \ + gdb + +# Install other dependencies +RUN apt-get install -y \ + # CMake dependencies + git pkg-config \ + # SDL3 dependencies (https://wiki.libsdl.org/SDL3/README-linux#build-dependencies) + cmake ninja-build gnome-desktop-testing libasound2-dev libpulse-dev \ + libaudio-dev libfribidi-dev libjack-dev libsndio-dev libx11-dev libxext-dev \ + libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev libxtst-dev \ + libxkbcommon-dev libdrm-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev \ + libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev \ + libpipewire-0.3-dev libwayland-dev libdecor-0-dev liburing-dev \ + # SDL3 dependencies not mentioned in the README + libusb-1.0-0-dev \ + # SDL3_mixer dependencies + libogg-dev libopus-dev libopusfile-dev libgme-dev libxmp-dev libfluidsynth-dev fluidsynth libwavpack-dev \ + # Other VVE dependencies + libglm-dev \ + # Documentation tools + doxygen graphviz + +# During configuration, CMake can't find libunwind - don't know why. It works without it. +RUN apt-get install -y \ + build-essential \ + clang-20 libc++-20-dev libc++abi-20-dev + +ENV XDG_RUNTIME_DIR=/run/user + +# Download, build and install SDL3 - needed for VECS Console on Linux +RUN git clone -b ${SDL3TagOrCommit} --depth 1 https://github.com/libsdl-org/SDL.git /tmp/SDL3 +WORKDIR /tmp/SDL3 +RUN cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -G Ninja && \ + cmake --build build && cmake --install build --prefix /usr/local +WORKDIR /app +RUN rm -rf /tmp/SDL3 + +# Download Vulkan SDK +RUN curl -o /tmp/vulkansdk.tar.gz https://sdk.lunarg.com/sdk/download/${VulkanSDKVersion}/linux/vulkansdk-linux-x86_64-${VulkanSDKVersion}.tar.xz +RUN mkdir /opt/VulkanSDK && tar -xf /tmp/vulkansdk.tar.gz -C /opt/VulkanSDK && rm /tmp/vulkansdk.tar.gz +RUN echo "source /opt/VulkanSDK/${VulkanSDKVersion}/setup-env.sh" >> ~/.bashrc +ENV VULKAN_SDK=/opt/VulkanSDK/${VulkanSDKVersion}/x86_64 +RUN echo "VULKAN_SDK=${VULKAN_SDK}" + +# Clean up download related packages +RUN apt-get remove -y curl xz-utils \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..6064d8b6c --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,72 @@ +// For format details, see https://aka.ms/devcontainer.json. +{ + "name": "C++", + "build": { + "dockerfile": "Dockerfile" + }, + // "dockerComposeFile": "compose.yml", + // "service": "cpp-dev", + "runArgs": [ + "--device=/dev/dri", + "--group-add=video", + "--ipc=host" + ], + + "containerEnv": { + "DISPLAY": "${localEnv:DISPLAY}", + "XAUTHORITY": "/tmp/.docker.xauth", + // PulseAudio / PipeWire configuration + "PULSE_SERVER": "unix:/run/user/host/pulse/native", + "PULSE_COOKIE": "/tmp/pulseaudio.cookie", + "PIPEWIRE_RUNTIME_DIR": "/run/user/host" + }, + + "mounts": [ + { + "type": "bind", + "source": "/tmp/.X11-unix", + "target": "/tmp/.X11-unix" + }, + { + "type": "bind", + "source": "${localEnv:HOME}/.Xauthority", + "target": "/tmp/.docker.xauth" + }, + // Mount XDG_RUNTIME_DIR for shared sockets (PulseAudio, PipeWire) + { + "type": "bind", + "source": "${localEnv:XDG_RUNTIME_DIR}", + "target": "/run/user/host" + }, + // Mount PulseAudio cookie if it exists + { + "type": "bind", + "source": "${localEnv:HOME}/.config/pulse/cookie", + "target": "/tmp/pulseaudio.cookie" + } + ], + + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "gcc -v", + + // Configure tool-specific properties. + "customizations": { + "vscode": { + "extensions": [ + "ms-vscode.cpptools-extension-pack", + "Gruntfuggly.todo-tree" + ] + } + }, + + // Connect as root so the container can read the mounted Xauthority (which is typically 0600 on host) + // More info: https://aka.ms/dev-containers-non-root + "remoteUser": "root" +} diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 92bdd20b7..dfea8a3ab 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -14,7 +14,7 @@ ], "windowsSdkVersion": "10.0.22000.0", "cppStandard": "c++20", - "intelliSenseMode": "windows-msvc-x64", + "intelliSenseMode": "${default}", "configurationProvider": "ms-vscode.cmake-tools" } ], diff --git a/.vscode/launch.json b/.vscode/launch.json index 57c749400..7d745b42e 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -148,7 +148,7 @@ "environment": [], "externalConsole": false, "MIMode": "lldb", - "MIDebuggerPath": "/usr/bin/lldb" + "miDebuggerPath": "/usr/bin/lldb" }, { "name": "AppleClang Helper", @@ -161,7 +161,7 @@ "environment": [], "externalConsole": false, "MIMode": "lldb", - "MIDebuggerPath": "/usr/bin/lldb" + "miDebuggerPath": "/usr/bin/lldb" }, { "name": "AppleClang Game", @@ -174,7 +174,7 @@ "environment": [], "externalConsole": false, "MIMode": "lldb", - "MIDebuggerPath": "/usr/bin/lldb" + "miDebuggerPath": "/usr/bin/lldb" }, { "name": "Linux Clang Test", @@ -187,7 +187,7 @@ "environment": [], "externalConsole": false, "MIMode": "gdb", - "MIDebuggerPath": "/usr/bin/gdb" + "miDebuggerPath": "/usr/bin/gdb" }, { "name": "Linux Clang Helper", @@ -200,7 +200,7 @@ "environment": [], "externalConsole": false, "MIMode": "gdb", - "MIDebuggerPath": "/usr/bin/gdb" + "miDebuggerPath": "/usr/bin/gdb" }, { "name": "Linux Clang Game", @@ -213,7 +213,20 @@ "environment": [], "externalConsole": false, "MIMode": "gdb", - "MIDebuggerPath": "/usr/bin/gdb" + "miDebuggerPath": "/usr/bin/gdb" + }, + { + "name": "Linux Clang Physics", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/examples/physics/physics", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "miDebuggerPath": "/usr/bin/gdb" } ] diff --git a/.vscode/settings.json b/.vscode/settings.json index 05700a9dd..3ac0c7dca 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -98,5 +98,6 @@ "source_location": "cpp", "future": "cpp" }, - "C_Cpp.errorSquiggles": "enabled" + "C_Cpp.errorSquiggles": "enabled", + "C_Cpp.default.cppStandard": "c++20" } \ No newline at end of file diff --git a/README_Linux.md b/README_Linux.md new file mode 100644 index 000000000..a4837f91a --- /dev/null +++ b/README_Linux.md @@ -0,0 +1,42 @@ +# The Vienna Vulkan Engine (VVE) - Linux +This README describes how to set up the dev enviroment on Linux via VSCode and Docker. + +> [!NOTE] +> Only tested with an AMD GPU and X11 on Linux Mint/Ubuntu. Also works with an Intel iGPU but fullscreening may be broken. +> +> With an NVIDIA GPU you might need the [nvidia-container-toolkit]() locally installed and need to edit `.devcontainer/devcontainer.json` and replace `--device=/dev/dri` with `--gpus all`. +> +> For native Wayland you may ask an AI of your choice to assist you. +> +> Also audio may or may not work depending on your setup - it worked fine for me with PipewWire as audio server. + +## Prerequesites +* [VSCode]() +* [Docker Engine]() - NOT Docker Desktop!! +* Be in the `docker` group to use docker commands without root +* [Dev Container Extension]() + +## Setup +After cloning and opening the project in VSCode open the Command Pallete (`F1`) and use the `>Dev Containers: Rebuild and Reopen in Container` command to build the development container and open the project inside it. + +Once you are in the container you can check if the GPU is detected by executing +```bash +vulkaninfo | head -n 60 +``` +> [!NOTE] +> If you get an output like this: `Authorization required, but no authorization protocol specified` +> +> Then grant permission to the root user to use your X11 session - RUN ON LOCAL USER, NOT IN THE CONTAINER!: +> ```bash +> xhost +si:localuser:root +> ``` +> You can remove the permissions again with +> ```bash +> xhost -si:localuser:root +> ``` + +You can now select the right compiler with `>CMake: Select a Kit` - I use *Clang \[...\]* (the one without *-cl*). If the list is empty select the *\[Scan for Kits\]* option and invoke the command again. + +And use `>CMake: Configure` and `>CMake: Build`. To change the build type use `>CMake: Select Variant` (e.g. *Debug* or *Release*). + +To debug/run an example use the *Run and Debug* (`CTRL+SHIFT+D`) option in the sidebar and select the appropriate option or create your own by modifying `.vscode/launch.json`. \ No newline at end of file diff --git a/examples/physics/VPE.hpp b/examples/physics/VPE.hpp index 7e40305e9..871416f74 100644 --- a/examples/physics/VPE.hpp +++ b/examples/physics/VPE.hpp @@ -228,12 +228,12 @@ namespace vpe { inline static glmmat3 CTrans = glm::transpose(C); - static constexpr glmvec3 toPhysics(glmvec3 vec) { return C * vec; } - static constexpr glmmat3 toPhysics(glmmat3 mat) { return CTrans * mat * C; } - static constexpr glmmat4 toPhysics(glmmat4 mat) { return glmmat4{CTrans} * mat * glmmat4{C}; } - static constexpr glmvec3 fromPhysics(glmvec3 vec) { return CTrans * vec; } - static constexpr glmmat3 fromPhysics(glmmat3 mat) { return C * mat * CTrans; } - static constexpr glmmat4 fromPhysics(glmmat4 mat) { return glmmat4{C} * mat * glmmat4{CTrans};} + static const glmvec3 toPhysics(glmvec3 vec) { return C * vec; } + static const glmmat3 toPhysics(glmmat3 mat) { return CTrans * mat * C; } + static const glmmat4 toPhysics(glmmat4 mat) { return glmmat4{CTrans} * mat * glmmat4{C}; } + static const glmvec3 fromPhysics(glmvec3 vec) { return CTrans * vec; } + static const glmmat3 fromPhysics(glmmat3 mat) { return C * mat * CTrans; } + static const glmmat4 fromPhysics(glmmat4 mat) { return glmmat4{C} * mat * glmmat4{CTrans};} /// /// This class implements a simple rigid body physics engine. @@ -248,12 +248,12 @@ namespace vpe { inline static glmmat3 CTrans = glm::transpose(C); - static constexpr glmvec3 toPhysics(glmvec3 vec) { return C * vec; } - static constexpr glmmat3 toPhysics(glmmat3 mat) { return CTrans * mat * C; } - static constexpr glmmat4 toPhysics(glmmat4 mat) { return glmmat4{CTrans} * mat * glmmat4{C}; } - static constexpr glmvec3 fromPhysics(glmvec3 vec) { return CTrans * vec; } - static constexpr glmmat3 fromPhysics(glmmat3 mat) { return C * mat * CTrans; } - static constexpr glmmat4 fromPhysics(glmmat4 mat) { return glmmat4{C} * mat * glmmat4{CTrans};} + static const glmvec3 toPhysics(glmvec3 vec) { return C * vec; } + static const glmmat3 toPhysics(glmmat3 mat) { return CTrans * mat * C; } + static const glmmat4 toPhysics(glmmat4 mat) { return glmmat4{CTrans} * mat * glmmat4{C}; } + static const glmvec3 fromPhysics(glmvec3 vec) { return CTrans * vec; } + static const glmmat3 fromPhysics(glmmat3 mat) { return C * mat * CTrans; } + static const glmmat4 fromPhysics(glmmat4 mat) { return glmmat4{C} * mat * glmmat4{CTrans};} public: @@ -1669,8 +1669,8 @@ namespace vpe { /// Contact between the two bodies. /// Result of edge query. void createEdgeContact(Contact& contact, EdgeQuery& eq) { - Face* ref_face = maxFaceAlignment(eq.m_normalL, eq.m_edge_ref->m_edge_face_ptrs, fabs); //face of A best aligned with the contact normal - Face* inc_face = maxFaceAlignment(-RTOIN(eq.m_normalL), eq.m_edge_inc->m_edge_face_ptrs, fabs); //face of B best aligned with the contact normal + Face* ref_face = maxFaceAlignment(eq.m_normalL, eq.m_edge_ref->m_edge_face_ptrs, [](real x) { return static_cast(fabs(x)); }); //face of A best aligned with the contact normal + Face* inc_face = maxFaceAlignment(-RTOIN(eq.m_normalL), eq.m_edge_inc->m_edge_face_ptrs, [](real x) { return static_cast(fabs(x)); }); //face of B best aligned with the contact normal real dp_ref = fabs(glm::dot(eq.m_normalL, ref_face->m_normalL)); //Use the better aligned face as reference face. real dp_inc = fabs(glm::dot(eq.m_normalL, inc_face->m_normalL));